From e3d1bb271f10de51b5139af78b9b3ac55ba6eeaa Mon Sep 17 00:00:00 2001 From: John Freeman Date: Tue, 11 Jun 2024 12:26:01 -0500 Subject: [PATCH 01/82] Fix compatibility with Conan 2.x: (#5001) Closes #4926, #4990 --- BUILD.md | 26 +++++++++---- conanfile.py | 101 +++++++++++++++++++++++++++++---------------------- 2 files changed, 77 insertions(+), 50 deletions(-) diff --git a/BUILD.md b/BUILD.md index 60ee31d42d1..590a7129863 100644 --- a/BUILD.md +++ b/BUILD.md @@ -36,9 +36,15 @@ See [System Requirements](https://xrpl.org/system-requirements.html). Building rippled generally requires git, Python, Conan, CMake, and a C++ compiler. Some guidance on setting up such a [C++ development environment can be found here](./docs/build/environment.md). - [Python 3.7](https://www.python.org/downloads/) -- [Conan 1.55](https://conan.io/downloads.html) +- [Conan 1.60](https://conan.io/downloads.html)[^1] - [CMake 3.16](https://cmake.org/download/) +[^1]: It is possible to build with Conan 2.x, +but the instructions are significantly different, +which is why we are not recommending it yet. +Notably, the `conan profile update` command is removed in 2.x. +Profiles must be edited by hand. + `rippled` is written in the C++20 dialect and includes the `` header. The [minimum compiler versions][2] required are: @@ -67,9 +73,6 @@ Here are [sample instructions for setting up a C++ development environment on ma Windows is not recommended for production use at this time. - Additionally, 32-bit Windows development is not supported. -- Visual Studio 2022 is not yet supported. - - rippled generally requires [Boost][] 1.77, which Conan cannot build with VS 2022. - - Until rippled is updated for compatibility with later versions of Boost, Windows developers may need to use Visual Studio 2019. [Boost]: https://www.boost.org/ @@ -144,21 +147,30 @@ It does not explicitly link the C++ standard library, which allows you to statically link it with GCC, if you want. ``` + # Conan 1.x conan export external/snappy snappy/1.1.10@ + # Conan 2.x + conan export --version 1.1.10 external/snappy ``` Export our [Conan recipe for RocksDB](./external/rocksdb). It does not override paths to dependencies when building with Visual Studio. ``` + # Conan 1.x conan export external/rocksdb rocksdb/6.29.5@ + # Conan 2.x + conan export --version 6.29.5 external/rocksdb ``` Export our [Conan recipe for SOCI](./external/soci). It patches their CMake to correctly import its dependencies. ``` + # Conan 1.x conan export external/soci soci/4.0.3@ + # Conan 2.x + conan export --version 4.0.3 external/soci ``` ### Build and Test @@ -196,13 +208,13 @@ It patches their CMake to correctly import its dependencies. generated by the first. You can pass the build type on the command line with `--settings build_type=$BUILD_TYPE` or in the profile itself, under the section `[settings]` with the key `build_type`. - + If you are using a Microsoft Visual C++ compiler, then you will need to ensure consistency between the `build_type` setting and the `compiler.runtime` setting. - + When `build_type` is `Release`, `compiler.runtime` should be `MT`. - + When `build_type` is `Debug`, `compiler.runtime` should be `MTd`. ``` diff --git a/conanfile.py b/conanfile.py index 10eeb6e3ca7..8c4068ecf69 100644 --- a/conanfile.py +++ b/conanfile.py @@ -24,17 +24,13 @@ class Xrpl(ConanFile): } requires = [ - 'boost/1.82.0', 'date/3.0.1', 'grpc/1.50.1', 'libarchive/3.6.2', - 'lz4/1.9.3', 'nudb/2.0.8', 'openssl/1.1.1u', - 'protobuf/3.21.9', 'snappy/1.1.10', 'soci/4.0.3', - 'sqlite3/3.42.0', 'zlib/1.2.13', 'xxhash/0.8.2', ] @@ -55,43 +51,43 @@ class Xrpl(ConanFile): 'tests': True, 'unity': False, - 'cassandra-cpp-driver:shared': False, - 'cassandra-cpp-driver:use_atomic': None, - 'date:header_only': True, - 'grpc:shared': False, - 'grpc:secure': True, - 'libarchive:shared': False, - 'libarchive:with_acl': False, - 'libarchive:with_bzip2': False, - 'libarchive:with_cng': False, - 'libarchive:with_expat': False, - 'libarchive:with_iconv': False, - 'libarchive:with_libxml2': False, - 'libarchive:with_lz4': True, - 'libarchive:with_lzma': False, - 'libarchive:with_lzo': False, - 'libarchive:with_nettle': False, - 'libarchive:with_openssl': False, - 'libarchive:with_pcreposix': False, - 'libarchive:with_xattr': False, - 'libarchive:with_zlib': False, - 'libpq:shared': False, - 'lz4:shared': False, - 'openssl:shared': False, - 'protobuf:shared': False, - 'protobuf:with_zlib': True, - 'rocksdb:enable_sse': False, - 'rocksdb:lite': False, - 'rocksdb:shared': False, - 'rocksdb:use_rtti': True, - 'rocksdb:with_jemalloc': False, - 'rocksdb:with_lz4': True, - 'rocksdb:with_snappy': True, - 'snappy:shared': False, - 'soci:shared': False, - 'soci:with_sqlite3': True, - 'soci:with_boost': True, - 'xxhash:shared': False, + 'cassandra-cpp-driver/*:shared': False, + 'cassandra-cpp-driver/*:use_atomic': None, + 'date/*:header_only': True, + 'grpc/*:shared': False, + 'grpc/*:secure': True, + 'libarchive/*:shared': False, + 'libarchive/*:with_acl': False, + 'libarchive/*:with_bzip2': False, + 'libarchive/*:with_cng': False, + 'libarchive/*:with_expat': False, + 'libarchive/*:with_iconv': False, + 'libarchive/*:with_libxml2': False, + 'libarchive/*:with_lz4': True, + 'libarchive/*:with_lzma': False, + 'libarchive/*:with_lzo': False, + 'libarchive/*:with_nettle': False, + 'libarchive/*:with_openssl': False, + 'libarchive/*:with_pcreposix': False, + 'libarchive/*:with_xattr': False, + 'libarchive/*:with_zlib': False, + 'libpq/*:shared': False, + 'lz4/*:shared': False, + 'openssl/*:shared': False, + 'protobuf/*:shared': False, + 'protobuf/*:with_zlib': True, + 'rocksdb/*:enable_sse': False, + 'rocksdb/*:lite': False, + 'rocksdb/*:shared': False, + 'rocksdb/*:use_rtti': True, + 'rocksdb/*:with_jemalloc': False, + 'rocksdb/*:with_lz4': True, + 'rocksdb/*:with_snappy': True, + 'snappy/*:shared': False, + 'soci/*:shared': False, + 'soci/*:with_sqlite3': True, + 'soci/*:with_boost': True, + 'xxhash/*:shared': False, } def set_version(self): @@ -107,6 +103,10 @@ def configure(self): self.options['boost'].visibility = 'global' def requirements(self): + self.requires('boost/1.82.0', force=True) + self.requires('lz4/1.9.3', force=True) + self.requires('protobuf/3.21.9', force=True) + self.requires('sqlite3/3.42.0', force=True) if self.options.jemalloc: self.requires('jemalloc/5.3.0') if self.options.reporting: @@ -116,7 +116,12 @@ def requirements(self): self.requires('rocksdb/6.29.5') exports_sources = ( - 'CMakeLists.txt', 'Builds/*', 'bin/getRippledInfo', 'src/*', 'cfg/*', 'external/*' + 'CMakeLists.txt', + 'Builds/*', + 'bin/getRippledInfo', + 'cfg/*' + 'external/*', + 'src/*', ) def layout(self): @@ -163,8 +168,18 @@ def package_info(self): libxrpl.includedirs = ['include', 'include/ripple/proto'] libxrpl.requires = [ 'boost::boost', - 'openssl::crypto', 'date::date', 'grpc::grpc++', + 'libarchive::libarchive', + 'lz4::lz4', + 'nudb::nudb', + 'openssl::crypto', + 'protobuf::libprotobuf', + 'snappy::snappy', + 'soci::soci', + 'sqlite3::sqlite', 'xxhash::xxhash', + 'zlib::zlib', ] + if self.options.rocksdb: + libxrpl.requires.append('rocksdb::librocksdb') From d5764169533cc1c339504c96a7c5ec06d95f5deb Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Tue, 11 Jun 2024 19:34:02 +0100 Subject: [PATCH 02/82] Add new command line option to make replaying transactions easier: (#5027) * Add trap_tx_hash command line option This new option can be used only if replay is also enabled. It takes a transaction hash from the ledger loaded for replay, and will cause a specific line to be hit in Transactor.cpp, right before the selected transaction is applied. --- src/ripple/app/main/Application.cpp | 32 +++++- src/ripple/app/main/Application.h | 3 + src/ripple/app/main/Main.cpp | 30 +++++ src/ripple/app/tx/impl/Transactor.cpp | 6 + src/ripple/core/Config.h | 2 + src/test/app/LedgerLoad_test.cpp | 152 ++++++++++++++++++++++++-- 6 files changed, 214 insertions(+), 11 deletions(-) diff --git a/src/ripple/app/main/Application.cpp b/src/ripple/app/main/Application.cpp index 55300a390c9..4f994cfe5ac 100644 --- a/src/ripple/app/main/Application.cpp +++ b/src/ripple/app/main/Application.cpp @@ -225,6 +225,7 @@ class ApplicationImp : public Application, public BasicApp std::unique_ptr mRelationalDatabase; std::unique_ptr mWalletDB; std::unique_ptr overlay_; + std::optional trapTxID_; boost::asio::signal_set m_signals; @@ -1254,6 +1255,12 @@ class ApplicationImp : public Application, public BasicApp return maxDisallowedLedger_; } + virtual const std::optional& + trapTxID() const override + { + return trapTxID_; + } + private: // For a newly-started validator, this is the greatest persisted ledger // and new validations must be greater than this. @@ -1272,7 +1279,11 @@ class ApplicationImp : public Application, public BasicApp loadLedgerFromFile(std::string const& ledgerID); bool - loadOldLedger(std::string const& ledgerID, bool replay, bool isFilename); + loadOldLedger( + std::string const& ledgerID, + bool replay, + bool isFilename, + std::optional trapTxID); void setMaxDisallowedLedger(); @@ -1404,7 +1415,8 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) if (!loadOldLedger( config_->START_LEDGER, startUp == Config::REPLAY, - startUp == Config::LOAD_FILE)) + startUp == Config::LOAD_FILE, + config_->TRAP_TX_HASH)) { JLOG(m_journal.error()) << "The specified ledger could not be loaded."; @@ -2086,7 +2098,8 @@ bool ApplicationImp::loadOldLedger( std::string const& ledgerID, bool replay, - bool isFileName) + bool isFileName, + std::optional trapTxID) { try { @@ -2233,6 +2246,11 @@ ApplicationImp::loadOldLedger( { (void)_; auto txID = tx->getTransactionID(); + if (trapTxID == txID) + { + trapTxID_ = txID; + JLOG(m_journal.debug()) << "Trap transaction set: " << txID; + } auto s = std::make_shared(); tx->add(*s); @@ -2247,6 +2265,14 @@ ApplicationImp::loadOldLedger( } m_ledgerMaster->takeReplay(std::move(replayData)); + + if (trapTxID && !trapTxID_) + { + JLOG(m_journal.fatal()) + << "Ledger " << replayLedger->info().seq + << " does not contain the transaction hash " << *trapTxID; + return false; + } } } catch (SHAMapMissingNode const& mn) diff --git a/src/ripple/app/main/Application.h b/src/ripple/app/main/Application.h index 3fa8d13e870..4a7d72aec25 100644 --- a/src/ripple/app/main/Application.h +++ b/src/ripple/app/main/Application.h @@ -284,6 +284,9 @@ class Application : public beast::PropertyStream::Source * than the last ledger it persisted. */ virtual LedgerIndex getMaxDisallowedLedger() = 0; + + virtual const std::optional& + trapTxID() const = 0; }; std::unique_ptr diff --git a/src/ripple/app/main/Main.cpp b/src/ripple/app/main/Main.cpp index 710e4e9674f..be4e354b6aa 100644 --- a/src/ripple/app/main/Main.cpp +++ b/src/ripple/app/main/Main.cpp @@ -400,6 +400,9 @@ run(int argc, char** argv) "net", "Get the initial ledger from the network.")( "nodetoshard", "Import node store into shards")( "replay", "Replay a ledger close.")( + "trap_tx_hash", + po::value(), + "Trap a specific transaction during replay.")( "start", "Start from a fresh Ledger.")( "startReporting", po::value(), @@ -558,6 +561,7 @@ run(int argc, char** argv) argc, argv); } + // LCOV_EXCL_START else { if (vm.count("unittest-jobs")) @@ -679,7 +683,25 @@ run(int argc, char** argv) { config->START_LEDGER = vm["ledger"].as(); if (vm.count("replay")) + { config->START_UP = Config::REPLAY; + if (vm.count("trap_tx_hash")) + { + uint256 tmp = {}; + auto hash = vm["trap_tx_hash"].as(); + if (tmp.parseHex(hash)) + { + config->TRAP_TX_HASH = tmp; + } + else + { + std::cerr << "Trap parameter was ill-formed, expected " + "valid transaction hash but received: " + << hash << std::endl; + return -1; + } + } + } else config->START_UP = Config::LOAD; } @@ -693,6 +715,13 @@ run(int argc, char** argv) config->START_UP = Config::LOAD; } + if (vm.count("trap_tx_hash") && vm.count("replay") == 0) + { + std::cerr << "Cannot use trap option without replay option" + << std::endl; + return -1; + } + if (vm.count("net") && !config->FAST_LOAD) { if ((config->START_UP == Config::LOAD) || @@ -828,6 +857,7 @@ run(int argc, char** argv) beast::setCurrentThreadName("rippled: rpc"); return RPCCall::fromCommandLine( *config, vm["parameters"].as>(), *logs); + // LCOV_EXCL_STOP } } // namespace ripple diff --git a/src/ripple/app/tx/impl/Transactor.cpp b/src/ripple/app/tx/impl/Transactor.cpp index 7dcf3f15ab7..c02b57a3ae4 100644 --- a/src/ripple/app/tx/impl/Transactor.cpp +++ b/src/ripple/app/tx/impl/Transactor.cpp @@ -854,6 +854,12 @@ Transactor::operator()() } #endif + if (auto const& trap = ctx_.app.trapTxID(); + trap && *trap == ctx_.tx.getTransactionID()) + { + JLOG(j_.debug()) << "Transaction trapped: " << *trap; + } + auto result = ctx_.preclaimResult; if (result == tesSUCCESS) result = apply(); diff --git a/src/ripple/core/Config.h b/src/ripple/core/Config.h index cf41678a16c..24b762cf8c5 100644 --- a/src/ripple/core/Config.h +++ b/src/ripple/core/Config.h @@ -162,6 +162,8 @@ class Config : public BasicConfig std::string START_LEDGER; + std::optional TRAP_TX_HASH; + // Network parameters uint32_t NETWORK_ID = 0; diff --git a/src/test/app/LedgerLoad_test.cpp b/src/test/app/LedgerLoad_test.cpp index f06e7d0bf01..599215c2435 100644 --- a/src/test/app/LedgerLoad_test.cpp +++ b/src/test/app/LedgerLoad_test.cpp @@ -18,6 +18,8 @@ //============================================================================== #include +#include +#include #include #include #include @@ -36,10 +38,12 @@ class LedgerLoad_test : public beast::unit_test::suite std::unique_ptr cfg, std::string const& dbPath, std::string const& ledger, - Config::StartUpType type) + Config::StartUpType type, + std::optional trapTxHash) { cfg->START_LEDGER = ledger; cfg->START_UP = type; + cfg->TRAP_TX_HASH = trapTxHash; assert(!dbPath.empty()); cfg->legacy("database_path", dbPath); return cfg; @@ -52,6 +56,7 @@ class LedgerLoad_test : public beast::unit_test::suite std::string ledgerFile{}; Json::Value ledger{}; Json::Value hashes{}; + uint256 trapTxHash{}; }; SetupData @@ -94,6 +99,16 @@ class LedgerLoad_test : public beast::unit_test::suite }(); BEAST_EXPECT(retval.hashes.size() == 41); + retval.trapTxHash = [&]() { + auto const txs = env.rpc( + "ledger", + std::to_string(41), + "tx")[jss::result][jss::ledger][jss::transactions]; + BEAST_EXPECT(txs.isArray() && txs.size() > 0); + uint256 tmp; + BEAST_EXPECT(tmp.parseHex(txs[0u][jss::hash].asString())); + return tmp; + }(); // write this ledger data to a file. std::ofstream o(retval.ledgerFile, std::ios::out | std::ios::trunc); @@ -112,7 +127,11 @@ class LedgerLoad_test : public beast::unit_test::suite Env env( *this, envconfig( - ledgerConfig, sd.dbPath, sd.ledgerFile, Config::LOAD_FILE), + ledgerConfig, + sd.dbPath, + sd.ledgerFile, + Config::LOAD_FILE, + std::nullopt), nullptr, beast::severities::kDisabled); auto jrb = env.rpc("ledger", "current", "full")[jss::result]; @@ -132,7 +151,12 @@ class LedgerLoad_test : public beast::unit_test::suite except([&] { Env env( *this, - envconfig(ledgerConfig, sd.dbPath, "", Config::LOAD_FILE), + envconfig( + ledgerConfig, + sd.dbPath, + "", + Config::LOAD_FILE, + std::nullopt), nullptr, beast::severities::kDisabled); }); @@ -142,7 +166,11 @@ class LedgerLoad_test : public beast::unit_test::suite Env env( *this, envconfig( - ledgerConfig, sd.dbPath, "badfile.json", Config::LOAD_FILE), + ledgerConfig, + sd.dbPath, + "badfile.json", + Config::LOAD_FILE, + std::nullopt), nullptr, beast::severities::kDisabled); }); @@ -172,7 +200,8 @@ class LedgerLoad_test : public beast::unit_test::suite ledgerConfig, sd.dbPath, ledgerFileCorrupt.string(), - Config::LOAD_FILE), + Config::LOAD_FILE, + std::nullopt), nullptr, beast::severities::kDisabled); }); @@ -189,7 +218,12 @@ class LedgerLoad_test : public beast::unit_test::suite boost::erase_all(ledgerHash, "\""); Env env( *this, - envconfig(ledgerConfig, sd.dbPath, ledgerHash, Config::LOAD), + envconfig( + ledgerConfig, + sd.dbPath, + ledgerHash, + Config::LOAD, + std::nullopt), nullptr, beast::severities::kDisabled); auto jrb = env.rpc("ledger", "current", "full")[jss::result]; @@ -199,6 +233,103 @@ class LedgerLoad_test : public beast::unit_test::suite sd.ledger[jss::ledger][jss::accountState].size()); } + void + testReplay(SetupData const& sd) + { + testcase("Load and replay by hash"); + using namespace test::jtx; + + // create a new env with the ledger hash specified for startup + auto ledgerHash = to_string(sd.hashes[sd.hashes.size() - 1]); + boost::erase_all(ledgerHash, "\""); + Env env( + *this, + envconfig( + ledgerConfig, + sd.dbPath, + ledgerHash, + Config::REPLAY, + std::nullopt), + nullptr, + beast::severities::kDisabled); + auto const jrb = env.rpc("ledger", "current", "full")[jss::result]; + BEAST_EXPECT(jrb[jss::ledger][jss::accountState].size() == 97); + // in replace mode do not automatically accept the ledger being replayed + + env.close(); + auto const closed = env.rpc("ledger", "current", "full")[jss::result]; + BEAST_EXPECT(closed[jss::ledger][jss::accountState].size() == 98); + BEAST_EXPECT( + closed[jss::ledger][jss::accountState].size() <= + sd.ledger[jss::ledger][jss::accountState].size()); + } + + void + testReplayTx(SetupData const& sd) + { + testcase("Load and replay transaction by hash"); + using namespace test::jtx; + + // create a new env with the ledger hash specified for startup + auto ledgerHash = to_string(sd.hashes[sd.hashes.size() - 1]); + boost::erase_all(ledgerHash, "\""); + Env env( + *this, + envconfig( + ledgerConfig, + sd.dbPath, + ledgerHash, + Config::REPLAY, + sd.trapTxHash), + nullptr, + beast::severities::kDisabled); + auto const jrb = env.rpc("ledger", "current", "full")[jss::result]; + BEAST_EXPECT(jrb[jss::ledger][jss::accountState].size() == 97); + // in replace mode do not automatically accept the ledger being replayed + + env.close(); + auto const closed = env.rpc("ledger", "current", "full")[jss::result]; + BEAST_EXPECT(closed[jss::ledger][jss::accountState].size() == 98); + BEAST_EXPECT( + closed[jss::ledger][jss::accountState].size() <= + sd.ledger[jss::ledger][jss::accountState].size()); + } + + void + testReplayTxFail(SetupData const& sd) + { + testcase("Load and replay transaction by hash failure"); + using namespace test::jtx; + + // create a new env with the ledger hash specified for startup + auto ledgerHash = to_string(sd.hashes[sd.hashes.size() - 1]); + boost::erase_all(ledgerHash, "\""); + try + { + // will throw an exception, because we cannot load a ledger for + // replay when trapTxHash is set to an invalid transaction + Env env( + *this, + envconfig( + ledgerConfig, + sd.dbPath, + ledgerHash, + Config::REPLAY, + ~sd.trapTxHash), + nullptr, + beast::severities::kDisabled); + BEAST_EXPECT(false); + } + catch (std::runtime_error const&) + { + BEAST_EXPECT(true); + } + catch (...) + { + BEAST_EXPECT(false); + } + } + void testLoadLatest(SetupData const& sd) { @@ -208,7 +339,8 @@ class LedgerLoad_test : public beast::unit_test::suite // create a new env with the ledger "latest" specified for startup Env env( *this, - envconfig(ledgerConfig, sd.dbPath, "latest", Config::LOAD), + envconfig( + ledgerConfig, sd.dbPath, "latest", Config::LOAD, std::nullopt), nullptr, beast::severities::kDisabled); auto jrb = env.rpc("ledger", "current", "full")[jss::result]; @@ -226,7 +358,8 @@ class LedgerLoad_test : public beast::unit_test::suite // create a new env with specific ledger index at startup Env env( *this, - envconfig(ledgerConfig, sd.dbPath, "43", Config::LOAD), + envconfig( + ledgerConfig, sd.dbPath, "43", Config::LOAD, std::nullopt), nullptr, beast::severities::kDisabled); auto jrb = env.rpc("ledger", "current", "full")[jss::result]; @@ -246,6 +379,9 @@ class LedgerLoad_test : public beast::unit_test::suite testLoad(sd); testBadFiles(sd); testLoadByHash(sd); + testReplay(sd); + testReplayTx(sd); + testReplayTxFail(sd); testLoadLatest(sd); testLoadIndex(sd); } From 58f3abe3c6873cc0bcc9894692415d6f59bd9901 Mon Sep 17 00:00:00 2001 From: Olek <115580134+oleks-rip@users.noreply.github.com> Date: Wed, 12 Jun 2024 13:16:54 -0400 Subject: [PATCH 03/82] Fix conan typo: (#5044) Add missed coma in 'exportes_sources' --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index 8c4068ecf69..78eab272a55 100644 --- a/conanfile.py +++ b/conanfile.py @@ -119,7 +119,7 @@ def requirements(self): 'CMakeLists.txt', 'Builds/*', 'bin/getRippledInfo', - 'cfg/*' + 'cfg/*', 'external/*', 'src/*', ) From 263e984bf4c72896b03715b9592a6834657882d2 Mon Sep 17 00:00:00 2001 From: Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com> Date: Thu, 13 Jun 2024 11:44:39 -0700 Subject: [PATCH 04/82] Additional unit tests for testing deletion of trust lines (#4886) --- src/test/app/SetTrust_test.cpp | 237 +++++++++++++++++++++++++++++++++ src/test/jtx/impl/trust.cpp | 4 + 2 files changed, 241 insertions(+) diff --git a/src/test/app/SetTrust_test.cpp b/src/test/app/SetTrust_test.cpp index 599ac1917f9..cab0132ae1c 100644 --- a/src/test/app/SetTrust_test.cpp +++ b/src/test/app/SetTrust_test.cpp @@ -29,6 +29,144 @@ class SetTrust_test : public beast::unit_test::suite FeatureBitset const disallowIncoming{featureDisallowIncoming}; public: + void + testTrustLineDelete() + { + testcase( + "Test deletion of trust lines: revert trust line limit to zero"); + + using namespace jtx; + Env env(*this); + + Account const alice = Account{"alice"}; + Account const becky = Account{"becky"}; + + env.fund(XRP(10000), becky, alice); + env.close(); + + // becky wants to hold at most 50 tokens of alice["USD"] + // becky is the customer, alice is the issuer + // becky can be sent at most 50 tokens of alice's USD + env(trust(becky, alice["USD"](50))); + env.close(); + + // Since the settings of the trust lines are non-default for both + // alice and becky, both of them will be charged an owner reserve + // Irrespective of whether the issuer or the customer initiated + // the trust-line creation, both will be charged + env.require(lines(alice, 1)); + env.require(lines(becky, 1)); + + // Fetch the trust-lines via RPC for verification + Json::Value jv; + jv["account"] = becky.human(); + auto beckyLines = env.rpc("json", "account_lines", to_string(jv)); + + jv["account"] = alice.human(); + auto aliceLines = env.rpc("json", "account_lines", to_string(jv)); + + BEAST_EXPECT(aliceLines[jss::result][jss::lines].size() == 1); + BEAST_EXPECT(beckyLines[jss::result][jss::lines].size() == 1); + + // reset the trust line limits to zero + env(trust(becky, alice["USD"](0))); + env.close(); + + // the reset of the trust line limits deletes the trust-line + // this occurs despite the authorization of the trust-line by the + // issuer(alice, in this unit test) + env.require(lines(becky, 0)); + env.require(lines(alice, 0)); + + // second verification check via RPC calls + jv["account"] = becky.human(); + beckyLines = env.rpc("json", "account_lines", to_string(jv)); + + jv["account"] = alice.human(); + aliceLines = env.rpc("json", "account_lines", to_string(jv)); + + BEAST_EXPECT(aliceLines[jss::result][jss::lines].size() == 0); + BEAST_EXPECT(beckyLines[jss::result][jss::lines].size() == 0); + + // additionally, verify that account_objects is an empty array + jv["account"] = becky.human(); + auto const beckyObj = env.rpc("json", "account_objects", to_string(jv)); + BEAST_EXPECT(beckyObj[jss::result][jss::account_objects].size() == 0); + + jv["account"] = alice.human(); + auto const aliceObj = env.rpc("json", "account_objects", to_string(jv)); + BEAST_EXPECT(aliceObj[jss::result][jss::account_objects].size() == 0); + } + + void + testTrustLineResetWithAuthFlag() + { + testcase( + "Reset trust line limit with Authorised Lines: Verify " + "deletion of trust lines"); + + using namespace jtx; + Env env(*this); + + Account const alice = Account{"alice"}; + Account const becky = Account{"becky"}; + + env.fund(XRP(10000), becky, alice); + env.close(); + + // alice wants to ensure that all holders of her tokens are authorised + env(fset(alice, asfRequireAuth)); + env.close(); + + // becky wants to hold at most 50 tokens of alice["USD"] + // becky is the customer, alice is the issuer + // becky can be sent at most 50 tokens of alice's USD + env(trust(becky, alice["USD"](50))); + env.close(); + + // alice authorizes becky to hold alice["USD"] tokens + env(trust(alice, alice["USD"](0), becky, tfSetfAuth)); + env.close(); + + // Since the settings of the trust lines are non-default for both + // alice and becky, both of them will be charged an owner reserve + // Irrespective of whether the issuer or the customer initiated + // the trust-line creation, both will be charged + env.require(lines(alice, 1)); + env.require(lines(becky, 1)); + + // Fetch the trust-lines via RPC for verification + Json::Value jv; + jv["account"] = becky.human(); + auto beckyLines = env.rpc("json", "account_lines", to_string(jv)); + + jv["account"] = alice.human(); + auto aliceLines = env.rpc("json", "account_lines", to_string(jv)); + + BEAST_EXPECT(aliceLines[jss::result][jss::lines].size() == 1); + BEAST_EXPECT(beckyLines[jss::result][jss::lines].size() == 1); + + // reset the trust line limits to zero + env(trust(becky, alice["USD"](0))); + env.close(); + + // the reset of the trust line limits deletes the trust-line + // this occurs despite the authorization of the trust-line by the + // issuer(alice, in this unit test) + env.require(lines(becky, 0)); + env.require(lines(alice, 0)); + + // second verification check via RPC calls + jv["account"] = becky.human(); + beckyLines = env.rpc("json", "account_lines", to_string(jv)); + + jv["account"] = alice.human(); + aliceLines = env.rpc("json", "account_lines", to_string(jv)); + + BEAST_EXPECT(aliceLines[jss::result][jss::lines].size() == 0); + BEAST_EXPECT(beckyLines[jss::result][jss::lines].size() == 0); + } + void testFreeTrustlines( FeatureBitset features, @@ -203,6 +341,100 @@ class SetTrust_test : public beast::unit_test::suite env(trust(alice, gw["USD"](100), tfSetfAuth), ter(tefNO_AUTH_REQUIRED)); } + void + testExceedTrustLineLimit() + { + testcase( + "Ensure that trust line limits are respected in payment " + "transactions"); + + using namespace jtx; + Env env{*this}; + + auto const gw = Account{"gateway"}; + auto const alice = Account{"alice"}; + env.fund(XRP(10000), gw, alice); + + // alice wants to hold at most 100 of gw's USD tokens + env(trust(alice, gw["USD"](100))); + env.close(); + + // send a payment for a large quantity through the trust line + env(pay(gw, alice, gw["USD"](200)), ter(tecPATH_PARTIAL)); + env.close(); + + // on the other hand, smaller payments should succeed + env(pay(gw, alice, gw["USD"](20))); + env.close(); + } + + void + testAuthFlagTrustLines() + { + testcase( + "Ensure that authorised trust lines do not allow payments " + "from unauthorised counter-parties"); + + using namespace jtx; + Env env{*this}; + + auto const bob = Account{"bob"}; + auto const alice = Account{"alice"}; + env.fund(XRP(10000), bob, alice); + + // alice wants to ensure that all holders of her tokens are authorised + env(fset(alice, asfRequireAuth)); + env.close(); + + // create a trust line from bob to alice. bob wants to hold at most + // 100 of alice's USD tokens. Note: alice hasn't authorised this + // trust line yet. + env(trust(bob, alice["USD"](100))); + env.close(); + + // send a payment from alice to bob, validate that the payment fails + env(pay(alice, bob, alice["USD"](10)), ter(tecPATH_DRY)); + env.close(); + } + + void + testTrustLineLimitsWithRippling() + { + testcase( + "Check that trust line limits are respected in conjunction " + "with rippling feature"); + + using namespace jtx; + Env env{*this}; + + auto const bob = Account{"bob"}; + auto const alice = Account{"alice"}; + env.fund(XRP(10000), bob, alice); + + // create a trust line from bob to alice. bob wants to hold at most + // 100 of alice's USD tokens. + env(trust(bob, alice["USD"](100))); + env.close(); + + // archetypical payment transaction from alice to bob must succeed + env(pay(alice, bob, alice["USD"](20)), ter(tesSUCCESS)); + env.close(); + + // Issued tokens are fungible. i.e. alice's USD is identical to bob's + // USD + env(pay(bob, alice, bob["USD"](10)), ter(tesSUCCESS)); + env.close(); + + // bob cannot place alice in his debt i.e. alice's balance of the USD + // tokens cannot go below zero. + env(pay(bob, alice, bob["USD"](11)), ter(tecPATH_PARTIAL)); + env.close(); + + // payments that respect the trust line limits of alice should succeed + env(pay(bob, alice, bob["USD"](10)), ter(tesSUCCESS)); + env.close(); + } + void testModifyQualityOfTrustline( FeatureBitset features, @@ -402,6 +634,11 @@ class SetTrust_test : public beast::unit_test::suite testModifyQualityOfTrustline(features, true, false); testModifyQualityOfTrustline(features, true, true); testDisallowIncoming(features); + testTrustLineResetWithAuthFlag(); + testTrustLineDelete(); + testExceedTrustLineLimit(); + testAuthFlagTrustLines(); + testTrustLineLimitsWithRippling(); } public: diff --git a/src/test/jtx/impl/trust.cpp b/src/test/jtx/impl/trust.cpp index cce4657e025..4ceb10a2365 100644 --- a/src/test/jtx/impl/trust.cpp +++ b/src/test/jtx/impl/trust.cpp @@ -39,6 +39,10 @@ trust(Account const& account, STAmount const& amount, std::uint32_t flags) return jv; } +// This function overload is especially useful for modelling Authorised trust +// lines. account (first function parameter) is the issuing authority, it +// authorises peer (third function parameter) to hold a certain currency +// (amount, the second function parameter) Json::Value trust( Account const& account, From ae7ea33b750c7bc74bbdf4e83519abf50f79420b Mon Sep 17 00:00:00 2001 From: Scott Schurr Date: Thu, 13 Jun 2024 14:57:12 -0700 Subject: [PATCH 05/82] fixReducedOffersV2: prevent offers from blocking order books: (#5032) Fixes issue #4937. The fixReducedOffersV1 amendment fixed certain forms of offer modification that could lead to blocked order books. Reduced offers can block order books if the effective quality of the reduced offer is worse than the quality of the original offer (from the perspective of the taker). It turns out that, for small values, the quality of the reduced offer can be significantly affected by the rounding mode used during scaling computations. Issue #4937 identified an additional code path that modified offers in a way that could lead to blocked order books. This commit changes the rounding in that newly located code path so the quality of the modified offer is never worse than the quality of the offer as it was originally placed. It is possible that additional ways of producing blocking offers will come to light. Therefore there may be a future need for a V3 amendment. --- src/ripple/app/paths/AMMOffer.h | 4 +- src/ripple/app/paths/impl/AMMOffer.cpp | 13 +- src/ripple/app/paths/impl/BookStep.cpp | 25 +-- src/ripple/app/tx/impl/Offer.h | 22 ++- src/ripple/protocol/Feature.h | 3 +- src/ripple/protocol/Quality.h | 168 ++++++++++++++------ src/ripple/protocol/impl/Feature.cpp | 1 + src/ripple/protocol/impl/Quality.cpp | 28 +++- src/test/app/AMM_test.cpp | 36 +++-- src/test/app/Flow_test.cpp | 46 +++++- src/test/app/Offer_test.cpp | 142 ++++++++++------- src/test/app/ReducedOffer_test.cpp | 205 +++++++++++++++++++++++-- 12 files changed, 534 insertions(+), 159 deletions(-) diff --git a/src/ripple/app/paths/AMMOffer.h b/src/ripple/app/paths/AMMOffer.h index e3fb41e220b..e47a5613b09 100644 --- a/src/ripple/app/paths/AMMOffer.h +++ b/src/ripple/app/paths/AMMOffer.h @@ -103,7 +103,6 @@ class AMMOffer limitOut( TAmounts const& offrAmt, TOut const& limit, - bool fixReducedOffers, bool roundUp) const; /** Limit in of the provided offer. If one-path then swapIn @@ -111,7 +110,8 @@ class AMMOffer * current quality. */ TAmounts - limitIn(TAmounts const& offrAmt, TIn const& limit) const; + limitIn(TAmounts const& offrAmt, TIn const& limit, bool roundUp) + const; QualityFunction getQualityFunc() const; diff --git a/src/ripple/app/paths/impl/AMMOffer.cpp b/src/ripple/app/paths/impl/AMMOffer.cpp index 697bac9c790..bf85ead6194 100644 --- a/src/ripple/app/paths/impl/AMMOffer.cpp +++ b/src/ripple/app/paths/impl/AMMOffer.cpp @@ -81,7 +81,6 @@ TAmounts AMMOffer::limitOut( TAmounts const& offrAmt, TOut const& limit, - bool fixReducedOffers, bool roundUp) const { // Change the offer size proportionally to the original offer quality @@ -92,7 +91,8 @@ AMMOffer::limitOut( // poolPays * poolGets < (poolPays - assetOut) * (poolGets + assetIn) if (ammLiquidity_.multiPath()) { - if (fixReducedOffers) + if (auto const& rules = getCurrentTransactionRules(); + rules && rules->enabled(fixReducedOffersV1)) // It turns out that the ceil_out implementation has some slop in // it. ceil_out_strict removes that slop. But removing that slop // affects transaction outcomes, so the change must be made using @@ -110,11 +110,18 @@ template TAmounts AMMOffer::limitIn( TAmounts const& offrAmt, - TIn const& limit) const + TIn const& limit, + bool roundUp) const { // See the comments above in limitOut(). if (ammLiquidity_.multiPath()) + { + if (auto const& rules = getCurrentTransactionRules(); + rules && rules->enabled(fixReducedOffersV2)) + return quality().ceil_in_strict(offrAmt, limit, roundUp); + return quality().ceil_in(offrAmt, limit); + } return {limit, swapAssetIn(balances_, limit, ammLiquidity_.tradingFee())}; } diff --git a/src/ripple/app/paths/impl/BookStep.cpp b/src/ripple/app/paths/impl/BookStep.cpp index 4a43d653e0c..af0c40b1925 100644 --- a/src/ripple/app/paths/impl/BookStep.cpp +++ b/src/ripple/app/paths/impl/BookStep.cpp @@ -668,7 +668,14 @@ limitStepIn( stpAmt.in = limit; auto const inLmt = mulRatio(stpAmt.in, QUALITY_ONE, transferRateIn, /*roundUp*/ false); - ofrAmt = offer.limitIn(ofrAmt, inLmt); + // It turns out we can prevent order book blocking by (strictly) + // rounding down the ceil_in() result. By rounding down we guarantee + // that the quality of an offer left in the ledger is as good or + // better than the quality of the containing order book page. + // + // This adjustment changes transaction outcomes, so it must be made + // under an amendment. + ofrAmt = offer.limitIn(ofrAmt, inLmt, /* roundUp */ false); stpAmt.out = ofrAmt.out; ownerGives = mulRatio( ofrAmt.out, transferRateOut, QUALITY_ONE, /*roundUp*/ false); @@ -685,8 +692,7 @@ limitStepOut( TOut& ownerGives, std::uint32_t transferRateIn, std::uint32_t transferRateOut, - TOut const& limit, - Rules const& rules) + TOut const& limit) { if (limit < stpAmt.out) { @@ -696,7 +702,6 @@ limitStepOut( ofrAmt = offer.limitOut( ofrAmt, stpAmt.out, - rules.enabled(fixReducedOffersV1), /*roundUp*/ true); stpAmt.in = mulRatio(ofrAmt.in, transferRateIn, QUALITY_ONE, /*roundUp*/ true); @@ -736,7 +741,6 @@ BookStep::forEachOffer( sb, afView, book_, sb.parentCloseTime(), counter, j_); bool const flowCross = afView.rules().enabled(featureFlowCross); - bool const fixReduced = afView.rules().enabled(fixReducedOffersV1); bool offerAttempted = false; std::optional ofrQ; auto execOffer = [&](auto& offer) { @@ -817,8 +821,7 @@ BookStep::forEachOffer( // It turns out we can prevent order book blocking by (strictly) // rounding down the ceil_out() result. This adjustment changes // transaction outcomes, so it must be made under an amendment. - ofrAmt = offer.limitOut( - ofrAmt, stpAmt.out, fixReduced, /*roundUp*/ false); + ofrAmt = offer.limitOut(ofrAmt, stpAmt.out, /*roundUp*/ false); stpAmt.in = mulRatio(ofrAmt.in, ofrInRate, QUALITY_ONE, /*roundUp*/ true); @@ -1055,8 +1058,7 @@ BookStep::revImp( ownerGivesAdj, transferRateIn, transferRateOut, - remainingOut, - afView.rules()); + remainingOut); remainingOut = beast::zero; savedIns.insert(stpAdjAmt.in); savedOuts.insert(remainingOut); @@ -1208,8 +1210,7 @@ BookStep::fwdImp( ownerGivesAdjRev, transferRateIn, transferRateOut, - remainingOut, - afView.rules()); + remainingOut); if (stpAdjAmtRev.in == remainingIn) { @@ -1228,7 +1229,7 @@ BookStep::fwdImp( } else { - // This is (likely) a problem case, and wil be caught + // This is (likely) a problem case, and will be caught // with later checks savedOuts.insert(lastOutAmt); } diff --git a/src/ripple/app/tx/impl/Offer.h b/src/ripple/app/tx/impl/Offer.h index bdae4d2b155..53253426c40 100644 --- a/src/ripple/app/tx/impl/Offer.h +++ b/src/ripple/app/tx/impl/Offer.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -140,11 +141,11 @@ class TOffer : private TOfferBase limitOut( TAmounts const& offrAmt, TOut const& limit, - bool fixReducedOffers, bool roundUp) const; TAmounts - limitIn(TAmounts const& offrAmt, TIn const& limit) const; + limitIn(TAmounts const& offrAmt, TIn const& limit, bool roundUp) + const; template static TER @@ -219,10 +220,10 @@ TAmounts TOffer::limitOut( TAmounts const& offrAmt, TOut const& limit, - bool fixReducedOffers, bool roundUp) const { - if (fixReducedOffers) + if (auto const& rules = getCurrentTransactionRules(); + rules && rules->enabled(fixReducedOffersV1)) // It turns out that the ceil_out implementation has some slop in // it. ceil_out_strict removes that slop. But removing that slop // affects transaction outcomes, so the change must be made using @@ -233,9 +234,18 @@ TOffer::limitOut( template TAmounts -TOffer::limitIn(TAmounts const& offrAmt, TIn const& limit) - const +TOffer::limitIn( + TAmounts const& offrAmt, + TIn const& limit, + bool roundUp) const { + if (auto const& rules = getCurrentTransactionRules(); + rules && rules->enabled(fixReducedOffersV2)) + // It turns out that the ceil_in implementation has some slop in + // it. ceil_in_strict removes that slop. But removing that slop + // affects transaction outcomes, so the change must be made using + // an amendment. + return quality().ceil_in_strict(offrAmt, limit, roundUp); return m_quality.ceil_in(offrAmt, limit); } diff --git a/src/ripple/protocol/Feature.h b/src/ripple/protocol/Feature.h index 57cd9513eea..91cf4d97ca4 100644 --- a/src/ripple/protocol/Feature.h +++ b/src/ripple/protocol/Feature.h @@ -74,7 +74,7 @@ namespace detail { // Feature.cpp. Because it's only used to reserve storage, and determine how // large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than // the actual number of amendments. A LogicError on startup will verify this. -static constexpr std::size_t numFeatures = 73; +static constexpr std::size_t numFeatures = 74; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated @@ -360,6 +360,7 @@ extern uint256 const fixEmptyDID; extern uint256 const fixXChainRewardRounding; extern uint256 const fixPreviousTxnID; extern uint256 const fixAMMv1_1; +extern uint256 const fixReducedOffersV2; } // namespace ripple diff --git a/src/ripple/protocol/Quality.h b/src/ripple/protocol/Quality.h index 840d8d444e1..06b8254df5e 100644 --- a/src/ripple/protocol/Quality.h +++ b/src/ripple/protocol/Quality.h @@ -181,71 +181,71 @@ class Quality Math is avoided if the result is exact. The output is clamped to prevent money creation. */ - Amounts + [[nodiscard]] Amounts ceil_in(Amounts const& amount, STAmount const& limit) const; template - TAmounts - ceil_in(TAmounts const& amount, In const& limit) const - { - if (amount.in <= limit) - return amount; - - // Use the existing STAmount implementation for now, but consider - // replacing with code specific to IOUAMount and XRPAmount - Amounts stAmt(toSTAmount(amount.in), toSTAmount(amount.out)); - STAmount stLim(toSTAmount(limit)); - auto const stRes = ceil_in(stAmt, stLim); - return TAmounts( - toAmount(stRes.in), toAmount(stRes.out)); - } + [[nodiscard]] TAmounts + ceil_in(TAmounts const& amount, In const& limit) const; + + // Some of the underlying rounding functions called by ceil_in() ignored + // low order bits that could influence rounding decisions. This "strict" + // method uses underlying functions that pay attention to all the bits. + [[nodiscard]] Amounts + ceil_in_strict(Amounts const& amount, STAmount const& limit, bool roundUp) + const; + + template + [[nodiscard]] TAmounts + ceil_in_strict( + TAmounts const& amount, + In const& limit, + bool roundUp) const; /** Returns the scaled amount with out capped. Math is avoided if the result is exact. The input is clamped to prevent money creation. */ - Amounts + [[nodiscard]] Amounts ceil_out(Amounts const& amount, STAmount const& limit) const; template - TAmounts - ceil_out(TAmounts const& amount, Out const& limit) const - { - if (amount.out <= limit) - return amount; - - // Use the existing STAmount implementation for now, but consider - // replacing with code specific to IOUAMount and XRPAmount - Amounts stAmt(toSTAmount(amount.in), toSTAmount(amount.out)); - STAmount stLim(toSTAmount(limit)); - auto const stRes = ceil_out(stAmt, stLim); - return TAmounts( - toAmount(stRes.in), toAmount(stRes.out)); - } + [[nodiscard]] TAmounts + ceil_out(TAmounts const& amount, Out const& limit) const; - Amounts + // Some of the underlying rounding functions called by ceil_out() ignored + // low order bits that could influence rounding decisions. This "strict" + // method uses underlying functions that pay attention to all the bits. + [[nodiscard]] Amounts ceil_out_strict(Amounts const& amount, STAmount const& limit, bool roundUp) const; template - TAmounts + [[nodiscard]] TAmounts ceil_out_strict( TAmounts const& amount, Out const& limit, - bool roundUp) const - { - if (amount.out <= limit) - return amount; - - // Use the existing STAmount implementation for now, but consider - // replacing with code specific to IOUAMount and XRPAmount - Amounts stAmt(toSTAmount(amount.in), toSTAmount(amount.out)); - STAmount stLim(toSTAmount(limit)); - auto const stRes = ceil_out_strict(stAmt, stLim, roundUp); - return TAmounts( - toAmount(stRes.in), toAmount(stRes.out)); - } + bool roundUp) const; +private: + // The ceil_in and ceil_out methods that deal in TAmount all convert + // their arguments to STAoumout and convert the result back to TAmount. + // This helper function takes care of all the conversion operations. + template < + class In, + class Out, + class Lim, + typename FnPtr, + std::same_as... Round> + [[nodiscard]] TAmounts + ceil_TAmounts_helper( + TAmounts const& amount, + Lim const& limit, + Lim const& limit_cmp, + FnPtr ceil_function, + Round... round) const; + +public: /** Returns `true` if lhs is lower quality than `rhs`. Lower quality means the taker receives a worse deal. Higher quality is better for the taker. @@ -327,6 +327,84 @@ class Quality } }; +template < + class In, + class Out, + class Lim, + typename FnPtr, + std::same_as... Round> +TAmounts +Quality::ceil_TAmounts_helper( + TAmounts const& amount, + Lim const& limit, + Lim const& limit_cmp, + FnPtr ceil_function, + Round... roundUp) const +{ + if (limit_cmp <= limit) + return amount; + + // Use the existing STAmount implementation for now, but consider + // replacing with code specific to IOUAMount and XRPAmount + Amounts stAmt(toSTAmount(amount.in), toSTAmount(amount.out)); + STAmount stLim(toSTAmount(limit)); + Amounts const stRes = ((*this).*ceil_function)(stAmt, stLim, roundUp...); + return TAmounts(toAmount(stRes.in), toAmount(stRes.out)); +} + +template +TAmounts +Quality::ceil_in(TAmounts const& amount, In const& limit) const +{ + // Construct a function pointer to the function we want to call. + static constexpr Amounts (Quality::*ceil_in_fn_ptr)( + Amounts const&, STAmount const&) const = &Quality::ceil_in; + + return ceil_TAmounts_helper(amount, limit, amount.in, ceil_in_fn_ptr); +} + +template +TAmounts +Quality::ceil_in_strict( + TAmounts const& amount, + In const& limit, + bool roundUp) const +{ + // Construct a function pointer to the function we want to call. + static constexpr Amounts (Quality::*ceil_in_fn_ptr)( + Amounts const&, STAmount const&, bool) const = &Quality::ceil_in_strict; + + return ceil_TAmounts_helper( + amount, limit, amount.in, ceil_in_fn_ptr, roundUp); +} + +template +TAmounts +Quality::ceil_out(TAmounts const& amount, Out const& limit) const +{ + // Construct a function pointer to the function we want to call. + static constexpr Amounts (Quality::*ceil_out_fn_ptr)( + Amounts const&, STAmount const&) const = &Quality::ceil_out; + + return ceil_TAmounts_helper(amount, limit, amount.out, ceil_out_fn_ptr); +} + +template +TAmounts +Quality::ceil_out_strict( + TAmounts const& amount, + Out const& limit, + bool roundUp) const +{ + // Construct a function pointer to the function we want to call. + static constexpr Amounts (Quality::*ceil_out_fn_ptr)( + Amounts const&, STAmount const&, bool) const = + &Quality::ceil_out_strict; + + return ceil_TAmounts_helper( + amount, limit, amount.out, ceil_out_fn_ptr, roundUp); +} + /** Calculate the quality of a two-hop path given the two hops. @param lhs The first leg of the path: input to intermediate. @param rhs The second leg of the path: intermediate to output. diff --git a/src/ripple/protocol/impl/Feature.cpp b/src/ripple/protocol/impl/Feature.cpp index ae7a8291bb4..4c347375766 100644 --- a/src/ripple/protocol/impl/Feature.cpp +++ b/src/ripple/protocol/impl/Feature.cpp @@ -467,6 +467,7 @@ REGISTER_FIX (fixEmptyDID, Supported::yes, VoteBehavior::De REGISTER_FIX (fixXChainRewardRounding, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixPreviousTxnID, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixAMMv1_1, Supported::yes, VoteBehavior::DefaultNo); +REGISTER_FIX (fixReducedOffersV2, Supported::yes, VoteBehavior::DefaultNo); // The following amendments are obsolete, but must remain supported // because they could potentially get enabled. diff --git a/src/ripple/protocol/impl/Quality.cpp b/src/ripple/protocol/impl/Quality.cpp index f7b9d6b3c41..2cb60f738d8 100644 --- a/src/ripple/protocol/impl/Quality.cpp +++ b/src/ripple/protocol/impl/Quality.cpp @@ -64,13 +64,20 @@ Quality::operator--(int) return prev; } -Amounts -Quality::ceil_in(Amounts const& amount, STAmount const& limit) const +template +static Amounts +ceil_in_impl( + Amounts const& amount, + STAmount const& limit, + bool roundUp, + Quality const& quality) { if (amount.in > limit) { Amounts result( - limit, divRound(limit, rate(), amount.out.issue(), true)); + limit, + DivRoundFunc(limit, quality.rate(), amount.out.issue(), roundUp)); // Clamp out if (result.out > amount.out) result.out = amount.out; @@ -81,6 +88,21 @@ Quality::ceil_in(Amounts const& amount, STAmount const& limit) const return amount; } +Amounts +Quality::ceil_in(Amounts const& amount, STAmount const& limit) const +{ + return ceil_in_impl(amount, limit, /* roundUp */ true, *this); +} + +Amounts +Quality::ceil_in_strict( + Amounts const& amount, + STAmount const& limit, + bool roundUp) const +{ + return ceil_in_impl(amount, limit, roundUp, *this); +} + template static Amounts diff --git a/src/test/app/AMM_test.cpp b/src/test/app/AMM_test.cpp index b4abd385257..a3c4ae9800c 100644 --- a/src/test/app/AMM_test.cpp +++ b/src/test/app/AMM_test.cpp @@ -3618,13 +3618,16 @@ struct AMM_test : public jtx::AMMTest STAmount(USD, UINT64_C(9'970'097277662122), -12), STAmount(EUR, UINT64_C(10'029'99250187452), -11), ammUSD_EUR.tokens())); - BEAST_EXPECT(expectOffers( - env, - alice, - 1, - {{Amounts{ - XRPAmount(30'201'749), - STAmount(USD, UINT64_C(29'90272233787818), -14)}}})); + + // fixReducedOffersV2 changes the expected results slightly. + Amounts const expectedAmounts = + env.closed()->rules().enabled(fixReducedOffersV2) + ? Amounts{XRPAmount(30'201'749), STAmount(USD, UINT64_C(29'90272233787816), -14)} + : Amounts{ + XRPAmount(30'201'749), + STAmount(USD, UINT64_C(29'90272233787818), -14)}; + + BEAST_EXPECT(expectOffers(env, alice, 1, {{expectedAmounts}})); } else { @@ -3632,13 +3635,16 @@ struct AMM_test : public jtx::AMMTest STAmount(USD, UINT64_C(9'970'097277662172), -12), STAmount(EUR, UINT64_C(10'029'99250187452), -11), ammUSD_EUR.tokens())); - BEAST_EXPECT(expectOffers( - env, - alice, - 1, - {{Amounts{ - XRPAmount(30'201'749), - STAmount(USD, UINT64_C(29'9027223378284), -13)}}})); + + // fixReducedOffersV2 changes the expected results slightly. + Amounts const expectedAmounts = + env.closed()->rules().enabled(fixReducedOffersV2) + ? Amounts{XRPAmount(30'201'749), STAmount(USD, UINT64_C(29'90272233782839), -14)} + : Amounts{ + XRPAmount(30'201'749), + STAmount(USD, UINT64_C(29'90272233782840), -14)}; + + BEAST_EXPECT(expectOffers(env, alice, 1, {{expectedAmounts}})); } // Initial 30,000 + 100 BEAST_EXPECT(expectLine(env, carol, STAmount{USD, 30'100})); @@ -6874,6 +6880,8 @@ struct AMM_test : public jtx::AMMTest testInvalidAMMPayment(); testBasicPaymentEngine(all); testBasicPaymentEngine(all - fixAMMv1_1); + testBasicPaymentEngine(all - fixReducedOffersV2); + testBasicPaymentEngine(all - fixAMMv1_1 - fixReducedOffersV2); testAMMTokens(); testAmendment(); testFlags(); diff --git a/src/test/app/Flow_test.cpp b/src/test/app/Flow_test.cpp index 920f7a6e058..bb7b96f1072 100644 --- a/src/test/app/Flow_test.cpp +++ b/src/test/app/Flow_test.cpp @@ -506,7 +506,6 @@ struct Flow_test : public beast::unit_test::suite // Without limits, the 0.4 USD would produce 1000 EUR in the forward // pass. This test checks that the payment produces 1 EUR, as // expected. - Env env(*this, features); env.fund(XRP(10000), alice, bob, carol, gw); env.trust(USD(1000), alice, bob, carol); @@ -515,17 +514,52 @@ struct Flow_test : public beast::unit_test::suite env(pay(gw, alice, USD(1000))); env(pay(gw, bob, EUR(1000))); + Keylet const bobUsdOffer = keylet::offer(bob, env.seq(bob)); env(offer(bob, USD(1), drops(2)), txflags(tfPassive)); env(offer(bob, drops(1), EUR(1000)), txflags(tfPassive)); + bool const reducedOffersV2 = features[fixReducedOffersV2]; + + // With reducedOffersV2, it is not allowed to accept less than + // USD(0.5) of bob's USD offer. If we provide 1 drop for less + // than USD(0.5), then the remaining fractional offer would + // block the order book. + TER const expectedTER = + reducedOffersV2 ? TER(tecPATH_DRY) : TER(tesSUCCESS); env(pay(alice, carol, EUR(1)), path(~XRP, ~EUR), sendmax(USD(0.4)), - txflags(tfNoRippleDirect | tfPartialPayment)); + txflags(tfNoRippleDirect | tfPartialPayment), + ter(expectedTER)); + + if (!reducedOffersV2) + { + env.require(balance(carol, EUR(1))); + env.require(balance(bob, USD(0.4))); + env.require(balance(bob, EUR(999))); - env.require(balance(carol, EUR(1))); - env.require(balance(bob, USD(0.4))); - env.require(balance(bob, EUR(999))); + // Show that bob's USD offer is now a blocker. + std::shared_ptr const usdOffer = env.le(bobUsdOffer); + if (BEAST_EXPECT(usdOffer)) + { + std::uint64_t const bookRate = [&usdOffer]() { + // Extract the least significant 64 bits from the + // book page. That's where the quality is stored. + std::string bookDirStr = + to_string(usdOffer->at(sfBookDirectory)); + bookDirStr.erase(0, 48); + return std::stoull(bookDirStr, nullptr, 16); + }(); + std::uint64_t const actualRate = getRate( + usdOffer->at(sfTakerGets), usdOffer->at(sfTakerPays)); + + // We expect the actual rate of the offer to be worse + // (larger) than the rate of the book page holding the + // offer. This is a defect which is corrected by + // fixReducedOffersV2. + BEAST_EXPECT(actualRate > bookRate); + } + } } } @@ -1375,9 +1409,11 @@ struct Flow_test : public beast::unit_test::suite { using namespace jtx; FeatureBitset const ownerPaysFee{featureOwnerPaysFee}; + FeatureBitset const reducedOffersV2(fixReducedOffersV2); testLineQuality(features); testFalseDry(features); + testBookStep(features - reducedOffersV2); testDirectStep(features); testBookStep(features); testDirectStep(features | ownerPaysFee); diff --git a/src/test/app/Offer_test.cpp b/src/test/app/Offer_test.cpp index 95ffd9f3aee..add436d5c59 100644 --- a/src/test/app/Offer_test.cpp +++ b/src/test/app/Offer_test.cpp @@ -1387,78 +1387,106 @@ class OfferBaseUtil_test : public beast::unit_test::suite using namespace jtx; - Env env{*this, features}; + // This is one of the few tests where fixReducedOffersV2 changes the + // results. So test both with and without fixReducedOffersV2. + for (FeatureBitset localFeatures : + {features - fixReducedOffersV2, features | fixReducedOffersV2}) + { + Env env{*this, localFeatures}; - auto const gw = Account{"gateway"}; - auto const alice = Account{"alice"}; - auto const bob = Account{"bob"}; - auto const USD = gw["USD"]; - auto const BTC = gw["BTC"]; + auto const gw = Account{"gateway"}; + auto const alice = Account{"alice"}; + auto const bob = Account{"bob"}; + auto const USD = gw["USD"]; + auto const BTC = gw["BTC"]; - // these *interesting* amounts were taken - // from the original JS test that was ported here - auto const gw_initial_balance = drops(1149999730); - auto const alice_initial_balance = drops(499946999680); - auto const bob_initial_balance = drops(10199999920); - auto const small_amount = - STAmount{bob["USD"].issue(), UINT64_C(2710505431213761), -33}; + // these *interesting* amounts were taken + // from the original JS test that was ported here + auto const gw_initial_balance = drops(1149999730); + auto const alice_initial_balance = drops(499946999680); + auto const bob_initial_balance = drops(10199999920); + auto const small_amount = + STAmount{bob["USD"].issue(), UINT64_C(2710505431213761), -33}; - env.fund(gw_initial_balance, gw); - env.fund(alice_initial_balance, alice); - env.fund(bob_initial_balance, bob); + env.fund(gw_initial_balance, gw); + env.fund(alice_initial_balance, alice); + env.fund(bob_initial_balance, bob); - env(rate(gw, 1.005)); + env(rate(gw, 1.005)); - env(trust(alice, USD(500))); - env(trust(bob, USD(50))); - env(trust(gw, alice["USD"](100))); + env(trust(alice, USD(500))); + env(trust(bob, USD(50))); + env(trust(gw, alice["USD"](100))); - env(pay(gw, alice, alice["USD"](50))); - env(pay(gw, bob, small_amount)); + env(pay(gw, alice, alice["USD"](50))); + env(pay(gw, bob, small_amount)); - env(offer(alice, USD(50), XRP(150000))); + env(offer(alice, USD(50), XRP(150000))); - // unfund the offer - env(pay(alice, gw, USD(100))); + // unfund the offer + env(pay(alice, gw, USD(100))); - // drop the trust line (set to 0) - env(trust(gw, alice["USD"](0))); + // drop the trust line (set to 0) + env(trust(gw, alice["USD"](0))); - // verify balances - auto jrr = ledgerEntryState(env, alice, gw, "USD"); - BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "50"); + // verify balances + auto jrr = ledgerEntryState(env, alice, gw, "USD"); + BEAST_EXPECT( + jrr[jss::node][sfBalance.fieldName][jss::value] == "50"); - jrr = ledgerEntryState(env, bob, gw, "USD"); - BEAST_EXPECT( - jrr[jss::node][sfBalance.fieldName][jss::value] == - "-2710505431213761e-33"); + jrr = ledgerEntryState(env, bob, gw, "USD"); + BEAST_EXPECT( + jrr[jss::node][sfBalance.fieldName][jss::value] == + "-2710505431213761e-33"); - // create crossing offer - env(offer(bob, XRP(2000), USD(1))); + // create crossing offer + std::uint32_t const bobOfferSeq = env.seq(bob); + env(offer(bob, XRP(2000), USD(1))); - // verify balances again. - // - // NOTE : - // Here a difference in the rounding modes of our two offer crossing - // algorithms becomes apparent. The old offer crossing would consume - // small_amount and transfer no XRP. The new offer crossing transfers - // a single drop, rather than no drops. - auto const crossingDelta = - features[featureFlowCross] ? drops(1) : drops(0); + if (localFeatures[featureFlowCross] && + localFeatures[fixReducedOffersV2]) + { + // With the rounding introduced by fixReducedOffersV2, bob's + // offer does not cross alice's offer and goes straight into + // the ledger. + jrr = ledgerEntryState(env, bob, gw, "USD"); + BEAST_EXPECT( + jrr[jss::node][sfBalance.fieldName][jss::value] == + "-2710505431213761e-33"); + + Json::Value const bobOffer = + ledgerEntryOffer(env, bob, bobOfferSeq)[jss::node]; + BEAST_EXPECT(bobOffer[sfTakerGets.jsonName][jss::value] == "1"); + BEAST_EXPECT(bobOffer[sfTakerPays.jsonName] == "2000000000"); + return; + } - jrr = ledgerEntryState(env, alice, gw, "USD"); - BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "50"); - BEAST_EXPECT( - env.balance(alice, xrpIssue()) == - alice_initial_balance - env.current()->fees().base * 3 - - crossingDelta); + // verify balances again. + // + // NOTE: + // Here a difference in the rounding modes of our two offer + // crossing algorithms becomes apparent. The old offer crossing + // would consume small_amount and transfer no XRP. The new offer + // crossing transfers a single drop, rather than no drops. + auto const crossingDelta = + localFeatures[featureFlowCross] ? drops(1) : drops(0); + + jrr = ledgerEntryState(env, alice, gw, "USD"); + BEAST_EXPECT( + jrr[jss::node][sfBalance.fieldName][jss::value] == "50"); + BEAST_EXPECT( + env.balance(alice, xrpIssue()) == + alice_initial_balance - env.current()->fees().base * 3 - + crossingDelta); - jrr = ledgerEntryState(env, bob, gw, "USD"); - BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] == "0"); - BEAST_EXPECT( - env.balance(bob, xrpIssue()) == - bob_initial_balance - env.current()->fees().base * 2 + - crossingDelta); + jrr = ledgerEntryState(env, bob, gw, "USD"); + BEAST_EXPECT( + jrr[jss::node][sfBalance.fieldName][jss::value] == "0"); + BEAST_EXPECT( + env.balance(bob, xrpIssue()) == + bob_initial_balance - env.current()->fees().base * 2 + + crossingDelta); + } } void diff --git a/src/test/app/ReducedOffer_test.cpp b/src/test/app/ReducedOffer_test.cpp index f82efcb7fc8..186162d5023 100644 --- a/src/test/app/ReducedOffer_test.cpp +++ b/src/test/app/ReducedOffer_test.cpp @@ -22,6 +22,8 @@ #include #include +#include + namespace ripple { namespace test { @@ -56,13 +58,11 @@ class ReducedOffer_test : public beast::unit_test::suite static void cleanupOldOffers( jtx::Env& env, - jtx::Account const& acct1, - jtx::Account const& acct2, - std::uint32_t acct1OfferSeq, - std::uint32_t acct2OfferSeq) + std::initializer_list> + list) { - env(offer_cancel(acct1, acct1OfferSeq)); - env(offer_cancel(acct2, acct2OfferSeq)); + for (auto [acct, offerSeq] : list) + env(offer_cancel(acct, offerSeq)); env.close(); } @@ -180,7 +180,8 @@ class ReducedOffer_test : public beast::unit_test::suite // In preparation for the next iteration make sure the two // offers are gone from the ledger. - cleanupOldOffers(env, alice, bob, aliceOfferSeq, bobOfferSeq); + cleanupOldOffers( + env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}}); return badRate; }; @@ -279,7 +280,7 @@ class ReducedOffer_test : public beast::unit_test::suite // If the in-ledger offer was not consumed then further // results are meaningless. cleanupOldOffers( - env, alice, bob, aliceOfferSeq, bobOfferSeq); + env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}}); return 1; } // alice's offer should still be in the ledger, but reduced in @@ -337,7 +338,8 @@ class ReducedOffer_test : public beast::unit_test::suite // In preparation for the next iteration make sure the two // offers are gone from the ledger. - cleanupOldOffers(env, alice, bob, aliceOfferSeq, bobOfferSeq); + cleanupOldOffers( + env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}}); return badRate; }; @@ -452,7 +454,7 @@ class ReducedOffer_test : public beast::unit_test::suite // In preparation for the next iteration clean up any // leftover offers. cleanupOldOffers( - env, alice, bob, aliceOfferSeq, bobOfferSeq); + env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}}); // Zero out alice's and bob's USD balances. if (STAmount const aliceBalance = env.balance(alice, USD); @@ -573,7 +575,8 @@ class ReducedOffer_test : public beast::unit_test::suite // In preparation for the next iteration clean up any // leftover offers. - cleanupOldOffers(env, alice, bob, aliceOfferSeq, bobOfferSeq); + cleanupOldOffers( + env, {{alice, aliceOfferSeq}, {bob, bobOfferSeq}}); // Zero out alice's and bob's IOU balances. auto zeroBalance = [&env, &gw]( @@ -606,6 +609,185 @@ class ReducedOffer_test : public beast::unit_test::suite } } + Amounts + jsonOfferToAmounts(Json::Value const& json) + { + STAmount const in = + amountFromJson(sfTakerPays, json[sfTakerPays.jsonName]); + STAmount const out = + amountFromJson(sfTakerGets, json[sfTakerGets.jsonName]); + return {in, out}; + } + + void + testSellPartialCrossOldXrpIouQChange() + { + // This test case was motivated by Issue #4937. It recreates + // the specific failure identified in that issue and samples some other + // cases in the same vicinity to make sure that the new behavior makes + // sense. + testcase("exercise tfSell partial cross old XRP/IOU offer Q change"); + + using namespace jtx; + + Account const gw("gateway"); + Account const alice("alice"); + Account const bob("bob"); + Account const carol("carol"); + auto const USD = gw["USD"]; + + // Make one test run without fixReducedOffersV2 and one with. + for (FeatureBitset features : + {supported_amendments() - fixReducedOffersV2, + supported_amendments() | fixReducedOffersV2}) + { + // Make sure none of the offers we generate are under funded. + Env env{*this, features}; + env.fund(XRP(10'000'000), gw, alice, bob, carol); + env.close(); + + env(trust(alice, USD(10'000'000))); + env(trust(bob, USD(10'000'000))); + env(trust(carol, USD(10'000'000))); + env.close(); + + env(pay(gw, alice, USD(10'000'000))); + env(pay(gw, bob, USD(10'000'000))); + env(pay(gw, carol, USD(10'000'000))); + env.close(); + + // Lambda that: + // 1. Exercises one offer trio, + // 2. Collects the results, and + // 3. Cleans up for the next offer trio. + auto exerciseOfferTrio = + [this, &env, &alice, &bob, &carol, &USD]( + Amounts const& carolOffer) -> unsigned int { + // alice submits an offer that may become a blocker. + std::uint32_t const aliceOfferSeq = env.seq(alice); + static Amounts const aliceInitialOffer(USD(2), drops(3382562)); + env(offer(alice, aliceInitialOffer.in, aliceInitialOffer.out)); + env.close(); + STAmount const initialRate = + Quality(jsonOfferToAmounts(ledgerEntryOffer( + env, alice, aliceOfferSeq)[jss::node])) + .rate(); + + // bob submits an offer that is more desirable than alice's + std::uint32_t const bobOfferSeq = env.seq(bob); + env(offer(bob, USD(0.97086565812384), drops(1642020))); + env.close(); + + // Now carol's offer consumes bob's and partially crosses + // alice's. The tfSell flag is important. + std::uint32_t const carolOfferSeq = env.seq(carol); + env(offer(carol, carolOffer.in, carolOffer.out), + txflags(tfSell)); + env.close(); + + // carol's offer should not have made it into the ledger and + // bob's offer should be fully consumed. + if (!BEAST_EXPECT( + !offerInLedger(env, carol, carolOfferSeq) && + !offerInLedger(env, bob, bobOfferSeq))) + { + // If carol's or bob's offers are still in the ledger then + // further results are meaningless. + cleanupOldOffers( + env, + {{alice, aliceOfferSeq}, + {bob, bobOfferSeq}, + {carol, carolOfferSeq}}); + return 1; + } + // alice's offer should still be in the ledger, but reduced in + // size. + unsigned int badRate = 1; + { + Json::Value aliceOffer = + ledgerEntryOffer(env, alice, aliceOfferSeq); + + Amounts aliceReducedOffer = + jsonOfferToAmounts(aliceOffer[jss::node]); + + BEAST_EXPECT(aliceReducedOffer.in < aliceInitialOffer.in); + BEAST_EXPECT(aliceReducedOffer.out < aliceInitialOffer.out); + STAmount const inLedgerRate = + Quality(aliceReducedOffer).rate(); + badRate = inLedgerRate > initialRate ? 1 : 0; + + // If the inLedgerRate is less than initial rate, then + // incrementing the mantissa of the reduced TakerGets + // should result in a rate higher than initial. Check + // this to verify that the largest allowable TakerGets + // was computed. + if (badRate == 0) + { + STAmount const tweakedTakerGets( + aliceReducedOffer.in.issue(), + aliceReducedOffer.in.mantissa() + 1, + aliceReducedOffer.in.exponent(), + aliceReducedOffer.in.negative()); + STAmount const tweakedRate = + Quality( + Amounts{aliceReducedOffer.in, tweakedTakerGets}) + .rate(); + BEAST_EXPECT(tweakedRate > initialRate); + } +#if 0 + std::cout << "Placed rate: " << initialRate + << "; in-ledger rate: " << inLedgerRate + << "; TakerPays: " << aliceReducedOffer.in + << "; TakerGets: " << aliceReducedOffer.out + << std::endl; +// #else + std::string_view filler = badRate ? "**" : " "; + std::cout << "| " << aliceReducedOffer.in << "` | `" + << aliceReducedOffer.out << "` | `" << initialRate + << "` | " << filler << "`" << inLedgerRate << "`" + << filler << std::endl; +#endif + } + + // In preparation for the next iteration make sure all three + // offers are gone from the ledger. + cleanupOldOffers( + env, + {{alice, aliceOfferSeq}, + {bob, bobOfferSeq}, + {carol, carolOfferSeq}}); + return badRate; + }; + + constexpr int loopCount = 100; + unsigned int blockedCount = 0; + { + STAmount increaseGets = USD(0); + STAmount const step(increaseGets.issue(), 1, -8); + for (unsigned int i = 0; i < loopCount; ++i) + { + blockedCount += exerciseOfferTrio( + Amounts(drops(1642020), USD(1) + increaseGets)); + increaseGets += step; + } + } + + // If fixReducedOffersV2 is enabled, then none of the test cases + // should produce a potentially blocking rate. + // + // Also verify that if fixReducedOffersV2 is not enabled then + // some of the test cases produced a potentially blocking rate. + if (features[fixReducedOffersV2]) + { + BEAST_EXPECT(blockedCount == 0); + } + else + { + BEAST_EXPECT(blockedCount > 80); + } + } + } + void run() override { @@ -613,6 +795,7 @@ class ReducedOffer_test : public beast::unit_test::suite testPartialCrossOldXrpIouQChange(); testUnderFundedXrpIouQChange(); testUnderFundedIouIouQChange(); + testSellPartialCrossOldXrpIouQChange(); } }; From 20d05492d2d072b202db1f4c655c100dc57da372 Mon Sep 17 00:00:00 2001 From: Alex Kremer Date: Fri, 14 Jun 2024 20:00:57 +0200 Subject: [PATCH 06/82] Expose all amendments known by libxrpl (#5026) --- src/ripple/protocol/Feature.h | 6 ++ src/ripple/protocol/impl/Feature.cpp | 26 +++++++++ src/test/rpc/Feature_test.cpp | 83 +++++++++++++++++++++------- 3 files changed, 94 insertions(+), 21 deletions(-) diff --git a/src/ripple/protocol/Feature.h b/src/ripple/protocol/Feature.h index 91cf4d97ca4..78863908c25 100644 --- a/src/ripple/protocol/Feature.h +++ b/src/ripple/protocol/Feature.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -67,6 +68,11 @@ namespace ripple { enum class VoteBehavior : int { Obsolete = -1, DefaultNo = 0, DefaultYes }; +enum class AmendmentSupport : int { Retired = -1, Supported = 0, Unsupported }; + +/** All amendments libxrpl knows about. */ +std::map const& +allAmendments(); namespace detail { diff --git a/src/ripple/protocol/impl/Feature.cpp b/src/ripple/protocol/impl/Feature.cpp index 4c347375766..6543498cef1 100644 --- a/src/ripple/protocol/impl/Feature.cpp +++ b/src/ripple/protocol/impl/Feature.cpp @@ -116,6 +116,7 @@ class FeatureCollections // name, index, and uint256 feature identifier boost::multi_index::multi_index_container features; + std::map all; std::map supported; std::size_t upVotes = 0; std::size_t downVotes = 0; @@ -179,6 +180,13 @@ class FeatureCollections std::string featureToName(uint256 const& f) const; + /** All amendments that are registered within the table. */ + std::map const& + allAmendments() const + { + return all; + } + /** Amendments that this server supports. Whether they are enabled depends on the Rules defined in the validated ledger */ @@ -251,6 +259,14 @@ FeatureCollections::registerFeature( features.emplace_back(name, f); + auto const getAmendmentSupport = [=]() { + if (vote == VoteBehavior::Obsolete) + return AmendmentSupport::Retired; + return support == Supported::yes ? AmendmentSupport::Supported + : AmendmentSupport::Unsupported; + }; + all.emplace(name, getAmendmentSupport()); + if (support == Supported::yes) { supported.emplace(name, vote); @@ -266,6 +282,9 @@ FeatureCollections::registerFeature( check( supported.size() <= features.size(), "More supported features than defined features"); + check( + features.size() == all.size(), + "The 'all' features list is populated incorrectly"); return f; } else @@ -313,6 +332,13 @@ static FeatureCollections featureCollections; } // namespace +/** All amendments libxrpl knows of. */ +std::map const& +allAmendments() +{ + return featureCollections.allAmendments(); +} + /** Amendments that this server supports. Whether they are enabled depends on the Rules defined in the validated ledger */ diff --git a/src/test/rpc/Feature_test.cpp b/src/test/rpc/Feature_test.cpp index fd63aee98e2..010a61fbfcc 100644 --- a/src/test/rpc/Feature_test.cpp +++ b/src/test/rpc/Feature_test.cpp @@ -31,34 +31,75 @@ class Feature_test : public beast::unit_test::suite { testcase("internals"); - std::map const& supported = - ripple::detail::supportedAmendments(); + auto const& supportedAmendments = ripple::detail::supportedAmendments(); + auto const& allAmendments = ripple::allAmendments(); + BEAST_EXPECT( - supported.size() == + supportedAmendments.size() == ripple::detail::numDownVotedAmendments() + ripple::detail::numUpVotedAmendments()); - std::size_t up = 0, down = 0, obsolete = 0; - for (std::pair const& amendment : - supported) { - switch (amendment.second) + std::size_t up = 0, down = 0, obsolete = 0; + for (auto const& [name, vote] : supportedAmendments) { - case VoteBehavior::DefaultYes: - ++up; - break; - case VoteBehavior::DefaultNo: - ++down; - break; - case VoteBehavior::Obsolete: - ++obsolete; - break; - default: - fail("Unknown VoteBehavior", __FILE__, __LINE__); + switch (vote) + { + case VoteBehavior::DefaultYes: + ++up; + break; + case VoteBehavior::DefaultNo: + ++down; + break; + case VoteBehavior::Obsolete: + ++obsolete; + break; + default: + fail("Unknown VoteBehavior", __FILE__, __LINE__); + } + + if (vote == VoteBehavior::Obsolete) + { + BEAST_EXPECT( + allAmendments.contains(name) && + allAmendments.at(name) == AmendmentSupport::Retired); + } + else + { + BEAST_EXPECT( + allAmendments.contains(name) && + allAmendments.at(name) == AmendmentSupport::Supported); + } } + BEAST_EXPECT( + down + obsolete == ripple::detail::numDownVotedAmendments()); + BEAST_EXPECT(up == ripple::detail::numUpVotedAmendments()); + } + { + std::size_t supported = 0, unsupported = 0, retired = 0; + for (auto const& [name, support] : allAmendments) + { + switch (support) + { + case AmendmentSupport::Supported: + ++supported; + BEAST_EXPECT(supportedAmendments.contains(name)); + break; + case AmendmentSupport::Unsupported: + ++unsupported; + break; + case AmendmentSupport::Retired: + ++retired; + break; + default: + fail("Unknown AmendmentSupport", __FILE__, __LINE__); + } + } + + BEAST_EXPECT(supported + retired == supportedAmendments.size()); + BEAST_EXPECT( + allAmendments.size() - unsupported == + supportedAmendments.size()); } - BEAST_EXPECT( - down + obsolete == ripple::detail::numDownVotedAmendments()); - BEAST_EXPECT(up == ripple::detail::numUpVotedAmendments()); } void From 3f5e3212fe232883dce3e0ef4b379c04d4d8f9b3 Mon Sep 17 00:00:00 2001 From: todaymoon Date: Sat, 15 Jun 2024 04:36:59 +0900 Subject: [PATCH 07/82] chore: remove repeat words (#5041) --- src/ripple/app/paths/impl/Steps.h | 6 +++--- src/ripple/ledger/impl/ApplyView.cpp | 2 +- src/ripple/ledger/impl/PaymentSandbox.cpp | 2 +- src/test/app/NFToken_test.cpp | 2 +- src/test/consensus/Consensus_test.cpp | 2 +- src/test/csf/BasicNetwork.h | 2 +- src/test/rpc/DepositAuthorized_test.cpp | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ripple/app/paths/impl/Steps.h b/src/ripple/app/paths/impl/Steps.h index 033b9696f1d..2a4bfe310dd 100644 --- a/src/ripple/app/paths/impl/Steps.h +++ b/src/ripple/app/paths/impl/Steps.h @@ -89,7 +89,7 @@ class Step subject to liquidity limits @param sb view with the strand's state of balances and offers - @param afView view the the state of balances before the strand runs + @param afView view the state of balances before the strand runs this determines if an offer becomes unfunded or is found unfunded @param ofrsToRm offers found unfunded or in an error state are added to this collection @@ -107,7 +107,7 @@ class Step subject to liquidity limits @param sb view with the strand's state of balances and offers - @param afView view the the state of balances before the strand runs + @param afView view the state of balances before the strand runs this determines if an offer becomes unfunded or is found unfunded @param ofrsToRm offers found unfunded or in an error state are added to this collection @@ -256,7 +256,7 @@ class Step Check that the step can correctly execute in the forward direction @param sb view with the strands state of balances and offers - @param afView view the the state of balances before the strand runs + @param afView view the state of balances before the strand runs this determines if an offer becomes unfunded or is found unfunded @param in requested step input @return first element is true if step is valid, second element is out diff --git a/src/ripple/ledger/impl/ApplyView.cpp b/src/ripple/ledger/impl/ApplyView.cpp index eced521fb5d..53dc073c33d 100644 --- a/src/ripple/ledger/impl/ApplyView.cpp +++ b/src/ripple/ledger/impl/ApplyView.cpp @@ -313,7 +313,7 @@ ApplyView::dirRemove( prev->setFieldU64(sfIndexNext, rootPage); update(prev); - // And the root points to the the last page: + // And the root points to the last page: auto root = peek(keylet::page(directory, rootPage)); if (!root) LogicError("Directory chain: root link broken."); diff --git a/src/ripple/ledger/impl/PaymentSandbox.cpp b/src/ripple/ledger/impl/PaymentSandbox.cpp index bbe2c313491..45a57cd30d6 100644 --- a/src/ripple/ledger/impl/PaymentSandbox.cpp +++ b/src/ripple/ledger/impl/PaymentSandbox.cpp @@ -180,7 +180,7 @@ PaymentSandbox::balanceHook( algorithm remembers the original balance, and subtracts the debits. The post-switchover algorithm should be more numerically stable. Consider a large credit with a small initial balance. The pre-switchover algorithm - computes (B+C)-C (where B+C will the the amount passed in). The + computes (B+C)-C (where B+C will the amount passed in). The post-switchover algorithm returns B. When B and C differ by large magnitudes, (B+C)-C may not equal B. */ diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index 8740b521132..9a5ace19b1e 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -6306,7 +6306,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite } // When an account mints and burns a batch of NFTokens using tickets, - // see if the the account can be deleted. + // see if the account can be deleted. { Env env{*this, features}; diff --git a/src/test/consensus/Consensus_test.cpp b/src/test/consensus/Consensus_test.cpp index 5c7dc2626fe..1ef1a718d3c 100644 --- a/src/test/consensus/Consensus_test.cpp +++ b/src/test/consensus/Consensus_test.cpp @@ -806,7 +806,7 @@ class Consensus_test : public beast::unit_test::suite on(csf::PeerID who, csf::SimTime, csf::FullyValidateLedger const& e) { using namespace std::chrono; - // As soon as the the fastC node fully validates C, disconnect + // As soon as the fastC node fully validates C, disconnect // ALL c nodes from the network. The fast C node needs to disconnect // as well to prevent it from relaying the validations it did see if (who == groupCfast[0]->id && diff --git a/src/test/csf/BasicNetwork.h b/src/test/csf/BasicNetwork.h index 3ce159a2333..a70ee6a3613 100644 --- a/src/test/csf/BasicNetwork.h +++ b/src/test/csf/BasicNetwork.h @@ -51,7 +51,7 @@ namespace csf { at either end of the connection will not be delivered. When creating the Peer set, the caller needs to provide a - Scheduler object for managing the the timing and delivery + Scheduler object for managing the timing and delivery of messages. After constructing the network, and establishing connections, the caller uses the scheduler's step_* functions to drive messages through the network. diff --git a/src/test/rpc/DepositAuthorized_test.cpp b/src/test/rpc/DepositAuthorized_test.cpp index 42b871e31e5..128d91f739d 100644 --- a/src/test/rpc/DepositAuthorized_test.cpp +++ b/src/test/rpc/DepositAuthorized_test.cpp @@ -128,7 +128,7 @@ class DepositAuthorized_test : public beast::unit_test::suite depositAuthArgs(carol, becky).toStyledString()), false); - // becky clears the the DepositAuth flag so carol becomes authorized. + // becky clears the DepositAuth flag so carol becomes authorized. env(fclear(becky, asfDepositAuth)); env.close(); From 9f7c619e4fbbb0e110dc3fa6e9d13dad74b5830f Mon Sep 17 00:00:00 2001 From: tequ Date: Sat, 15 Jun 2024 01:32:25 +0200 Subject: [PATCH 08/82] XLS-52d: NFTokenMintOffer (#4845) --- src/ripple/app/tx/impl/NFTokenCreateOffer.cpp | 261 ++-------- src/ripple/app/tx/impl/NFTokenMint.cpp | 98 +++- .../app/tx/impl/details/NFTokenUtils.cpp | 247 +++++++++ src/ripple/app/tx/impl/details/NFTokenUtils.h | 41 ++ src/ripple/protocol/Feature.h | 3 +- src/ripple/protocol/impl/Feature.cpp | 1 + src/ripple/protocol/impl/NFTokenOfferID.cpp | 3 +- src/ripple/protocol/impl/TxFormats.cpp | 3 + src/test/app/NFToken_test.cpp | 490 +++++++++++++++++- src/test/jtx/impl/token.cpp | 6 + src/test/jtx/token.h | 15 + 11 files changed, 927 insertions(+), 241 deletions(-) diff --git a/src/ripple/app/tx/impl/NFTokenCreateOffer.cpp b/src/ripple/app/tx/impl/NFTokenCreateOffer.cpp index 22eca2dffdd..e1a0e04aa52 100644 --- a/src/ripple/app/tx/impl/NFTokenCreateOffer.cpp +++ b/src/ripple/app/tx/impl/NFTokenCreateOffer.cpp @@ -37,65 +37,24 @@ NFTokenCreateOffer::preflight(PreflightContext const& ctx) return ret; auto const txFlags = ctx.tx.getFlags(); - bool const isSellOffer = txFlags & tfSellNFToken; if (txFlags & tfNFTokenCreateOfferMask) return temINVALID_FLAG; - auto const account = ctx.tx[sfAccount]; auto const nftFlags = nft::getFlags(ctx.tx[sfNFTokenID]); - { - STAmount const amount = ctx.tx[sfAmount]; - - if (amount.negative() && ctx.rules.enabled(fixNFTokenNegOffer)) - // An offer for a negative amount makes no sense. - return temBAD_AMOUNT; - - if (!isXRP(amount)) - { - if (nftFlags & nft::flagOnlyXRP) - return temBAD_AMOUNT; - - if (!amount) - return temBAD_AMOUNT; - } - - // If this is an offer to buy, you must offer something; if it's an - // offer to sell, you can ask for nothing. - if (!isSellOffer && !amount) - return temBAD_AMOUNT; - } - - if (auto exp = ctx.tx[~sfExpiration]; exp == 0) - return temBAD_EXPIRATION; - - auto const owner = ctx.tx[~sfOwner]; - - // The 'Owner' field must be present when offering to buy, but can't - // be present when selling (it's implicit): - if (owner.has_value() == isSellOffer) - return temMALFORMED; - - if (owner && owner == account) - return temMALFORMED; - - if (auto dest = ctx.tx[~sfDestination]) - { - // Some folks think it makes sense for a buy offer to specify a - // specific broker using the Destination field. This change doesn't - // deserve it's own amendment, so we're piggy-backing on - // fixNFTokenNegOffer. - // - // Prior to fixNFTokenNegOffer any use of the Destination field on - // a buy offer was malformed. - if (!isSellOffer && !ctx.rules.enabled(fixNFTokenNegOffer)) - return temMALFORMED; - - // The destination can't be the account executing the transaction. - if (dest == account) - return temMALFORMED; - } + // Use implementation shared with NFTokenMint + if (NotTEC notTec = nft::tokenOfferCreatePreflight( + ctx.tx[sfAccount], + ctx.tx[sfAmount], + ctx.tx[~sfDestination], + ctx.tx[~sfExpiration], + nftFlags, + ctx.rules, + ctx.tx[~sfOwner], + txFlags); + !isTesSuccess(notTec)) + return notTec; return preflight2(ctx); } @@ -106,182 +65,44 @@ NFTokenCreateOffer::preclaim(PreclaimContext const& ctx) if (hasExpired(ctx.view, ctx.tx[~sfExpiration])) return tecEXPIRED; - auto const nftokenID = ctx.tx[sfNFTokenID]; - bool const isSellOffer = ctx.tx.isFlag(tfSellNFToken); + uint256 const nftokenID = ctx.tx[sfNFTokenID]; + std::uint32_t const txFlags = {ctx.tx.getFlags()}; if (!nft::findToken( - ctx.view, ctx.tx[isSellOffer ? sfAccount : sfOwner], nftokenID)) - return tecNO_ENTRY; - - auto const nftFlags = nft::getFlags(nftokenID); - auto const issuer = nft::getIssuer(nftokenID); - auto const amount = ctx.tx[sfAmount]; - - if (!(nftFlags & nft::flagCreateTrustLines) && !amount.native() && - nft::getTransferFee(nftokenID)) - { - if (!ctx.view.exists(keylet::account(issuer))) - return tecNO_ISSUER; - - if (!ctx.view.exists(keylet::line(issuer, amount.issue()))) - return tecNO_LINE; - - if (isFrozen( - ctx.view, issuer, amount.getCurrency(), amount.getIssuer())) - return tecFROZEN; - } - - if (issuer != ctx.tx[sfAccount] && !(nftFlags & nft::flagTransferable)) - { - auto const root = ctx.view.read(keylet::account(issuer)); - assert(root); - - if (auto minter = (*root)[~sfNFTokenMinter]; - minter != ctx.tx[sfAccount]) - return tefNFTOKEN_IS_NOT_TRANSFERABLE; - } - - if (isFrozen( ctx.view, - ctx.tx[sfAccount], - amount.getCurrency(), - amount.getIssuer())) - return tecFROZEN; - - // If this is an offer to buy the token, the account must have the - // needed funds at hand; but note that funds aren't reserved and the - // offer may later become unfunded. - if (!isSellOffer) - { - // After this amendment, we allow an IOU issuer to make a buy offer - // using their own currency. - if (ctx.view.rules().enabled(fixNonFungibleTokensV1_2)) - { - if (accountFunds( - ctx.view, - ctx.tx[sfAccount], - amount, - FreezeHandling::fhZERO_IF_FROZEN, - ctx.j) - .signum() <= 0) - return tecUNFUNDED_OFFER; - } - else if ( - accountHolds( - ctx.view, - ctx.tx[sfAccount], - amount.getCurrency(), - amount.getIssuer(), - FreezeHandling::fhZERO_IF_FROZEN, - ctx.j) - .signum() <= 0) - return tecUNFUNDED_OFFER; - } - - if (auto const destination = ctx.tx[~sfDestination]) - { - // If a destination is specified, the destination must already be in - // the ledger. - auto const sleDst = ctx.view.read(keylet::account(*destination)); - - if (!sleDst) - return tecNO_DST; - - // check if the destination has disallowed incoming offers - if (ctx.view.rules().enabled(featureDisallowIncoming)) - { - // flag cannot be set unless amendment is enabled but - // out of an abundance of caution check anyway - - if (sleDst->getFlags() & lsfDisallowIncomingNFTokenOffer) - return tecNO_PERMISSION; - } - } - - if (auto const owner = ctx.tx[~sfOwner]) - { - // Check if the owner (buy offer) has disallowed incoming offers - if (ctx.view.rules().enabled(featureDisallowIncoming)) - { - auto const sleOwner = ctx.view.read(keylet::account(*owner)); - - // defensively check - // it should not be possible to specify owner that doesn't exist - if (!sleOwner) - return tecNO_TARGET; - - if (sleOwner->getFlags() & lsfDisallowIncomingNFTokenOffer) - return tecNO_PERMISSION; - } - } + ctx.tx[(txFlags & tfSellNFToken) ? sfAccount : sfOwner], + nftokenID)) + return tecNO_ENTRY; - return tesSUCCESS; + // Use implementation shared with NFTokenMint + return nft::tokenOfferCreatePreclaim( + ctx.view, + ctx.tx[sfAccount], + nft::getIssuer(nftokenID), + ctx.tx[sfAmount], + ctx.tx[~sfDestination], + nft::getFlags(nftokenID), + nft::getTransferFee(nftokenID), + ctx.j, + ctx.tx[~sfOwner], + txFlags); } TER NFTokenCreateOffer::doApply() { - if (auto const acct = view().read(keylet::account(ctx_.tx[sfAccount])); - mPriorBalance < view().fees().accountReserve((*acct)[sfOwnerCount] + 1)) - return tecINSUFFICIENT_RESERVE; - - auto const nftokenID = ctx_.tx[sfNFTokenID]; - - auto const offerID = - keylet::nftoffer(account_, ctx_.tx.getSeqProxy().value()); - - // Create the offer: - { - // Token offers are always added to the owner's owner directory: - auto const ownerNode = view().dirInsert( - keylet::ownerDir(account_), offerID, describeOwnerDir(account_)); - - if (!ownerNode) - return tecDIR_FULL; - - bool const isSellOffer = ctx_.tx.isFlag(tfSellNFToken); - - // Token offers are also added to the token's buy or sell offer - // directory - auto const offerNode = view().dirInsert( - isSellOffer ? keylet::nft_sells(nftokenID) - : keylet::nft_buys(nftokenID), - offerID, - [&nftokenID, isSellOffer](std::shared_ptr const& sle) { - (*sle)[sfFlags] = - isSellOffer ? lsfNFTokenSellOffers : lsfNFTokenBuyOffers; - (*sle)[sfNFTokenID] = nftokenID; - }); - - if (!offerNode) - return tecDIR_FULL; - - std::uint32_t sleFlags = 0; - - if (isSellOffer) - sleFlags |= lsfSellNFToken; - - auto offer = std::make_shared(offerID); - (*offer)[sfOwner] = account_; - (*offer)[sfNFTokenID] = nftokenID; - (*offer)[sfAmount] = ctx_.tx[sfAmount]; - (*offer)[sfFlags] = sleFlags; - (*offer)[sfOwnerNode] = *ownerNode; - (*offer)[sfNFTokenOfferNode] = *offerNode; - - if (auto const expiration = ctx_.tx[~sfExpiration]) - (*offer)[sfExpiration] = *expiration; - - if (auto const destination = ctx_.tx[~sfDestination]) - (*offer)[sfDestination] = *destination; - - view().insert(offer); - } - - // Update owner count. - adjustOwnerCount(view(), view().peek(keylet::account(account_)), 1, j_); - - return tesSUCCESS; + // Use implementation shared with NFTokenMint + return nft::tokenOfferCreateApply( + view(), + ctx_.tx[sfAccount], + ctx_.tx[sfAmount], + ctx_.tx[~sfDestination], + ctx_.tx[~sfExpiration], + ctx_.tx.getSeqProxy(), + ctx_.tx[sfNFTokenID], + mPriorBalance, + j_, + ctx_.tx.getFlags()); } } // namespace ripple diff --git a/src/ripple/app/tx/impl/NFTokenMint.cpp b/src/ripple/app/tx/impl/NFTokenMint.cpp index c26fb1fb12a..daffd29ed31 100644 --- a/src/ripple/app/tx/impl/NFTokenMint.cpp +++ b/src/ripple/app/tx/impl/NFTokenMint.cpp @@ -31,12 +31,25 @@ namespace ripple { +static std::uint16_t +extractNFTokenFlagsFromTxFlags(std::uint32_t txFlags) +{ + return static_cast(txFlags & 0x0000FFFF); +} + NotTEC NFTokenMint::preflight(PreflightContext const& ctx) { if (!ctx.rules.enabled(featureNonFungibleTokensV1)) return temDISABLED; + bool const hasOfferFields = ctx.tx.isFieldPresent(sfAmount) || + ctx.tx.isFieldPresent(sfDestination) || + ctx.tx.isFieldPresent(sfExpiration); + + if (!ctx.rules.enabled(featureNFTokenMintOffer) && hasOfferFields) + return temDISABLED; + if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) return ret; @@ -80,6 +93,29 @@ NFTokenMint::preflight(PreflightContext const& ctx) return temMALFORMED; } + if (hasOfferFields) + { + // The Amount field must be present if either the Destination or + // Expiration fields are present. + if (!ctx.tx.isFieldPresent(sfAmount)) + return temMALFORMED; + + // Rely on the common code shared with NFTokenCreateOffer to + // do the validation. We pass tfSellNFToken as the transaction flags + // because a Mint is only allowed to create a sell offer. + if (NotTEC notTec = nft::tokenOfferCreatePreflight( + ctx.tx[sfAccount], + ctx.tx[sfAmount], + ctx.tx[~sfDestination], + ctx.tx[~sfExpiration], + extractNFTokenFlagsFromTxFlags(ctx.tx.getFlags()), + ctx.rules); + !isTesSuccess(notTec)) + { + return notTec; + } + } + return preflight2(ctx); } @@ -146,6 +182,27 @@ NFTokenMint::preclaim(PreclaimContext const& ctx) return tecNO_PERMISSION; } + if (ctx.tx.isFieldPresent(sfAmount)) + { + // The Amount field says create an offer for the minted token. + if (hasExpired(ctx.view, ctx.tx[~sfExpiration])) + return tecEXPIRED; + + // Rely on the common code shared with NFTokenCreateOffer to + // do the validation. We pass tfSellNFToken as the transaction flags + // because a Mint is only allowed to create a sell offer. + if (TER const ter = nft::tokenOfferCreatePreclaim( + ctx.view, + ctx.tx[sfAccount], + ctx.tx[~sfIssuer].value_or(ctx.tx[sfAccount]), + ctx.tx[sfAmount], + ctx.tx[~sfDestination], + extractNFTokenFlagsFromTxFlags(ctx.tx.getFlags()), + ctx.tx[~sfTransferFee].value_or(0), + ctx.j); + !isTesSuccess(ter)) + return ter; + } return tesSUCCESS; } @@ -238,18 +295,16 @@ NFTokenMint::doApply() // Should never happen. return tecINTERNAL; + auto const nftokenID = createNFTokenID( + extractNFTokenFlagsFromTxFlags(ctx_.tx.getFlags()), + ctx_.tx[~sfTransferFee].value_or(0), + issuer, + nft::toTaxon(ctx_.tx[sfNFTokenTaxon]), + tokenSeq.value()); + STObject newToken( - *nfTokenTemplate, - sfNFToken, - [this, &issuer, &tokenSeq](STObject& object) { - object.setFieldH256( - sfNFTokenID, - createNFTokenID( - static_cast(ctx_.tx.getFlags() & 0x0000FFFF), - ctx_.tx[~sfTransferFee].value_or(0), - issuer, - nft::toTaxon(ctx_.tx[sfNFTokenTaxon]), - tokenSeq.value())); + *nfTokenTemplate, sfNFToken, [this, &nftokenID](STObject& object) { + object.setFieldH256(sfNFTokenID, nftokenID); if (auto const uri = ctx_.tx[~sfURI]) object.setFieldVL(sfURI, *uri); @@ -260,10 +315,29 @@ NFTokenMint::doApply() ret != tesSUCCESS) return ret; + if (ctx_.tx.isFieldPresent(sfAmount)) + { + // Rely on the common code shared with NFTokenCreateOffer to create + // the offer. We pass tfSellNFToken as the transaction flags + // because a Mint is only allowed to create a sell offer. + if (TER const ter = nft::tokenOfferCreateApply( + view(), + ctx_.tx[sfAccount], + ctx_.tx[sfAmount], + ctx_.tx[~sfDestination], + ctx_.tx[~sfExpiration], + ctx_.tx.getSeqProxy(), + nftokenID, + mPriorBalance, + j_); + !isTesSuccess(ter)) + return ter; + } + // Only check the reserve if the owner count actually changed. This // allows NFTs to be added to the page (and burn fees) without // requiring the reserve to be met each time. The reserve is - // only managed when a new NFT page is added. + // only managed when a new NFT page or sell offer is added. if (auto const ownerCountAfter = view().read(keylet::account(account_))->getFieldU32(sfOwnerCount); ownerCountAfter > ownerCountBefore) diff --git a/src/ripple/app/tx/impl/details/NFTokenUtils.cpp b/src/ripple/app/tx/impl/details/NFTokenUtils.cpp index 09ff8f13caa..4acc00f956e 100644 --- a/src/ripple/app/tx/impl/details/NFTokenUtils.cpp +++ b/src/ripple/app/tx/impl/details/NFTokenUtils.cpp @@ -636,5 +636,252 @@ deleteTokenOffer(ApplyView& view, std::shared_ptr const& offer) return true; } +NotTEC +tokenOfferCreatePreflight( + AccountID const& acctID, + STAmount const& amount, + std::optional const& dest, + std::optional const& expiration, + std::uint16_t nftFlags, + Rules const& rules, + std::optional const& owner, + std::uint32_t txFlags) +{ + if (amount.negative() && rules.enabled(fixNFTokenNegOffer)) + // An offer for a negative amount makes no sense. + return temBAD_AMOUNT; + + if (!isXRP(amount)) + { + if (nftFlags & nft::flagOnlyXRP) + return temBAD_AMOUNT; + + if (!amount) + return temBAD_AMOUNT; + } + + // If this is an offer to buy, you must offer something; if it's an + // offer to sell, you can ask for nothing. + bool const isSellOffer = txFlags & tfSellNFToken; + if (!isSellOffer && !amount) + return temBAD_AMOUNT; + + if (expiration.has_value() && expiration.value() == 0) + return temBAD_EXPIRATION; + + // The 'Owner' field must be present when offering to buy, but can't + // be present when selling (it's implicit): + if (owner.has_value() == isSellOffer) + return temMALFORMED; + + if (owner && owner == acctID) + return temMALFORMED; + + if (dest) + { + // Some folks think it makes sense for a buy offer to specify a + // specific broker using the Destination field. This change doesn't + // deserve it's own amendment, so we're piggy-backing on + // fixNFTokenNegOffer. + // + // Prior to fixNFTokenNegOffer any use of the Destination field on + // a buy offer was malformed. + if (!isSellOffer && !rules.enabled(fixNFTokenNegOffer)) + return temMALFORMED; + + // The destination can't be the account executing the transaction. + if (dest == acctID) + return temMALFORMED; + } + return tesSUCCESS; +} + +TER +tokenOfferCreatePreclaim( + ReadView const& view, + AccountID const& acctID, + AccountID const& nftIssuer, + STAmount const& amount, + std::optional const& dest, + std::uint16_t nftFlags, + std::uint16_t xferFee, + beast::Journal j, + std::optional const& owner, + std::uint32_t txFlags) +{ + if (!(nftFlags & nft::flagCreateTrustLines) && !amount.native() && xferFee) + { + if (!view.exists(keylet::account(nftIssuer))) + return tecNO_ISSUER; + + // If the IOU issuer and the NFToken issuer are the same, then that + // issuer does not need a trust line to accept their fee. + if (view.rules().enabled(featureNFTokenMintOffer)) + { + if (nftIssuer != amount.getIssuer() && + !view.read(keylet::line(nftIssuer, amount.issue()))) + return tecNO_LINE; + } + else if (!view.exists(keylet::line(nftIssuer, amount.issue()))) + { + return tecNO_LINE; + } + + if (isFrozen(view, nftIssuer, amount.getCurrency(), amount.getIssuer())) + return tecFROZEN; + } + + if (nftIssuer != acctID && !(nftFlags & nft::flagTransferable)) + { + auto const root = view.read(keylet::account(nftIssuer)); + assert(root); + + if (auto minter = (*root)[~sfNFTokenMinter]; minter != acctID) + return tefNFTOKEN_IS_NOT_TRANSFERABLE; + } + + if (isFrozen(view, acctID, amount.getCurrency(), amount.getIssuer())) + return tecFROZEN; + + // If this is an offer to buy the token, the account must have the + // needed funds at hand; but note that funds aren't reserved and the + // offer may later become unfunded. + if ((txFlags & tfSellNFToken) == 0) + { + // After this amendment, we allow an IOU issuer to make a buy offer + // using their own currency. + if (view.rules().enabled(fixNonFungibleTokensV1_2)) + { + if (accountFunds( + view, acctID, amount, FreezeHandling::fhZERO_IF_FROZEN, j) + .signum() <= 0) + return tecUNFUNDED_OFFER; + } + else if ( + accountHolds( + view, + acctID, + amount.getCurrency(), + amount.getIssuer(), + FreezeHandling::fhZERO_IF_FROZEN, + j) + .signum() <= 0) + return tecUNFUNDED_OFFER; + } + + if (dest) + { + // If a destination is specified, the destination must already be in + // the ledger. + auto const sleDst = view.read(keylet::account(*dest)); + + if (!sleDst) + return tecNO_DST; + + // check if the destination has disallowed incoming offers + if (view.rules().enabled(featureDisallowIncoming)) + { + // flag cannot be set unless amendment is enabled but + // out of an abundance of caution check anyway + + if (sleDst->getFlags() & lsfDisallowIncomingNFTokenOffer) + return tecNO_PERMISSION; + } + } + + if (owner) + { + // Check if the owner (buy offer) has disallowed incoming offers + if (view.rules().enabled(featureDisallowIncoming)) + { + auto const sleOwner = view.read(keylet::account(*owner)); + + // defensively check + // it should not be possible to specify owner that doesn't exist + if (!sleOwner) + return tecNO_TARGET; + + if (sleOwner->getFlags() & lsfDisallowIncomingNFTokenOffer) + return tecNO_PERMISSION; + } + } + + return tesSUCCESS; +} + +TER +tokenOfferCreateApply( + ApplyView& view, + AccountID const& acctID, + STAmount const& amount, + std::optional const& dest, + std::optional const& expiration, + SeqProxy seqProxy, + uint256 const& nftokenID, + XRPAmount const& priorBalance, + beast::Journal j, + std::uint32_t txFlags) +{ + Keylet const acctKeylet = keylet::account(acctID); + if (auto const acct = view.read(acctKeylet); + priorBalance < view.fees().accountReserve((*acct)[sfOwnerCount] + 1)) + return tecINSUFFICIENT_RESERVE; + + auto const offerID = keylet::nftoffer(acctID, seqProxy.value()); + + // Create the offer: + { + // Token offers are always added to the owner's owner directory: + auto const ownerNode = view.dirInsert( + keylet::ownerDir(acctID), offerID, describeOwnerDir(acctID)); + + if (!ownerNode) + return tecDIR_FULL; + + bool const isSellOffer = txFlags & tfSellNFToken; + + // Token offers are also added to the token's buy or sell offer + // directory + auto const offerNode = view.dirInsert( + isSellOffer ? keylet::nft_sells(nftokenID) + : keylet::nft_buys(nftokenID), + offerID, + [&nftokenID, isSellOffer](std::shared_ptr const& sle) { + (*sle)[sfFlags] = + isSellOffer ? lsfNFTokenSellOffers : lsfNFTokenBuyOffers; + (*sle)[sfNFTokenID] = nftokenID; + }); + + if (!offerNode) + return tecDIR_FULL; + + std::uint32_t sleFlags = 0; + + if (isSellOffer) + sleFlags |= lsfSellNFToken; + + auto offer = std::make_shared(offerID); + (*offer)[sfOwner] = acctID; + (*offer)[sfNFTokenID] = nftokenID; + (*offer)[sfAmount] = amount; + (*offer)[sfFlags] = sleFlags; + (*offer)[sfOwnerNode] = *ownerNode; + (*offer)[sfNFTokenOfferNode] = *offerNode; + + if (expiration) + (*offer)[sfExpiration] = *expiration; + + if (dest) + (*offer)[sfDestination] = *dest; + + view.insert(offer); + } + + // Update owner count. + adjustOwnerCount(view, view.peek(acctKeylet), 1, j); + + return tesSUCCESS; +} + } // namespace nft } // namespace ripple diff --git a/src/ripple/app/tx/impl/details/NFTokenUtils.h b/src/ripple/app/tx/impl/details/NFTokenUtils.h index 5242bf38ff3..48ed3993357 100644 --- a/src/ripple/app/tx/impl/details/NFTokenUtils.h +++ b/src/ripple/app/tx/impl/details/NFTokenUtils.h @@ -20,6 +20,7 @@ #ifndef RIPPLE_TX_IMPL_DETAILS_NFTOKENUTILS_H_INCLUDED #define RIPPLE_TX_IMPL_DETAILS_NFTOKENUTILS_H_INCLUDED +#include #include #include #include @@ -97,6 +98,46 @@ deleteTokenOffer(ApplyView& view, std::shared_ptr const& offer); bool compareTokens(uint256 const& a, uint256 const& b); +/** Preflight checks shared by NFTokenCreateOffer and NFTokenMint */ +NotTEC +tokenOfferCreatePreflight( + AccountID const& acctID, + STAmount const& amount, + std::optional const& dest, + std::optional const& expiration, + std::uint16_t nftFlags, + Rules const& rules, + std::optional const& owner = std::nullopt, + std::uint32_t txFlags = lsfSellNFToken); + +/** Preclaim checks shared by NFTokenCreateOffer and NFTokenMint */ +TER +tokenOfferCreatePreclaim( + ReadView const& view, + AccountID const& acctID, + AccountID const& nftIssuer, + STAmount const& amount, + std::optional const& dest, + std::uint16_t nftFlags, + std::uint16_t xferFee, + beast::Journal j, + std::optional const& owner = std::nullopt, + std::uint32_t txFlags = lsfSellNFToken); + +/** doApply implementation shared by NFTokenCreateOffer and NFTokenMint */ +TER +tokenOfferCreateApply( + ApplyView& view, + AccountID const& acctID, + STAmount const& amount, + std::optional const& dest, + std::optional const& expiration, + SeqProxy seqProxy, + uint256 const& nftokenID, + XRPAmount const& priorBalance, + beast::Journal j, + std::uint32_t txFlags = lsfSellNFToken); + } // namespace nft } // namespace ripple diff --git a/src/ripple/protocol/Feature.h b/src/ripple/protocol/Feature.h index 78863908c25..2119a954ca9 100644 --- a/src/ripple/protocol/Feature.h +++ b/src/ripple/protocol/Feature.h @@ -80,7 +80,7 @@ namespace detail { // Feature.cpp. Because it's only used to reserve storage, and determine how // large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than // the actual number of amendments. A LogicError on startup will verify this. -static constexpr std::size_t numFeatures = 74; +static constexpr std::size_t numFeatures = 75; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated @@ -366,6 +366,7 @@ extern uint256 const fixEmptyDID; extern uint256 const fixXChainRewardRounding; extern uint256 const fixPreviousTxnID; extern uint256 const fixAMMv1_1; +extern uint256 const featureNFTokenMintOffer; extern uint256 const fixReducedOffersV2; } // namespace ripple diff --git a/src/ripple/protocol/impl/Feature.cpp b/src/ripple/protocol/impl/Feature.cpp index 6543498cef1..a1b73dbea8b 100644 --- a/src/ripple/protocol/impl/Feature.cpp +++ b/src/ripple/protocol/impl/Feature.cpp @@ -493,6 +493,7 @@ REGISTER_FIX (fixEmptyDID, Supported::yes, VoteBehavior::De REGISTER_FIX (fixXChainRewardRounding, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixPreviousTxnID, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixAMMv1_1, Supported::yes, VoteBehavior::DefaultNo); +REGISTER_FEATURE(NFTokenMintOffer, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixReducedOffersV2, Supported::yes, VoteBehavior::DefaultNo); // The following amendments are obsolete, but must remain supported diff --git a/src/ripple/protocol/impl/NFTokenOfferID.cpp b/src/ripple/protocol/impl/NFTokenOfferID.cpp index c9c3118cf2a..51408bfb21a 100644 --- a/src/ripple/protocol/impl/NFTokenOfferID.cpp +++ b/src/ripple/protocol/impl/NFTokenOfferID.cpp @@ -31,7 +31,8 @@ canHaveNFTokenOfferID( return false; TxType const tt = serializedTx->getTxnType(); - if (tt != ttNFTOKEN_CREATE_OFFER) + if (!(tt == ttNFTOKEN_MINT && serializedTx->isFieldPresent(sfAmount)) && + tt != ttNFTOKEN_CREATE_OFFER) return false; // if the transaction failed nothing could have been delivered. diff --git a/src/ripple/protocol/impl/TxFormats.cpp b/src/ripple/protocol/impl/TxFormats.cpp index d2bdd4f8aa7..324c0e30790 100644 --- a/src/ripple/protocol/impl/TxFormats.cpp +++ b/src/ripple/protocol/impl/TxFormats.cpp @@ -333,6 +333,9 @@ TxFormats::TxFormats() {sfTransferFee, soeOPTIONAL}, {sfIssuer, soeOPTIONAL}, {sfURI, soeOPTIONAL}, + {sfAmount, soeOPTIONAL}, + {sfDestination, soeOPTIONAL}, + {sfExpiration, soeOPTIONAL}, }, commonFields); diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index 9a5ace19b1e..c8531273917 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -3171,6 +3171,26 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite ter(tecNO_PERMISSION)); env.close(); } + + // minter mint and offer to buyer + if (features[featureNFTokenMintOffer]) + { + // enable flag + env(fset(buyer, asfDisallowIncomingNFTokenOffer)); + // a sell offer from the minter to the buyer should be rejected + env(token::mint(minter), + token::amount(drops(1)), + token::destination(buyer), + ter(tecNO_PERMISSION)); + env.close(); + + // disable flag + env(fclear(buyer, asfDisallowIncomingNFTokenOffer)); + env(token::mint(minter), + token::amount(drops(1)), + token::destination(buyer)); + env.close(); + } } void @@ -6566,6 +6586,281 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite } } + void + testFeatMintWithOffer(FeatureBitset features) + { + testcase("NFTokenMint with Create NFTokenOffer"); + + using namespace test::jtx; + + if (!features[featureNFTokenMintOffer]) + { + Env env{*this, features}; + Account const alice("alice"); + Account const buyer("buyer"); + + env.fund(XRP(10000), alice, buyer); + env.close(); + + env(token::mint(alice), + token::amount(XRP(10000)), + ter(temDISABLED)); + env.close(); + + env(token::mint(alice), + token::destination("buyer"), + ter(temDISABLED)); + env.close(); + + env(token::mint(alice), + token::expiration(lastClose(env) + 25), + ter(temDISABLED)); + env.close(); + + return; + } + + // The remaining tests assume featureNFTokenMintOffer is enabled. + { + Env env{*this, features}; + Account const alice("alice"); + Account const buyer{"buyer"}; + Account const gw("gw"); + Account const issuer("issuer"); + Account const minter("minter"); + Account const bob("bob"); + IOU const gwAUD(gw["AUD"]); + + env.fund(XRP(10000), alice, buyer, gw, issuer, minter); + env.close(); + + { + // Destination field specified but Amount field not specified + env(token::mint(alice), + token::destination(buyer), + ter(temMALFORMED)); + env.close(); + BEAST_EXPECT(ownerCount(env, alice) == 0); + + // Expiration field specified but Amount field not specified + env(token::mint(alice), + token::expiration(lastClose(env) + 25), + ter(temMALFORMED)); + env.close(); + BEAST_EXPECT(ownerCount(env, buyer) == 0); + } + + { + // The destination may not be the account submitting the + // transaction. + env(token::mint(alice), + token::amount(XRP(1000)), + token::destination(alice), + ter(temMALFORMED)); + env.close(); + BEAST_EXPECT(ownerCount(env, alice) == 0); + + // The destination must be an account already established in the + // ledger. + env(token::mint(alice), + token::amount(XRP(1000)), + token::destination(Account("demon")), + ter(tecNO_DST)); + env.close(); + BEAST_EXPECT(ownerCount(env, alice) == 0); + } + + { + // Set a bad expiration. + env(token::mint(alice), + token::amount(XRP(1000)), + token::expiration(0), + ter(temBAD_EXPIRATION)); + env.close(); + BEAST_EXPECT(ownerCount(env, alice) == 0); + + // The new NFTokenOffer may not have passed its expiration time. + env(token::mint(alice), + token::amount(XRP(1000)), + token::expiration(lastClose(env)), + ter(tecEXPIRED)); + env.close(); + BEAST_EXPECT(ownerCount(env, alice) == 0); + } + + { + // Set an invalid amount. + env(token::mint(alice), + token::amount(buyer["USD"](1)), + txflags(tfOnlyXRP), + ter(temBAD_AMOUNT)); + env(token::mint(alice), + token::amount(buyer["USD"](0)), + ter(temBAD_AMOUNT)); + env.close(); + BEAST_EXPECT(ownerCount(env, alice) == 0); + + // Issuer (alice) must have a trust line for the offered funds. + env(token::mint(alice), + token::amount(gwAUD(1000)), + txflags(tfTransferable), + token::xferFee(10), + ter(tecNO_LINE)); + env.close(); + BEAST_EXPECT(ownerCount(env, alice) == 0); + + // If the IOU issuer and the NFToken issuer are the same, + // then that issuer does not need a trust line to accept their + // fee. + env(token::mint(gw), + token::amount(gwAUD(1000)), + txflags(tfTransferable), + token::xferFee(10)); + env.close(); + + // Give alice the needed trust line, but freeze it. + env(trust(gw, alice["AUD"](999), tfSetFreeze)); + env.close(); + + // Issuer (alice) must have a trust line for the offered funds + // and the trust line may not be frozen. + env(token::mint(alice), + token::amount(gwAUD(1000)), + txflags(tfTransferable), + token::xferFee(10), + ter(tecFROZEN)); + env.close(); + BEAST_EXPECT(ownerCount(env, alice) == 0); + + // Seller (alice) must have a trust line may not be frozen. + env(token::mint(alice), + token::amount(gwAUD(1000)), + ter(tecFROZEN)); + env.close(); + BEAST_EXPECT(ownerCount(env, alice) == 0); + + // Unfreeze alice's trustline. + env(trust(gw, alice["AUD"](999), tfClearFreeze)); + env.close(); + } + + { + // check reserve + auto const acctReserve = + env.current()->fees().accountReserve(0); + auto const incReserve = env.current()->fees().increment; + + env.fund(acctReserve + incReserve, bob); + env.close(); + + // doesn't have reserve for 2 objects (NFTokenPage, Offer) + env(token::mint(bob), + token::amount(XRP(0)), + ter(tecINSUFFICIENT_RESERVE)); + env.close(); + + // have reserve for NFTokenPage, Offer + env(pay(env.master, bob, incReserve + drops(10))); + env.close(); + env(token::mint(bob), token::amount(XRP(0))); + env.close(); + + // doesn't have reserve for Offer + env(pay(env.master, bob, drops(10))); + env.close(); + env(token::mint(bob), + token::amount(XRP(0)), + ter(tecINSUFFICIENT_RESERVE)); + env.close(); + + // have reserve for Offer + env(pay(env.master, bob, incReserve + drops(10))); + env.close(); + env(token::mint(bob), token::amount(XRP(0))); + env.close(); + } + + // Amount field specified + BEAST_EXPECT(ownerCount(env, alice) == 0); + env(token::mint(alice), token::amount(XRP(10))); + BEAST_EXPECT(ownerCount(env, alice) == 2); + env.close(); + + // Amount field and Destination field, Expiration field specified + env(token::mint(alice), + token::amount(XRP(10)), + token::destination(buyer), + token::expiration(lastClose(env) + 25)); + env.close(); + + // With TransferFee field + env(trust(alice, gwAUD(1000))); + env.close(); + env(token::mint(alice), + token::amount(gwAUD(1)), + token::destination(buyer), + token::expiration(lastClose(env) + 25), + txflags(tfTransferable), + token::xferFee(10)); + env.close(); + + // Can be canceled by the issuer. + env(token::mint(alice), + token::amount(XRP(10)), + token::destination(buyer), + token::expiration(lastClose(env) + 25)); + uint256 const offerAliceSellsToBuyer = + keylet::nftoffer(alice, env.seq(alice)).key; + env(token::cancelOffer(alice, {offerAliceSellsToBuyer})); + env.close(); + + // Can be canceled by the buyer. + env(token::mint(buyer), + token::amount(XRP(10)), + token::destination(alice), + token::expiration(lastClose(env) + 25)); + uint256 const offerBuyerSellsToAlice = + keylet::nftoffer(buyer, env.seq(buyer)).key; + env(token::cancelOffer(alice, {offerBuyerSellsToAlice})); + env.close(); + + env(token::setMinter(issuer, minter)); + env.close(); + + // Minter will have offer not issuer + BEAST_EXPECT(ownerCount(env, minter) == 0); + BEAST_EXPECT(ownerCount(env, issuer) == 0); + env(token::mint(minter), + token::issuer(issuer), + token::amount(drops(1))); + env.close(); + BEAST_EXPECT(ownerCount(env, minter) == 2); + BEAST_EXPECT(ownerCount(env, issuer) == 0); + } + + // Test sell offers with a destination with and without + // fixNFTokenNegOffer. + for (auto const& tweakedFeatures : + {features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1, + features | fixNFTokenNegOffer}) + { + Env env{*this, tweakedFeatures}; + Account const alice("alice"); + + env.fund(XRP(1000000), alice); + + TER const offerCreateTER = tweakedFeatures[fixNFTokenNegOffer] + ? static_cast(temBAD_AMOUNT) + : static_cast(tesSUCCESS); + + // Make offers with negative amounts for the NFTs + env(token::mint(alice), + token::amount(XRP(-2)), + ter(offerCreateTER)); + env.close(); + } + } + void testTxJsonMetaFields(FeatureBitset features) { @@ -6796,6 +7091,15 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); verifyNFTokenIDsInCancelOffer({nftId}); } + + if (features[featureNFTokenMintOffer]) + { + uint256 const aliceMintWithOfferIndex1 = + keylet::nftoffer(alice, env.seq(alice)).key; + env(token::mint(alice), token::amount(XRP(0))); + env.close(); + verifyNFTokenOfferID(aliceMintWithOfferIndex1); + } } void @@ -7112,6 +7416,164 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite } } + void + testNFTIssuerIsIOUIssuer(FeatureBitset features) + { + testcase("Test fix NFT issuer is IOU issuer"); + + using namespace test::jtx; + + Account const issuer{"issuer"}; + Account const becky{"becky"}; + Account const cheri{"cheri"}; + IOU const isISU(issuer["ISU"]); + + // This test case covers issue... + // https://github.com/XRPLF/rippled/issues/4941 + // + // If an NFToken has a transfer fee then, when an offer is accepted, + // a portion of the sale price goes to the issuer. + // + // It is possible for an issuer to issue both an IOU (for remittances) + // and NFTokens. If the issuer's IOU is used to pay for the transfer + // of one of the issuer's NFTokens, then paying the fee for that + // transfer will fail with a tecNO_LINE. + // + // The problem occurs because the NFT code looks for a trust line to + // pay the transfer fee. However the issuer of an IOU does not need + // a trust line to accept their own issuance and, in fact, is not + // allowed to have a trust line to themselves. + // + // This test looks at a situation where transfer of an NFToken is + // prevented by this bug: + // 1. Issuer issues an IOU (e.g, isISU). + // 2. Becky and Cheri get trust lines for, and acquire, some isISU. + // 3. Issuer mints NFToken with transfer fee. + // 4. Becky acquires the NFToken, paying with XRP. + // 5. Becky attempts to create an offer to sell the NFToken for + // isISU(100). The attempt fails with `tecNO_LINE`. + // + // The featureNFTokenMintOffer amendment addresses this oversight. + // + // We remove the fixRemoveNFTokenAutoTrustLine amendment. Otherwise + // we can't create NFTokens with tfTrustLine enabled. + FeatureBitset const localFeatures = + features - fixRemoveNFTokenAutoTrustLine; + + Env env{*this, localFeatures}; + env.fund(XRP(1000), issuer, becky, cheri); + env.close(); + + // Set trust lines so becky and cheri can use isISU. + env(trust(becky, isISU(1000))); + env(trust(cheri, isISU(1000))); + env.close(); + env(pay(issuer, cheri, isISU(500))); + env.close(); + + // issuer creates two NFTs: one with and one without AutoTrustLine. + std::uint16_t xferFee = 5000; // 5% + uint256 const nftAutoTrustID{token::getNextID( + env, issuer, 0u, tfTransferable | tfTrustLine, xferFee)}; + env(token::mint(issuer, 0u), + token::xferFee(xferFee), + txflags(tfTransferable | tfTrustLine)); + env.close(); + + uint256 const nftNoAutoTrustID{ + token::getNextID(env, issuer, 0u, tfTransferable, xferFee)}; + env(token::mint(issuer, 0u), + token::xferFee(xferFee), + txflags(tfTransferable)); + env.close(); + + // becky buys the nfts for 1 drop each. + { + uint256 const beckyBuyOfferIndex1 = + keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftAutoTrustID, drops(1)), + token::owner(issuer)); + + uint256 const beckyBuyOfferIndex2 = + keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftNoAutoTrustID, drops(1)), + token::owner(issuer)); + + env.close(); + env(token::acceptBuyOffer(issuer, beckyBuyOfferIndex1)); + env(token::acceptBuyOffer(issuer, beckyBuyOfferIndex2)); + env.close(); + } + + // Behavior from here down diverges significantly based on + // featureNFTokenMintOffer. + if (!localFeatures[featureNFTokenMintOffer]) + { + // Without featureNFTokenMintOffer becky simply can't + // create an offer for a non-tfTrustLine NFToken that would + // pay the transfer fee in issuer's own IOU. + env(token::createOffer(becky, nftNoAutoTrustID, isISU(100)), + txflags(tfSellNFToken), + ter(tecNO_LINE)); + env.close(); + + // And issuer can't create a trust line to themselves. + env(trust(issuer, isISU(1000)), ter(temDST_IS_SRC)); + env.close(); + + // However if the NFToken has the tfTrustLine flag set, + // then becky can create the offer. + uint256 const beckyAutoTrustOfferIndex = + keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftAutoTrustID, isISU(100)), + txflags(tfSellNFToken)); + env.close(); + + // And cheri can accept the offer. + env(token::acceptSellOffer(cheri, beckyAutoTrustOfferIndex)); + env.close(); + + // We verify that issuer got their transfer fee by seeing that + // ISU(5) has disappeared out of cheri's and becky's balances. + BEAST_EXPECT(env.balance(becky, isISU) == isISU(95)); + BEAST_EXPECT(env.balance(cheri, isISU) == isISU(400)); + } + else + { + // With featureNFTokenMintOffer things go better. + // becky creates offers to sell the nfts for ISU. + uint256 const beckyNoAutoTrustOfferIndex = + keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftNoAutoTrustID, isISU(100)), + txflags(tfSellNFToken)); + env.close(); + uint256 const beckyAutoTrustOfferIndex = + keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftAutoTrustID, isISU(100)), + txflags(tfSellNFToken)); + env.close(); + + // cheri accepts becky's offers. Behavior is uniform: + // issuer gets paid. + env(token::acceptSellOffer(cheri, beckyAutoTrustOfferIndex)); + env.close(); + + // We verify that issuer got their transfer fee by seeing that + // ISU(5) has disappeared out of cheri's and becky's balances. + BEAST_EXPECT(env.balance(becky, isISU) == isISU(95)); + BEAST_EXPECT(env.balance(cheri, isISU) == isISU(400)); + + env(token::acceptSellOffer(cheri, beckyNoAutoTrustOfferIndex)); + env.close(); + + // We verify that issuer got their transfer fee by seeing that + // an additional ISU(5) has disappeared out of cheri's and + // becky's balances. + BEAST_EXPECT(env.balance(becky, isISU) == isISU(190)); + BEAST_EXPECT(env.balance(cheri, isISU) == isISU(300)); + } + } + void testWithFeats(FeatureBitset features) { @@ -7144,8 +7606,10 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite testIOUWithTransferFee(features); testBrokeredSaleToSelf(features); testFixNFTokenRemint(features); + testFeatMintWithOffer(features); testTxJsonMetaFields(features); testFixNFTokenBuyerReserve(features); + testNFTIssuerIsIOUIssuer(features); } public: @@ -7156,15 +7620,17 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite static FeatureBitset const all{supported_amendments()}; static FeatureBitset const fixNFTDir{fixNFTokenDirV1}; - static std::array const feats{ + static std::array const feats{ all - fixNFTDir - fixNonFungibleTokensV1_2 - fixNFTokenRemint - - fixNFTokenReserve, + fixNFTokenReserve - featureNFTokenMintOffer, all - disallowIncoming - fixNonFungibleTokensV1_2 - - fixNFTokenRemint - fixNFTokenReserve, + fixNFTokenRemint - fixNFTokenReserve - featureNFTokenMintOffer, all - fixNonFungibleTokensV1_2 - fixNFTokenRemint - - fixNFTokenReserve, - all - fixNFTokenRemint - fixNFTokenReserve, - all - fixNFTokenReserve, + fixNFTokenReserve - featureNFTokenMintOffer, + all - fixNFTokenRemint - fixNFTokenReserve - + featureNFTokenMintOffer, + all - fixNFTokenReserve - featureNFTokenMintOffer, + all - featureNFTokenMintOffer, all}; if (BEAST_EXPECT(instance < feats.size())) @@ -7217,12 +7683,21 @@ class NFTokenWOTokenReserve_test : public NFTokenBaseUtil_test } }; +class NFTokenWOMintOffer_test : public NFTokenBaseUtil_test +{ + void + run() override + { + NFTokenBaseUtil_test::run(5); + } +}; + class NFTokenAllFeatures_test : public NFTokenBaseUtil_test { void run() override { - NFTokenBaseUtil_test::run(5, true); + NFTokenBaseUtil_test::run(6, true); } }; @@ -7231,6 +7706,7 @@ BEAST_DEFINE_TESTSUITE_PRIO(NFTokenDisallowIncoming, tx, ripple, 2); BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOfixV1, tx, ripple, 2); BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOTokenRemint, tx, ripple, 2); BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOTokenReserve, tx, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOMintOffer, tx, ripple, 2); BEAST_DEFINE_TESTSUITE_PRIO(NFTokenAllFeatures, tx, ripple, 2); } // namespace ripple diff --git a/src/test/jtx/impl/token.cpp b/src/test/jtx/impl/token.cpp index 6c5cae4147a..12b738ca42f 100644 --- a/src/test/jtx/impl/token.cpp +++ b/src/test/jtx/impl/token.cpp @@ -57,6 +57,12 @@ uri::operator()(Env& env, JTx& jt) const jt.jv[sfURI.jsonName] = uri_; } +void +amount::operator()(Env& env, JTx& jt) const +{ + jt.jv[sfAmount.jsonName] = amount_.getJson(JsonOptions::none); +} + uint256 getNextID( jtx::Env const& env, diff --git a/src/test/jtx/token.h b/src/test/jtx/token.h index 150ddfab0ea..957e499cefa 100644 --- a/src/test/jtx/token.h +++ b/src/test/jtx/token.h @@ -83,6 +83,21 @@ class uri operator()(Env&, JTx& jtx) const; }; +/** Sets the optional amount field on an NFTokenMint. */ +class amount +{ +private: + STAmount const amount_; + +public: + explicit amount(STAmount const amount) : amount_(amount) + { + } + + void + operator()(Env&, JTx& jtx) const; +}; + /** Get the next NFTokenID that will be issued. */ uint256 getNextID( From 06733ec21a73a856893920b94814c985492655f1 Mon Sep 17 00:00:00 2001 From: Elliot Lee Date: Mon, 17 Jun 2024 12:32:08 -0700 Subject: [PATCH 09/82] docs: explain how to find a clang-format patch generated by CI (#4521) --- CONTRIBUTING.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 75616eb6b4e..5355878fa79 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -119,6 +119,16 @@ this: You can format individual files in place by running `clang-format -i ...` from any directory within this project. +There is a Continuous Integration job that runs clang-format on pull requests. If the code doesn't comply, a patch file that corrects auto-fixable formatting issues is generated. + +To download the patch file: + +1. Next to `clang-format / check (pull_request) Failing after #s` -> click **Details** to open the details page. +2. Left menu -> click **Summary** +3. Scroll down to near the bottom-right under `Artifacts` -> click **clang-format.patch** +4. Download the zip file and extract it to your local git repository. Run `git apply [patch-file-name]`. +5. Commit and push. + You can install a pre-commit hook to automatically run `clang-format` before every commit: ``` pip3 install pre-commit From 825864032ae3d8a989ff070bf396bedfde48ccff Mon Sep 17 00:00:00 2001 From: Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com> Date: Mon, 17 Jun 2024 13:41:03 -0700 Subject: [PATCH 10/82] Replaces the usage of boost::string_view with std::string_view (#4509) --- BUILD.md | 14 +++++ src/ripple/app/misc/ValidatorList.h | 2 +- src/ripple/app/misc/impl/ValidatorList.cpp | 6 +- src/ripple/basics/StringUtilities.h | 4 +- src/ripple/basics/base64.h | 2 +- src/ripple/basics/impl/StringUtilities.cpp | 4 +- src/ripple/basics/impl/base64.cpp | 2 +- src/ripple/beast/core/LexicalCast.h | 61 +++++++++++++++----- src/ripple/json/Output.h | 1 + src/ripple/overlay/impl/Cluster.cpp | 5 +- src/ripple/overlay/impl/Handshake.cpp | 13 ++--- src/ripple/overlay/impl/OverlayImpl.cpp | 7 +-- src/ripple/overlay/impl/PeerImp.cpp | 10 ++-- src/ripple/resource/ResourceManager.h | 2 +- src/ripple/resource/impl/ResourceManager.cpp | 5 +- src/ripple/rpc/Context.h | 4 +- src/ripple/rpc/Role.h | 8 +-- src/ripple/rpc/ServerHandler.h | 4 +- src/ripple/rpc/handlers/Ping.cpp | 6 +- src/ripple/rpc/impl/Role.cpp | 33 +++++------ src/ripple/rpc/impl/ServerHandler.cpp | 10 ++-- src/ripple/rpc/impl/WSInfoSub.h | 4 +- src/test/app/NFTokenDir_test.cpp | 8 +-- src/test/jtx/TrustedPublisherServer.h | 6 +- 24 files changed, 131 insertions(+), 90 deletions(-) diff --git a/BUILD.md b/BUILD.md index 590a7129863..0b9ef40e61b 100644 --- a/BUILD.md +++ b/BUILD.md @@ -107,6 +107,20 @@ then you will need to choose the `libstdc++11` ABI: conan profile update settings.compiler.libcxx=libstdc++11 default ``` + +Ensure inter-operability between `boost::string_view` and `std::string_view` types: + +``` +conan profile update 'conf.tools.build:cxxflags+=["-DBOOST_BEAST_USE_STD_STRING_VIEW"]' default +conan profile update 'env.CXXFLAGS="-DBOOST_BEAST_USE_STD_STRING_VIEW"' default +``` + +If you have other flags in the `conf.tools.build` or `env.CXXFLAGS` sections, make sure to retain the existing flags and append the new ones. You can check them with: +``` +conan profile show default +``` + + **Windows** developers may need to use the x64 native build tools. An easy way to do that is to run the shortcut "x64 Native Tools Command Prompt" for the version of Visual Studio that you have installed. diff --git a/src/ripple/app/misc/ValidatorList.h b/src/ripple/app/misc/ValidatorList.h index 280818abd35..4d792b36b0f 100644 --- a/src/ripple/app/misc/ValidatorList.h +++ b/src/ripple/app/misc/ValidatorList.h @@ -633,7 +633,7 @@ class ValidatorList */ std::optional getAvailable( - boost::beast::string_view const& pubKey, + std::string_view pubKey, std::optional forceVersion = {}); /** Return the number of configured validator list sites. */ diff --git a/src/ripple/app/misc/impl/ValidatorList.cpp b/src/ripple/app/misc/impl/ValidatorList.cpp index ff5fbd90eac..13dcd7873db 100644 --- a/src/ripple/app/misc/impl/ValidatorList.cpp +++ b/src/ripple/app/misc/impl/ValidatorList.cpp @@ -34,7 +34,6 @@ #include #include -#include #include #include @@ -215,7 +214,8 @@ ValidatorList::load( return false; } - auto const id = parseBase58(TokenType::NodePublic, match[1]); + auto const id = + parseBase58(TokenType::NodePublic, match[1].str()); if (!id) { @@ -1707,7 +1707,7 @@ ValidatorList::for_each_available( std::optional ValidatorList::getAvailable( - boost::beast::string_view const& pubKey, + std::string_view pubKey, std::optional forceVersion /* = {} */) { std::shared_lock read_lock{mutex_}; diff --git a/src/ripple/basics/StringUtilities.h b/src/ripple/basics/StringUtilities.h index 8af81a37403..69314ce096e 100644 --- a/src/ripple/basics/StringUtilities.h +++ b/src/ripple/basics/StringUtilities.h @@ -110,7 +110,7 @@ strUnHex(std::string const& strSrc) } inline std::optional -strViewUnHex(boost::string_view const& strSrc) +strViewUnHex(std::string_view strSrc) { return strUnHex(strSrc.size(), strSrc.cbegin(), strSrc.cend()); } @@ -150,7 +150,7 @@ to_uint64(std::string const& s); doesn't check whether the TLD is valid. */ bool -isProperlyFormedTomlDomain(std::string const& domain); +isProperlyFormedTomlDomain(std::string_view domain); } // namespace ripple diff --git a/src/ripple/basics/base64.h b/src/ripple/basics/base64.h index 05a61133f83..515a7584e56 100644 --- a/src/ripple/basics/base64.h +++ b/src/ripple/basics/base64.h @@ -73,7 +73,7 @@ base64_encode(std::string const& s) } std::string -base64_decode(std::string const& data); +base64_decode(std::string_view data); } // namespace ripple diff --git a/src/ripple/basics/impl/StringUtilities.cpp b/src/ripple/basics/impl/StringUtilities.cpp index bebbe1ef80b..67344b48013 100644 --- a/src/ripple/basics/impl/StringUtilities.cpp +++ b/src/ripple/basics/impl/StringUtilities.cpp @@ -120,7 +120,7 @@ to_uint64(std::string const& s) } bool -isProperlyFormedTomlDomain(std::string const& domain) +isProperlyFormedTomlDomain(std::string_view domain) { // The domain must be between 4 and 128 characters long if (domain.size() < 4 || domain.size() > 128) @@ -143,7 +143,7 @@ isProperlyFormedTomlDomain(std::string const& domain) , boost::regex_constants::optimize); - return boost::regex_match(domain, re); + return boost::regex_match(domain.begin(), domain.end(), re); } } // namespace ripple diff --git a/src/ripple/basics/impl/base64.cpp b/src/ripple/basics/impl/base64.cpp index 39b615100e5..4291a99556b 100644 --- a/src/ripple/basics/impl/base64.cpp +++ b/src/ripple/basics/impl/base64.cpp @@ -242,7 +242,7 @@ base64_encode(std::uint8_t const* data, std::size_t len) } std::string -base64_decode(std::string const& data) +base64_decode(std::string_view data) { std::string dest; dest.resize(base64::decoded_size(data.size())); diff --git a/src/ripple/beast/core/LexicalCast.h b/src/ripple/beast/core/LexicalCast.h index f4c78341b91..e0fa24ca9f5 100644 --- a/src/ripple/beast/core/LexicalCast.h +++ b/src/ripple/beast/core/LexicalCast.h @@ -20,6 +20,7 @@ #ifndef BEAST_MODULE_CORE_TEXT_LEXICALCAST_H_INCLUDED #define BEAST_MODULE_CORE_TEXT_LEXICALCAST_H_INCLUDED +#include #include #include #include @@ -64,9 +65,9 @@ struct LexicalCast } }; -// Parse std::string to number -template -struct LexicalCast +// Parse a std::string_view into a number +template +struct LexicalCast { explicit LexicalCast() = default; @@ -78,7 +79,7 @@ struct LexicalCast std::enable_if_t< std::is_integral_v && !std::is_same_v, bool> - operator()(Integral& out, std::string const& in) const + operator()(Integral& out, std::string_view in) const { auto first = in.data(); auto last = in.data() + in.size(); @@ -92,20 +93,23 @@ struct LexicalCast } bool - operator()(bool& out, std::string in) const + operator()(bool& out, std::string_view in) const { + std::string result; + // Convert the input to lowercase - std::transform(in.begin(), in.end(), in.begin(), [](auto c) { - return std::tolower(static_cast(c)); - }); + std::transform( + in.begin(), in.end(), std::back_inserter(result), [](auto c) { + return std::tolower(static_cast(c)); + }); - if (in == "1" || in == "true") + if (result == "1" || result == "true") { out = true; return true; } - if (in == "0" || in == "false") + if (result == "0" || result == "false") { out = false; return true; @@ -114,9 +118,38 @@ struct LexicalCast return false; } }; - //------------------------------------------------------------------------------ +// Parse boost library's string_view to number or boolean value +// Note: As of Jan 2024, Boost contains three different types of string_view +// (boost::core::basic_string_view, boost::string_ref and +// boost::string_view). The below template specialization is included because +// it is used in the handshake.cpp file +template +struct LexicalCast> +{ + explicit LexicalCast() = default; + + bool + operator()(Out& out, boost::core::basic_string_view in) const + { + return LexicalCast()(out, in); + } +}; + +// Parse std::string to number or boolean value +template +struct LexicalCast +{ + explicit LexicalCast() = default; + + bool + operator()(Out& out, std::string in) const + { + return LexicalCast()(out, in); + } +}; + // Conversion from null terminated char const* template struct LexicalCast @@ -126,7 +159,8 @@ struct LexicalCast bool operator()(Out& out, char const* in) const { - return LexicalCast()(out, in); + assert(in); + return LexicalCast()(out, in); } }; @@ -140,7 +174,8 @@ struct LexicalCast bool operator()(Out& out, char* in) const { - return LexicalCast()(out, in); + assert(in); + return LexicalCast()(out, in); } }; diff --git a/src/ripple/json/Output.h b/src/ripple/json/Output.h index 74aaa65269d..96905c20ba9 100644 --- a/src/ripple/json/Output.h +++ b/src/ripple/json/Output.h @@ -22,6 +22,7 @@ #include #include +#include namespace Json { diff --git a/src/ripple/overlay/impl/Cluster.cpp b/src/ripple/overlay/impl/Cluster.cpp index 53ec13b7403..a7b1e44d4b7 100644 --- a/src/ripple/overlay/impl/Cluster.cpp +++ b/src/ripple/overlay/impl/Cluster.cpp @@ -17,7 +17,6 @@ */ //============================================================================== -#include #include #include #include @@ -27,7 +26,6 @@ #include #include #include -#include namespace ripple { @@ -113,7 +111,8 @@ Cluster::load(Section const& nodes) return false; } - auto const id = parseBase58(TokenType::NodePublic, match[1]); + auto const id = + parseBase58(TokenType::NodePublic, match[1].str()); if (!id) { diff --git a/src/ripple/overlay/impl/Handshake.cpp b/src/ripple/overlay/impl/Handshake.cpp index 8fe383e1d47..b655859dcbc 100644 --- a/src/ripple/overlay/impl/Handshake.cpp +++ b/src/ripple/overlay/impl/Handshake.cpp @@ -20,16 +20,12 @@ #include #include #include -#include #include #include #include #include - #include - #include -#include // VFALCO Shouldn't we have to include the OpenSSL // headers or something for SSL_get_finished? @@ -46,8 +42,8 @@ getFeatureValue( return {}; boost::smatch match; boost::regex rx(feature + "=([^;\\s]+)"); - std::string const value = header->value(); - if (boost::regex_search(value, match, rx)) + std::string const allFeatures(header->value()); + if (boost::regex_search(allFeatures, match, rx)) return {match[1]}; return {}; } @@ -243,7 +239,7 @@ verifyHandshake( { std::uint32_t nid; - if (!beast::lexicalCastChecked(nid, std::string(iter->value()))) + if (!beast::lexicalCastChecked(nid, iter->value())) throw std::runtime_error("Invalid peer network identifier"); if (networkID && nid != *networkID) @@ -252,8 +248,7 @@ verifyHandshake( if (auto const iter = headers.find("Network-Time"); iter != headers.end()) { - auto const netTime = - [str = std::string(iter->value())]() -> TimeKeeper::time_point { + auto const netTime = [str = iter->value()]() -> TimeKeeper::time_point { TimeKeeper::duration::rep val; if (beast::lexicalCastChecked(val, str)) diff --git a/src/ripple/overlay/impl/OverlayImpl.cpp b/src/ripple/overlay/impl/OverlayImpl.cpp index 1bb9a381edd..7e60b2c120c 100644 --- a/src/ripple/overlay/impl/OverlayImpl.cpp +++ b/src/ripple/overlay/impl/OverlayImpl.cpp @@ -39,7 +39,6 @@ #include #include -#include namespace ripple { @@ -826,7 +825,7 @@ OverlayImpl::getOverlayInfo() auto version{sp->getVersion()}; if (!version.empty()) // Could move here if Json::value supported moving from strings - pv[jss::version] = version; + pv[jss::version] = std::string{version}; } std::uint32_t minSeq, maxSeq; @@ -994,9 +993,9 @@ OverlayImpl::processValidatorList( return true; }; - auto key = req.target().substr(prefix.size()); + std::string_view key = req.target().substr(prefix.size()); - if (auto slash = key.find('/'); slash != boost::string_view::npos) + if (auto slash = key.find('/'); slash != std::string_view::npos) { auto verString = key.substr(0, slash); if (!boost::conversion::try_lexical_convert(verString, version)) diff --git a/src/ripple/overlay/impl/PeerImp.cpp b/src/ripple/overlay/impl/PeerImp.cpp index f93c9f135ad..4cd3a89452d 100644 --- a/src/ripple/overlay/impl/PeerImp.cpp +++ b/src/ripple/overlay/impl/PeerImp.cpp @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -41,7 +40,6 @@ #include #include -#include #include #include @@ -160,7 +158,7 @@ PeerImp::run() return post(strand_, std::bind(&PeerImp::run, shared_from_this())); auto parseLedgerHash = - [](std::string const& value) -> std::optional { + [](std::string_view value) -> std::optional { if (uint256 ret; ret.parseHex(value)) return ret; @@ -397,15 +395,15 @@ PeerImp::json() } if (auto const d = domain(); !d.empty()) - ret[jss::server_domain] = domain(); + ret[jss::server_domain] = std::string{d}; if (auto const nid = headers_["Network-ID"]; !nid.empty()) - ret[jss::network_id] = std::string(nid); + ret[jss::network_id] = std::string{nid}; ret[jss::load] = usage_.balance(); if (auto const version = getVersion(); !version.empty()) - ret[jss::version] = version; + ret[jss::version] = std::string{version}; ret[jss::protocol] = to_string(protocol_); diff --git a/src/ripple/resource/ResourceManager.h b/src/ripple/resource/ResourceManager.h index 7471a37ab35..10e20a82f06 100644 --- a/src/ripple/resource/ResourceManager.h +++ b/src/ripple/resource/ResourceManager.h @@ -49,7 +49,7 @@ class Manager : public beast::PropertyStream::Source newInboundEndpoint( beast::IP::Endpoint const& address, bool const proxy, - boost::string_view const& forwardedFor) = 0; + std::string_view forwardedFor) = 0; /** Create a new endpoint keyed by outbound IP address and port. */ virtual Consumer diff --git a/src/ripple/resource/impl/ResourceManager.cpp b/src/ripple/resource/impl/ResourceManager.cpp index 1a7e74ec1f8..ae4eaac23fd 100644 --- a/src/ripple/resource/impl/ResourceManager.cpp +++ b/src/ripple/resource/impl/ResourceManager.cpp @@ -77,14 +77,13 @@ class ManagerImp : public Manager newInboundEndpoint( beast::IP::Endpoint const& address, bool const proxy, - boost::string_view const& forwardedFor) override + std::string_view forwardedFor) override { if (!proxy) return newInboundEndpoint(address); boost::system::error_code ec; - auto const proxiedIp = - boost::asio::ip::make_address(forwardedFor.to_string(), ec); + auto const proxiedIp = boost::asio::ip::make_address(forwardedFor, ec); if (ec) { journal_.warn() diff --git a/src/ripple/rpc/Context.h b/src/ripple/rpc/Context.h index 7a22ed9fe0c..ea18efcec6c 100644 --- a/src/ripple/rpc/Context.h +++ b/src/ripple/rpc/Context.h @@ -57,8 +57,8 @@ struct JsonContext : public Context */ struct Headers { - boost::string_view user; - boost::string_view forwardedFor; + std::string_view user; + std::string_view forwardedFor; }; Json::Value params; diff --git a/src/ripple/rpc/Role.h b/src/ripple/rpc/Role.h index c4f1f730c02..1ce76f90d6d 100644 --- a/src/ripple/rpc/Role.h +++ b/src/ripple/rpc/Role.h @@ -56,15 +56,15 @@ requestRole( Port const& port, Json::Value const& params, beast::IP::Endpoint const& remoteIp, - boost::string_view const& user); + std::string_view user); Resource::Consumer requestInboundEndpoint( Resource::Manager& manager, beast::IP::Endpoint const& remoteAddress, Role const& role, - boost::string_view const& user, - boost::string_view const& forwardedFor); + std::string_view user, + std::string_view forwardedFor); /** * Check if the role entitles the user to unlimited resources. @@ -85,7 +85,7 @@ ipAllowed( std::vector const& nets4, std::vector const& nets6); -boost::string_view +std::string_view forwardedFor(http_request_type const& request); } // namespace ripple diff --git a/src/ripple/rpc/ServerHandler.h b/src/ripple/rpc/ServerHandler.h index 07fb61362a0..7e9e427cfdb 100644 --- a/src/ripple/rpc/ServerHandler.h +++ b/src/ripple/rpc/ServerHandler.h @@ -208,8 +208,8 @@ class ServerHandler beast::IP::Endpoint const& remoteIPAddress, Output&&, std::shared_ptr coro, - boost::string_view forwardedFor, - boost::string_view user); + std::string_view forwardedFor, + std::string_view user); Handoff statusResponse(http_request_type const& request) const; diff --git a/src/ripple/rpc/handlers/Ping.cpp b/src/ripple/rpc/handlers/Ping.cpp index 7bd91d8edc1..efe9063a1e2 100644 --- a/src/ripple/rpc/handlers/Ping.cpp +++ b/src/ripple/rpc/handlers/Ping.cpp @@ -39,13 +39,13 @@ doPing(RPC::JsonContext& context) break; case Role::IDENTIFIED: ret[jss::role] = "identified"; - ret[jss::username] = context.headers.user.to_string(); + ret[jss::username] = std::string{context.headers.user}; if (context.headers.forwardedFor.size()) - ret[jss::ip] = context.headers.forwardedFor.to_string(); + ret[jss::ip] = std::string{context.headers.forwardedFor}; break; case Role::PROXY: ret[jss::role] = "proxied"; - ret[jss::ip] = context.headers.forwardedFor.to_string(); + ret[jss::ip] = std::string{context.headers.forwardedFor}; default:; } diff --git a/src/ripple/rpc/impl/Role.cpp b/src/ripple/rpc/impl/Role.cpp index 1807ecc20f6..54f6d6e2575 100644 --- a/src/ripple/rpc/impl/Role.cpp +++ b/src/ripple/rpc/impl/Role.cpp @@ -18,9 +18,7 @@ //============================================================================== #include -#include #include -#include #include #include #include @@ -96,7 +94,7 @@ requestRole( Port const& port, Json::Value const& params, beast::IP::Endpoint const& remoteIp, - boost::string_view const& user) + std::string_view user) { if (isAdmin(port, params, remoteIp.address())) return Role::ADMIN; @@ -142,8 +140,8 @@ requestInboundEndpoint( Resource::Manager& manager, beast::IP::Endpoint const& remoteAddress, Role const& role, - boost::string_view const& user, - boost::string_view const& forwardedFor) + std::string_view user, + std::string_view forwardedFor) { if (isUnlimited(role)) return manager.newUnlimitedEndpoint(remoteAddress); @@ -152,18 +150,18 @@ requestInboundEndpoint( remoteAddress, role == Role::PROXY, forwardedFor); } -static boost::string_view -extractIpAddrFromField(boost::string_view field) +static std::string_view +extractIpAddrFromField(std::string_view field) { // Lambda to trim leading and trailing spaces on the field. - auto trim = [](boost::string_view str) -> boost::string_view { - boost::string_view ret = str; + auto trim = [](std::string_view str) -> std::string_view { + std::string_view ret = str; // Only do the work if there's at least one leading space. if (!ret.empty() && ret.front() == ' ') { std::size_t const firstNonSpace = ret.find_first_not_of(' '); - if (firstNonSpace == boost::string_view::npos) + if (firstNonSpace == std::string_view::npos) // We know there's at least one leading space. So if we got // npos, then it must be all spaces. Return empty string_view. return {}; @@ -178,7 +176,7 @@ extractIpAddrFromField(boost::string_view field) c == ' ' || c == '\r' || c == '\n') { std::size_t const lastNonSpace = ret.find_last_not_of(" \r\n"); - if (lastNonSpace == boost::string_view::npos) + if (lastNonSpace == std::string_view::npos) // We know there's at least one leading space. So if we // got npos, then it must be all spaces. return {}; @@ -189,7 +187,7 @@ extractIpAddrFromField(boost::string_view field) return ret; }; - boost::string_view ret = trim(field); + std::string_view ret = trim(field); if (ret.empty()) return {}; @@ -251,13 +249,13 @@ extractIpAddrFromField(boost::string_view field) // If there's a port appended to the IP address, strip that by // terminating at the colon. - if (std::size_t colon = ret.find(':'); colon != boost::string_view::npos) + if (std::size_t colon = ret.find(':'); colon != std::string_view::npos) ret = ret.substr(0, colon); return ret; } -boost::string_view +std::string_view forwardedFor(http_request_type const& request) { // Look for the Forwarded field in the request. @@ -286,10 +284,9 @@ forwardedFor(http_request_type const& request) // We found a "for=". Scan for the end of the IP address. std::size_t const pos = [&found, &it]() { - std::size_t pos = - boost::string_view(found, it->value().end() - found) - .find_first_of(",;"); - if (pos != boost::string_view::npos) + std::size_t pos = std::string_view(found, it->value().end() - found) + .find_first_of(",;"); + if (pos != std::string_view::npos) return pos; return it->value().size() - forStr.size(); diff --git a/src/ripple/rpc/impl/ServerHandler.cpp b/src/ripple/rpc/impl/ServerHandler.cpp index d643bdb6331..700e1c64976 100644 --- a/src/ripple/rpc/impl/ServerHandler.cpp +++ b/src/ripple/rpc/impl/ServerHandler.cpp @@ -247,6 +247,8 @@ build_map(boost::beast::http::fields const& h) std::map c; for (auto const& e : h) { + // key cannot be a std::string_view because it needs to be used in + // map and along with iterators std::string key(e.name_string()); std::transform(key.begin(), key.end(), key.begin(), [](auto kc) { return std::tolower(static_cast(kc)); @@ -592,8 +594,8 @@ ServerHandler::processRequest( beast::IP::Endpoint const& remoteIPAddress, Output&& output, std::shared_ptr coro, - boost::string_view forwardedFor, - boost::string_view user) + std::string_view forwardedFor, + std::string_view user) { auto rpcJ = app_.journal("RPC"); @@ -847,8 +849,8 @@ ServerHandler::processRequest( */ if (role != Role::IDENTIFIED && role != Role::PROXY) { - forwardedFor.clear(); - user.clear(); + forwardedFor.remove_suffix(forwardedFor.size()); + user.remove_suffix(user.size()); } JLOG(m_journal.debug()) << "Query: " << strMethod << params; diff --git a/src/ripple/rpc/impl/WSInfoSub.h b/src/ripple/rpc/impl/WSInfoSub.h index 267c8f98f24..31f6353b994 100644 --- a/src/ripple/rpc/impl/WSInfoSub.h +++ b/src/ripple/rpc/impl/WSInfoSub.h @@ -55,13 +55,13 @@ class WSInfoSub : public InfoSub } } - boost::string_view + std::string_view user() const { return user_; } - boost::string_view + std::string_view forwarded_for() const { return fwdfor_; diff --git a/src/test/app/NFTokenDir_test.cpp b/src/test/app/NFTokenDir_test.cpp index e9addfa83f7..8e6a9fe5209 100644 --- a/src/test/app/NFTokenDir_test.cpp +++ b/src/test/app/NFTokenDir_test.cpp @@ -185,7 +185,7 @@ class NFTokenDir_test : public beast::unit_test::suite // Create accounts for all of the seeds and fund those accounts. std::vector accounts; accounts.reserve(seeds.size()); - for (std::string_view const& seed : seeds) + for (std::string_view seed : seeds) { Account const& account = accounts.emplace_back( Account::base58Seed, std::string(seed)); @@ -409,7 +409,7 @@ class NFTokenDir_test : public beast::unit_test::suite // Create accounts for all of the seeds and fund those accounts. std::vector accounts; accounts.reserve(seeds.size()); - for (std::string_view const& seed : seeds) + for (std::string_view seed : seeds) { Account const& account = accounts.emplace_back( Account::base58Seed, std::string(seed)); @@ -659,7 +659,7 @@ class NFTokenDir_test : public beast::unit_test::suite // Create accounts for all of the seeds and fund those accounts. std::vector accounts; accounts.reserve(seeds.size()); - for (std::string_view const& seed : seeds) + for (std::string_view seed : seeds) { Account const& account = accounts.emplace_back(Account::base58Seed, std::string(seed)); @@ -840,7 +840,7 @@ class NFTokenDir_test : public beast::unit_test::suite // Create accounts for all of the seeds and fund those accounts. std::vector accounts; accounts.reserve(seeds.size()); - for (std::string_view const& seed : seeds) + for (std::string_view seed : seeds) { Account const& account = accounts.emplace_back(Account::base58Seed, std::string(seed)); diff --git a/src/test/jtx/TrustedPublisherServer.h b/src/test/jtx/TrustedPublisherServer.h index da7ea1c137a..db57b2d94c6 100644 --- a/src/test/jtx/TrustedPublisherServer.h +++ b/src/test/jtx/TrustedPublisherServer.h @@ -574,7 +574,7 @@ xbEQ+TUZ5jbJGSeBqNFKFeuOUQGJ46Io0jBSYd4rSmKUXkvElQwR+n7KF3jy1uAt if (ec) break; - std::string path = req.target(); + std::string_view const path = req.target(); res.insert("Server", "TrustedPublisherServer"); res.version(req.version()); res.keep_alive(req.keep_alive()); @@ -677,7 +677,9 @@ xbEQ+TUZ5jbJGSeBqNFKFeuOUQGJ46Io0jBSYd4rSmKUXkvElQwR+n7KF3jy1uAt // unknown request res.result(boost::beast::http::status::not_found); res.insert("Content-Type", "text/html"); - res.body() = "The file '" + path + "' was not found"; + res.body() = "The file '" + std::string(path) + + "' was not " + "found"; } if (prepare) From 223e6c7590f196b25a7e5767a26150ca64eab92c Mon Sep 17 00:00:00 2001 From: Scott Schurr Date: Mon, 17 Jun 2024 23:47:54 -0700 Subject: [PATCH 11/82] Add the fixEnforceNFTokenTrustline amendment: (#4946) Fix interactions between NFTokenOffers and trust lines. Since the NFTokenAcceptOffer does not check the trust line that the issuer receives as a transfer fee in the NFTokenAcceptOffer, if the issuer deletes the trust line after NFTokenCreateOffer, the trust line is created for the issuer by the NFTokenAcceptOffer. That's fixed. Resolves #4925. --- src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp | 22 +++ src/ripple/protocol/Feature.h | 3 +- src/ripple/protocol/impl/Feature.cpp | 1 + src/test/app/NFToken_test.cpp | 171 ++++++++++++++++++ src/test/app/Offer_test.cpp | 12 +- 5 files changed, 202 insertions(+), 7 deletions(-) diff --git a/src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp b/src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp index 3b6aaf60ea1..0b61799ac35 100644 --- a/src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp +++ b/src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp @@ -270,6 +270,28 @@ NFTokenAcceptOffer::preclaim(PreclaimContext const& ctx) } } + // Fix a bug where the transfer of an NFToken with a transfer fee could + // give the NFToken issuer an undesired trust line. + if (ctx.view.rules().enabled(fixEnforceNFTokenTrustline)) + { + std::shared_ptr const& offer = bo ? bo : so; + if (!offer) + // Should be caught in preflight. + return tecINTERNAL; + + uint256 const& tokenID = offer->at(sfNFTokenID); + STAmount const& amount = offer->at(sfAmount); + if (nft::getTransferFee(tokenID) != 0 && + (nft::getFlags(tokenID) & nft::flagCreateTrustLines) == 0 && + !amount.native()) + { + auto const issuer = nft::getIssuer(tokenID); + // Issuer doesn't need a trust line to accept their own currency. + if (issuer != amount.getIssuer() && + !ctx.view.read(keylet::line(issuer, amount.issue()))) + return tecNO_LINE; + } + } return tesSUCCESS; } diff --git a/src/ripple/protocol/Feature.h b/src/ripple/protocol/Feature.h index 2119a954ca9..e0864540cc5 100644 --- a/src/ripple/protocol/Feature.h +++ b/src/ripple/protocol/Feature.h @@ -80,7 +80,7 @@ namespace detail { // Feature.cpp. Because it's only used to reserve storage, and determine how // large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than // the actual number of amendments. A LogicError on startup will verify this. -static constexpr std::size_t numFeatures = 75; +static constexpr std::size_t numFeatures = 76; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated @@ -368,6 +368,7 @@ extern uint256 const fixPreviousTxnID; extern uint256 const fixAMMv1_1; extern uint256 const featureNFTokenMintOffer; extern uint256 const fixReducedOffersV2; +extern uint256 const fixEnforceNFTokenTrustline; } // namespace ripple diff --git a/src/ripple/protocol/impl/Feature.cpp b/src/ripple/protocol/impl/Feature.cpp index a1b73dbea8b..4434a7fbdc3 100644 --- a/src/ripple/protocol/impl/Feature.cpp +++ b/src/ripple/protocol/impl/Feature.cpp @@ -495,6 +495,7 @@ REGISTER_FIX (fixPreviousTxnID, Supported::yes, VoteBehavior::De REGISTER_FIX (fixAMMv1_1, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FEATURE(NFTokenMintOffer, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixReducedOffersV2, Supported::yes, VoteBehavior::DefaultNo); +REGISTER_FIX (fixEnforceNFTokenTrustline, Supported::yes, VoteBehavior::DefaultNo); // The following amendments are obsolete, but must remain supported // because they could potentially get enabled. diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index c8531273917..69432c85d17 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -7416,6 +7416,176 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite } } + void + testUnaskedForAutoTrustline(FeatureBitset features) + { + testcase("Test fix unasked for auto-trustline."); + + using namespace test::jtx; + + Account const issuer{"issuer"}; + Account const becky{"becky"}; + Account const cheri{"cheri"}; + Account const gw("gw"); + IOU const gwAUD(gw["AUD"]); + + // This test case covers issue... + // https://github.com/XRPLF/rippled/issues/4925 + // + // For an NFToken with a transfer fee, the issuer must be able to + // accept the transfer fee or else a transfer should fail. If the + // NFToken is transferred for a non-XRP asset, then the issuer must + // have a trustline to that asset to receive the fee. + // + // This test looks at a situation where issuer would get a trustline + // for the fee without the issuer's consent. Here are the steps: + // 1. Issuer has a trustline (i.e., USD) + // 2. Issuer mints NFToken with transfer fee. + // 3. Becky acquires the NFToken, paying with XRP. + // 4. Becky creates offer to sell NFToken for USD(100). + // 5. Issuer deletes trustline for USD. + // 6. Carol buys NFToken from Becky for USD(100). + // 7. The transfer fee from Carol's purchase re-establishes issuer's + // USD trustline. + // + // The fixEnforceNFTokenTrustline amendment addresses this oversight. + // + // We run this test case both with and without + // fixEnforceNFTokenTrustline enabled so we can see the change + // in behavior. + // + // In both cases we remove the fixRemoveNFTokenAutoTrustLine amendment. + // Otherwise we can't create NFTokens with tfTrustLine enabled. + FeatureBitset const localFeatures = + features - fixRemoveNFTokenAutoTrustLine; + for (FeatureBitset feats : + {localFeatures - fixEnforceNFTokenTrustline, + localFeatures | fixEnforceNFTokenTrustline}) + { + Env env{*this, feats}; + env.fund(XRP(1000), issuer, becky, cheri, gw); + env.close(); + + // Set trust lines so becky and cheri can use gw's currency. + env(trust(becky, gwAUD(1000))); + env(trust(cheri, gwAUD(1000))); + env.close(); + env(pay(gw, cheri, gwAUD(500))); + env.close(); + + // issuer creates two NFTs: one with and one without AutoTrustLine. + std::uint16_t xferFee = 5000; // 5% + uint256 const nftAutoTrustID{token::getNextID( + env, issuer, 0u, tfTransferable | tfTrustLine, xferFee)}; + env(token::mint(issuer, 0u), + token::xferFee(xferFee), + txflags(tfTransferable | tfTrustLine)); + env.close(); + + uint256 const nftNoAutoTrustID{ + token::getNextID(env, issuer, 0u, tfTransferable, xferFee)}; + env(token::mint(issuer, 0u), + token::xferFee(xferFee), + txflags(tfTransferable)); + env.close(); + + // becky buys the nfts for 1 drop each. + { + uint256 const beckyBuyOfferIndex1 = + keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftAutoTrustID, drops(1)), + token::owner(issuer)); + + uint256 const beckyBuyOfferIndex2 = + keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftNoAutoTrustID, drops(1)), + token::owner(issuer)); + + env.close(); + env(token::acceptBuyOffer(issuer, beckyBuyOfferIndex1)); + env(token::acceptBuyOffer(issuer, beckyBuyOfferIndex2)); + env.close(); + } + + // becky creates offers to sell the nfts for AUD. + uint256 const beckyAutoTrustOfferIndex = + keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftAutoTrustID, gwAUD(100)), + txflags(tfSellNFToken)); + env.close(); + + // Creating an offer for the NFToken without tfTrustLine fails + // because issuer does not have a trust line for AUD. + env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)), + txflags(tfSellNFToken), + ter(tecNO_LINE)); + env.close(); + + // issuer creates a trust line. Now the offer create for the + // NFToken without tfTrustLine succeeds. + BEAST_EXPECT(ownerCount(env, issuer) == 0); + env(trust(issuer, gwAUD(1000))); + env.close(); + BEAST_EXPECT(ownerCount(env, issuer) == 1); + + uint256 const beckyNoAutoTrustOfferIndex = + keylet::nftoffer(becky, env.seq(becky)).key; + env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)), + txflags(tfSellNFToken)); + env.close(); + + // Now that the offers are in place, issuer removes the trustline. + BEAST_EXPECT(ownerCount(env, issuer) == 1); + env(trust(issuer, gwAUD(0))); + env.close(); + BEAST_EXPECT(ownerCount(env, issuer) == 0); + + // cheri attempts to accept becky's offers. Behavior with the + // AutoTrustline NFT is uniform: issuer gets a new trust line. + env(token::acceptSellOffer(cheri, beckyAutoTrustOfferIndex)); + env.close(); + + // Here's evidence that issuer got the new AUD trust line. + BEAST_EXPECT(ownerCount(env, issuer) == 1); + BEAST_EXPECT(env.balance(issuer, gwAUD) == gwAUD(5)); + + // issuer once again removes the trust line for AUD. + env(pay(issuer, gw, gwAUD(5))); + env.close(); + BEAST_EXPECT(ownerCount(env, issuer) == 0); + + // cheri attempts to accept the NoAutoTrustLine NFT. Behavior + // depends on whether fixEnforceNFTokenTrustline is enabled. + if (feats[fixEnforceNFTokenTrustline]) + { + // With fixEnforceNFTokenTrustline cheri can't accept the + // offer because issuer could not get their transfer fee + // without the appropriate trustline. + env(token::acceptSellOffer(cheri, beckyNoAutoTrustOfferIndex), + ter(tecNO_LINE)); + env.close(); + + // But if issuer re-establishes the trustline then the offer + // can be accepted. + env(trust(issuer, gwAUD(1000))); + env.close(); + BEAST_EXPECT(ownerCount(env, issuer) == 1); + + env(token::acceptSellOffer(cheri, beckyNoAutoTrustOfferIndex)); + env.close(); + } + else + { + // Without fixEnforceNFTokenTrustline the offer just works + // and issuer gets a trustline that they did not request. + env(token::acceptSellOffer(cheri, beckyNoAutoTrustOfferIndex)); + env.close(); + } + BEAST_EXPECT(ownerCount(env, issuer) == 1); + BEAST_EXPECT(env.balance(issuer, gwAUD) == gwAUD(5)); + } // for feats + } + void testNFTIssuerIsIOUIssuer(FeatureBitset features) { @@ -7609,6 +7779,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite testFeatMintWithOffer(features); testTxJsonMetaFields(features); testFixNFTokenBuyerReserve(features); + testUnaskedForAutoTrustline(features); testNFTIssuerIsIOUIssuer(features); } diff --git a/src/test/app/Offer_test.cpp b/src/test/app/Offer_test.cpp index add436d5c59..3956adfbe0d 100644 --- a/src/test/app/Offer_test.cpp +++ b/src/test/app/Offer_test.cpp @@ -5467,12 +5467,12 @@ class Offer_manual_test : public OfferBaseUtil_test } }; -BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, tx, ripple, 4); -BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFlowCross, tx, ripple, 4); -BEAST_DEFINE_TESTSUITE_PRIO(OfferWTakerDryOffer, tx, ripple, 4); -BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, tx, ripple, 4); -BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFillOrKill, tx, ripple, 4); -BEAST_DEFINE_TESTSUITE_PRIO(OfferAllFeatures, tx, ripple, 4); +BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, tx, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFlowCross, tx, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(OfferWTakerDryOffer, tx, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, tx, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFillOrKill, tx, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(OfferAllFeatures, tx, ripple, 2); BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Offer_manual, tx, ripple, 20); } // namespace test From c706926ee3c7d0f3abbbd3545cc85d6886643444 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Tue, 18 Jun 2024 17:55:40 +0100 Subject: [PATCH 12/82] Change order of checks in amm_info: (#4924) * Change order of checks in amm_info * Change amm_info error message in API version 3 * Change amm_info error tests --- src/ripple/rpc/handlers/AMMInfo.cpp | 23 +++-- src/test/jtx/AMM.h | 3 +- src/test/jtx/impl/AMM.cpp | 8 +- src/test/rpc/AMMInfo_test.cpp | 127 ++++++++++++++++++++++++---- 4 files changed, 136 insertions(+), 25 deletions(-) diff --git a/src/ripple/rpc/handlers/AMMInfo.cpp b/src/ripple/rpc/handlers/AMMInfo.cpp index b240c8c2ae6..b4f56ffba21 100644 --- a/src/ripple/rpc/handlers/AMMInfo.cpp +++ b/src/ripple/rpc/handlers/AMMInfo.cpp @@ -96,8 +96,15 @@ doAMMInfo(RPC::JsonContext& context) std::optional issue2; std::optional ammID; - if ((params.isMember(jss::asset) != params.isMember(jss::asset2)) || - (params.isMember(jss::asset) == params.isMember(jss::amm_account))) + constexpr auto invalid = [](Json::Value const& params) -> bool { + return (params.isMember(jss::asset) != + params.isMember(jss::asset2)) || + (params.isMember(jss::asset) == + params.isMember(jss::amm_account)); + }; + + // NOTE, identical check for apVersion >= 3 below + if (context.apiVersion < 3 && invalid(params)) return Unexpected(rpcINVALID_PARAMS); if (params.isMember(jss::asset)) @@ -127,10 +134,6 @@ doAMMInfo(RPC::JsonContext& context) ammID = sle->getFieldH256(sfAMMID); } - assert( - (issue1.has_value() == issue2.has_value()) && - (issue1.has_value() != ammID.has_value())); - if (params.isMember(jss::account)) { accountID = getAccount(params[jss::account], result); @@ -138,6 +141,14 @@ doAMMInfo(RPC::JsonContext& context) return Unexpected(rpcACT_MALFORMED); } + // NOTE, identical check for apVersion < 3 above + if (context.apiVersion >= 3 && invalid(params)) + return Unexpected(rpcINVALID_PARAMS); + + assert( + (issue1.has_value() == issue2.has_value()) && + (issue1.has_value() != ammID.has_value())); + auto const ammKeylet = [&]() { if (issue1 && issue2) return keylet::amm(*issue1, *issue2); diff --git a/src/test/jtx/AMM.h b/src/test/jtx/AMM.h index b98065a077e..bb1032e006d 100644 --- a/src/test/jtx/AMM.h +++ b/src/test/jtx/AMM.h @@ -174,7 +174,8 @@ class AMM std::optional issue1 = std::nullopt, std::optional issue2 = std::nullopt, std::optional const& ammAccount = std::nullopt, - bool ignoreParams = false) const; + bool ignoreParams = false, + unsigned apiVersion = RPC::apiInvalidVersion) const; /** Verify the AMM balances. */ diff --git a/src/test/jtx/impl/AMM.cpp b/src/test/jtx/impl/AMM.cpp index 38cdb201854..a36384f4a29 100644 --- a/src/test/jtx/impl/AMM.cpp +++ b/src/test/jtx/impl/AMM.cpp @@ -163,7 +163,8 @@ AMM::ammRpcInfo( std::optional issue1, std::optional issue2, std::optional const& ammAccount, - bool ignoreParams) const + bool ignoreParams, + unsigned apiVersion) const { Json::Value jv; if (account) @@ -191,7 +192,10 @@ AMM::ammRpcInfo( if (ammAccount) jv[jss::amm_account] = to_string(*ammAccount); } - auto jr = env_.rpc("json", "amm_info", to_string(jv)); + auto jr = + (apiVersion == RPC::apiInvalidVersion + ? env_.rpc("json", "amm_info", to_string(jv)) + : env_.rpc(apiVersion, "json", "amm_info", to_string(jv))); if (jr.isObject() && jr.isMember(jss::result) && jr[jss::result].isMember(jss::status)) return jr[jss::result]; diff --git a/src/test/rpc/AMMInfo_test.cpp b/src/test/rpc/AMMInfo_test.cpp index cfcb672c032..664a0c04cd5 100644 --- a/src/test/rpc/AMMInfo_test.cpp +++ b/src/test/rpc/AMMInfo_test.cpp @@ -37,6 +37,19 @@ class AMMInfo_test : public jtx::AMMTestBase testcase("Errors"); using namespace jtx; + + Account const bogie("bogie"); + enum TestAccount { None, Alice, Bogie }; + auto accountId = [&](AMM const& ammAlice, + TestAccount v) -> std::optional { + if (v == Alice) + return ammAlice.ammAccount(); + else if (v == Bogie) + return bogie; + else + return std::nullopt; + }; + // Invalid tokens pair testAMM([&](AMM& ammAlice, Env&) { Account const gw("gw"); @@ -48,36 +61,70 @@ class AMMInfo_test : public jtx::AMMTestBase // Invalid LP account id testAMM([&](AMM& ammAlice, Env&) { - Account bogie("bogie"); auto const jv = ammAlice.ammRpcInfo(bogie.id()); BEAST_EXPECT(jv[jss::error_message] == "Account malformed."); }); + std::vector, + std::optional, + TestAccount, + bool>> const invalidParams = { + {xrpIssue(), std::nullopt, None, false}, + {std::nullopt, USD.issue(), None, false}, + {xrpIssue(), std::nullopt, Alice, false}, + {std::nullopt, USD.issue(), Alice, false}, + {xrpIssue(), USD.issue(), Alice, false}, + {std::nullopt, std::nullopt, None, true}}; + // Invalid parameters testAMM([&](AMM& ammAlice, Env&) { - std::vector, - std::optional, - std::optional, - bool>> - vals = { - {xrpIssue(), std::nullopt, std::nullopt, false}, - {std::nullopt, USD.issue(), std::nullopt, false}, - {xrpIssue(), std::nullopt, ammAlice.ammAccount(), false}, - {std::nullopt, USD.issue(), ammAlice.ammAccount(), false}, - {xrpIssue(), USD.issue(), ammAlice.ammAccount(), false}, - {std::nullopt, std::nullopt, std::nullopt, true}}; - for (auto const& [iss1, iss2, acct, ignoreParams] : vals) + for (auto const& [iss1, iss2, acct, ignoreParams] : invalidParams) + { + auto const jv = ammAlice.ammRpcInfo( + std::nullopt, + std::nullopt, + iss1, + iss2, + accountId(ammAlice, acct), + ignoreParams); + BEAST_EXPECT(jv[jss::error_message] == "Invalid parameters."); + } + }); + + // Invalid parameters *and* invalid LP account, default API version + testAMM([&](AMM& ammAlice, Env&) { + for (auto const& [iss1, iss2, acct, ignoreParams] : invalidParams) { auto const jv = ammAlice.ammRpcInfo( - std::nullopt, std::nullopt, iss1, iss2, acct, ignoreParams); + bogie, // + std::nullopt, + iss1, + iss2, + accountId(ammAlice, acct), + ignoreParams); BEAST_EXPECT(jv[jss::error_message] == "Invalid parameters."); } }); + // Invalid parameters *and* invalid LP account, API version 3 + testAMM([&](AMM& ammAlice, Env&) { + for (auto const& [iss1, iss2, acct, ignoreParams] : invalidParams) + { + auto const jv = ammAlice.ammRpcInfo( + bogie, // + std::nullopt, + iss1, + iss2, + accountId(ammAlice, acct), + ignoreParams, + 3); + BEAST_EXPECT(jv[jss::error_message] == "Account malformed."); + } + }); + // Invalid AMM account id testAMM([&](AMM& ammAlice, Env&) { - Account bogie("bogie"); auto const jv = ammAlice.ammRpcInfo( std::nullopt, std::nullopt, @@ -86,6 +133,54 @@ class AMMInfo_test : public jtx::AMMTestBase bogie.id()); BEAST_EXPECT(jv[jss::error_message] == "Account malformed."); }); + + std::vector, + std::optional, + TestAccount, + bool>> const invalidParamsBadAccount = { + {xrpIssue(), std::nullopt, None, false}, + {std::nullopt, USD.issue(), None, false}, + {xrpIssue(), std::nullopt, Bogie, false}, + {std::nullopt, USD.issue(), Bogie, false}, + {xrpIssue(), USD.issue(), Bogie, false}, + {std::nullopt, std::nullopt, None, true}}; + + // Invalid parameters *and* invalid AMM account, default API version + testAMM([&](AMM& ammAlice, Env&) { + for (auto const& [iss1, iss2, acct, ignoreParams] : + invalidParamsBadAccount) + { + auto const jv = ammAlice.ammRpcInfo( + std::nullopt, + std::nullopt, + iss1, + iss2, + accountId(ammAlice, acct), + ignoreParams); + BEAST_EXPECT(jv[jss::error_message] == "Invalid parameters."); + } + }); + + // Invalid parameters *and* invalid AMM account, API version 3 + testAMM([&](AMM& ammAlice, Env&) { + for (auto const& [iss1, iss2, acct, ignoreParams] : + invalidParamsBadAccount) + { + auto const jv = ammAlice.ammRpcInfo( + std::nullopt, + std::nullopt, + iss1, + iss2, + accountId(ammAlice, acct), + ignoreParams, + 3); + BEAST_EXPECT( + jv[jss::error_message] == + (acct == Bogie ? std::string("Account malformed.") + : std::string("Invalid parameters."))); + } + }); } void From ae20a3ad3fd79cdd34ff5ad49acf76b2ea386a84 Mon Sep 17 00:00:00 2001 From: John Freeman Date: Fri, 29 Mar 2024 20:21:18 -0500 Subject: [PATCH 13/82] Prepare to rearrange sources: (#4997) - Remove CMake module "MultiConfig". - Update clang-format configuration, CodeCov configuration, levelization script. - Replace source lists in CMake with globs. --- .clang-format | 6 +- .codecov.yml | 4 +- .github/workflows/clang-format.yml | 6 +- Builds/CMake/RippledCore.cmake | 1192 ++----------------------- Builds/CMake/RippledDocs.cmake | 3 +- Builds/CMake/RippledInstall.cmake | 23 +- Builds/CMake/RippledMultiConfig.cmake | 39 - Builds/CMake/RippledVersion.cmake | 22 +- Builds/levelization/levelization.sh | 2 +- CMakeLists.txt | 9 +- conanfile.py | 11 +- 11 files changed, 113 insertions(+), 1204 deletions(-) delete mode 100644 Builds/CMake/RippledMultiConfig.cmake diff --git a/.clang-format b/.clang-format index ba409869bd3..0b1b4efea07 100644 --- a/.clang-format +++ b/.clang-format @@ -45,9 +45,11 @@ DisableFormat: false ExperimentalAutoDetectBinPacking: false ForEachMacros: [ Q_FOREACH, BOOST_FOREACH ] IncludeCategories: - - Regex: '^<(BeastConfig)' + - Regex: '^<(test)/' Priority: 0 - - Regex: '^<(ripple)/' + - Regex: '^<(xrpld)/' + Priority: 1 + - Regex: '^<(xrpl)/' Priority: 2 - Regex: '^<(boost)/' Priority: 3 diff --git a/.codecov.yml b/.codecov.yml index 3e6f09d58ae..6df3786197f 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -33,5 +33,5 @@ slack_app: false ignore: - "src/test/" - - "src/ripple/beast/test/" - - "src/ripple/beast/unit_test/" + - "include/xrpl/beast/test/" + - "include/xrpl/beast/unit_test/" diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index 8c915ec00ff..e86b7b257a5 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -19,10 +19,8 @@ jobs: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add sudo apt-get update sudo apt-get install clang-format-${CLANG_VERSION} - - name: Format src/ripple - run: find src/ripple -type f \( -name '*.cpp' -o -name '*.h' -o -name '*.ipp' \) -print0 | xargs -0 clang-format-${CLANG_VERSION} -i - - name: Format src/test - run: find src/test -type f \( -name '*.cpp' -o -name '*.h' -o -name '*.ipp' \) -print0 | xargs -0 clang-format-${CLANG_VERSION} -i + - name: Format sources + run: find include src -type f \( -name '*.cpp' -o -name '*.h' -o -name '*.ipp' \) -exec clang-format-${CLANG_VERSION} -i {} + - name: Check for differences id: assert run: | diff --git a/Builds/CMake/RippledCore.cmake b/Builds/CMake/RippledCore.cmake index 6b7b2aae683..9af3303f662 100644 --- a/Builds/CMake/RippledCore.cmake +++ b/Builds/CMake/RippledCore.cmake @@ -1,33 +1,29 @@ #[===================================================================[ - xrpl_core - core functionality, useable by some client software perhaps + Exported targets. #]===================================================================] include(target_protobuf_sources) -file (GLOB_RECURSE rb_headers - src/ripple/beast/*.h) - # Protocol buffers cannot participate in a unity build, # because all the generated sources # define a bunch of `static const` variables with the same names, # so we just build them as a separate library. add_library(xrpl.libpb) -target_protobuf_sources(xrpl.libpb ripple/proto +target_protobuf_sources(xrpl.libpb xrpl/proto LANGUAGE cpp - IMPORT_DIRS src/ripple/proto - PROTOS src/ripple/proto/ripple.proto + IMPORT_DIRS include/xrpl/proto + PROTOS include/xrpl/proto/ripple.proto ) -file(GLOB_RECURSE protos "src/ripple/proto/org/*.proto") -target_protobuf_sources(xrpl.libpb ripple/proto +file(GLOB_RECURSE protos "include/xrpl/proto/org/*.proto") +target_protobuf_sources(xrpl.libpb xrpl/proto LANGUAGE cpp - IMPORT_DIRS src/ripple/proto + IMPORT_DIRS include/xrpl/proto PROTOS "${protos}" ) -target_protobuf_sources(xrpl.libpb ripple/proto +target_protobuf_sources(xrpl.libpb xrpl/proto LANGUAGE grpc - IMPORT_DIRS src/ripple/proto + IMPORT_DIRS include/xrpl/proto PROTOS "${protos}" PLUGIN protoc-gen-grpc=$ GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc @@ -51,1162 +47,100 @@ target_link_libraries(xrpl.libpb gRPC::grpc++ ) -add_library (xrpl_core - ${rb_headers}) ## headers added here for benefit of IDEs -if (unity) - set_target_properties(xrpl_core PROPERTIES UNITY_BUILD ON) -endif () - -add_library(libxrpl INTERFACE) -target_link_libraries(libxrpl INTERFACE xrpl_core) -add_library(xrpl::libxrpl ALIAS libxrpl) +add_library(xrpl.libxrpl) +set_target_properties(xrpl.libxrpl PROPERTIES OUTPUT_NAME xrpl) +if(unity) + set_target_properties(xrpl.libxrpl PROPERTIES UNITY_BUILD ON) +endif() -#[===============================[ - beast/legacy FILES: - TODO: review these sources for removal or replacement -#]===============================] -# BEGIN LIBXRPL SOURCES -target_sources (xrpl_core PRIVATE - src/ripple/beast/clock/basic_seconds_clock.cpp - src/ripple/beast/core/CurrentThreadName.cpp - src/ripple/beast/core/SemanticVersion.cpp - src/ripple/beast/insight/impl/Collector.cpp - src/ripple/beast/insight/impl/Groups.cpp - src/ripple/beast/insight/impl/Hook.cpp - src/ripple/beast/insight/impl/Metric.cpp - src/ripple/beast/insight/impl/NullCollector.cpp - src/ripple/beast/insight/impl/StatsDCollector.cpp - src/ripple/beast/net/impl/IPAddressConversion.cpp - src/ripple/beast/net/impl/IPAddressV4.cpp - src/ripple/beast/net/impl/IPAddressV6.cpp - src/ripple/beast/net/impl/IPEndpoint.cpp - src/ripple/beast/utility/src/beast_Journal.cpp - src/ripple/beast/utility/src/beast_PropertyStream.cpp) +add_library(xrpl::libxrpl ALIAS xrpl.libxrpl) -#[===============================[ - core sources -#]===============================] -target_sources (xrpl_core PRIVATE - #[===============================[ - main sources: - subdir: basics - #]===============================] - src/ripple/basics/impl/Archive.cpp - src/ripple/basics/impl/base64.cpp - src/ripple/basics/impl/BasicConfig.cpp - src/ripple/basics/impl/contract.cpp - src/ripple/basics/impl/CountedObject.cpp - src/ripple/basics/impl/FileUtilities.cpp - src/ripple/basics/impl/IOUAmount.cpp - src/ripple/basics/impl/Log.cpp - src/ripple/basics/impl/make_SSLContext.cpp - src/ripple/basics/impl/mulDiv.cpp - src/ripple/basics/impl/Number.cpp - src/ripple/basics/impl/partitioned_unordered_map.cpp - src/ripple/basics/impl/ResolverAsio.cpp - src/ripple/basics/impl/StringUtilities.cpp - src/ripple/basics/impl/UptimeClock.cpp - #[===============================[ - main sources: - subdir: json - #]===============================] - src/ripple/json/impl/JsonPropertyStream.cpp - src/ripple/json/impl/Object.cpp - src/ripple/json/impl/Output.cpp - src/ripple/json/impl/Writer.cpp - src/ripple/json/impl/json_reader.cpp - src/ripple/json/impl/json_value.cpp - src/ripple/json/impl/json_valueiterator.cpp - src/ripple/json/impl/json_writer.cpp - src/ripple/json/impl/to_string.cpp - #[===============================[ - main sources: - subdir: protocol - #]===============================] - src/ripple/protocol/impl/AccountID.cpp - src/ripple/protocol/impl/AMMCore.cpp - src/ripple/protocol/impl/Book.cpp - src/ripple/protocol/impl/BuildInfo.cpp - src/ripple/protocol/impl/ErrorCodes.cpp - src/ripple/protocol/impl/Feature.cpp - src/ripple/protocol/impl/Indexes.cpp - src/ripple/protocol/impl/InnerObjectFormats.cpp - src/ripple/protocol/impl/Issue.cpp - src/ripple/protocol/impl/STIssue.cpp - src/ripple/protocol/impl/Keylet.cpp - src/ripple/protocol/impl/LedgerFormats.cpp - src/ripple/protocol/impl/LedgerHeader.cpp - src/ripple/protocol/impl/PublicKey.cpp - src/ripple/protocol/impl/Quality.cpp - src/ripple/protocol/impl/QualityFunction.cpp - src/ripple/protocol/impl/RPCErr.cpp - src/ripple/protocol/impl/Rate2.cpp - src/ripple/protocol/impl/Rules.cpp - src/ripple/protocol/impl/SField.cpp - src/ripple/protocol/impl/SOTemplate.cpp - src/ripple/protocol/impl/STAccount.cpp - src/ripple/protocol/impl/STAmount.cpp - src/ripple/protocol/impl/STArray.cpp - src/ripple/protocol/impl/STBase.cpp - src/ripple/protocol/impl/STBlob.cpp - src/ripple/protocol/impl/STCurrency.cpp - src/ripple/protocol/impl/STInteger.cpp - src/ripple/protocol/impl/STLedgerEntry.cpp - src/ripple/protocol/impl/STObject.cpp - src/ripple/protocol/impl/STParsedJSON.cpp - src/ripple/protocol/impl/STPathSet.cpp - src/ripple/protocol/impl/STXChainBridge.cpp - src/ripple/protocol/impl/STTx.cpp - src/ripple/protocol/impl/XChainAttestations.cpp - src/ripple/protocol/impl/STValidation.cpp - src/ripple/protocol/impl/STVar.cpp - src/ripple/protocol/impl/STVector256.cpp - src/ripple/protocol/impl/SecretKey.cpp - src/ripple/protocol/impl/Seed.cpp - src/ripple/protocol/impl/Serializer.cpp - src/ripple/protocol/impl/Sign.cpp - src/ripple/protocol/impl/TER.cpp - src/ripple/protocol/impl/TxFormats.cpp - src/ripple/protocol/impl/TxMeta.cpp - src/ripple/protocol/impl/UintTypes.cpp - src/ripple/protocol/impl/digest.cpp - src/ripple/protocol/impl/tokens.cpp - src/ripple/protocol/impl/NFTSyntheticSerializer.cpp - src/ripple/protocol/impl/NFTokenID.cpp - src/ripple/protocol/impl/NFTokenOfferID.cpp - #[===============================[ - main sources: - subdir: resource - #]===============================] - src/ripple/resource/impl/Charge.cpp - src/ripple/resource/impl/Consumer.cpp - src/ripple/resource/impl/Fees.cpp - src/ripple/resource/impl/ResourceManager.cpp - #[===============================[ - main sources: - subdir: server - #]===============================] - src/ripple/server/impl/JSONRPCUtil.cpp - src/ripple/server/impl/Port.cpp - #[===============================[ - main sources: - subdir: crypto - #]===============================] - src/ripple/crypto/impl/RFC1751.cpp - src/ripple/crypto/impl/csprng.cpp - src/ripple/crypto/impl/secure_erase.cpp) -# END LIBXRPL SOURCES +file(GLOB_RECURSE sources CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/src/libxrpl/*.cpp" +) +target_sources(xrpl.libxrpl PRIVATE ${sources}) -add_library (Ripple::xrpl_core ALIAS xrpl_core) -target_include_directories (xrpl_core +target_include_directories(xrpl.libxrpl PUBLIC - $ + $ $) -target_compile_definitions(xrpl_core +target_compile_definitions(xrpl.libxrpl PUBLIC BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT BOOST_CONTAINER_FWD_BAD_DEQUE HAS_UNCAUGHT_EXCEPTIONS=1) -target_compile_options (xrpl_core + +target_compile_options(xrpl.libxrpl PUBLIC - $<$:-Wno-maybe-uninitialized>) -target_link_libraries (xrpl_core + $<$:-Wno-maybe-uninitialized> +) + +target_link_libraries(xrpl.libxrpl PUBLIC - date::date - ed25519::ed25519 LibArchive::LibArchive OpenSSL::Crypto Ripple::boost Ripple::opts Ripple::syslibs + absl::random_random + date::date + ed25519::ed25519 secp256k1::secp256k1 xrpl.libpb - xxHash::xxhash) -#[=================================[ - main/core headers installation -#]=================================] -# BEGIN LIBXRPL HEADERS -install ( - FILES - src/ripple/basics/Archive.h - src/ripple/basics/BasicConfig.h - src/ripple/basics/Blob.h - src/ripple/basics/Buffer.h - src/ripple/basics/ByteUtilities.h - src/ripple/basics/CompressionAlgorithms.h - src/ripple/basics/CountedObject.h - src/ripple/basics/DecayingSample.h - src/ripple/basics/Expected.h - src/ripple/basics/FeeUnits.h - src/ripple/basics/FileUtilities.h - src/ripple/basics/IOUAmount.h - src/ripple/basics/KeyCache.h - src/ripple/basics/LocalValue.h - src/ripple/basics/Log.h - src/ripple/basics/MathUtilities.h - src/ripple/basics/Number.h - src/ripple/basics/PerfLog.h - src/ripple/basics/README.md - src/ripple/basics/RangeSet.h - src/ripple/basics/Resolver.h - src/ripple/basics/ResolverAsio.h - src/ripple/basics/SHAMapHash.h - src/ripple/basics/Slice.h - src/ripple/basics/StringUtilities.h - src/ripple/basics/TaggedCache.h - src/ripple/basics/ThreadSafetyAnalysis.h - src/ripple/basics/ToString.h - src/ripple/basics/UnorderedContainers.h - src/ripple/basics/UptimeClock.h - src/ripple/basics/XRPAmount.h - src/ripple/basics/algorithm.h - src/ripple/basics/base64.h - src/ripple/basics/base_uint.h - src/ripple/basics/chrono.h - src/ripple/basics/comparators.h - src/ripple/basics/contract.h - src/ripple/basics/hardened_hash.h - src/ripple/basics/join.h - src/ripple/basics/make_SSLContext.h - src/ripple/basics/mulDiv.h - src/ripple/basics/partitioned_unordered_map.h - src/ripple/basics/random.h - src/ripple/basics/safe_cast.h - src/ripple/basics/scope.h - src/ripple/basics/spinlock.h - src/ripple/basics/strHex.h - src/ripple/basics/tagged_integer.h - DESTINATION include/ripple/basics) -install ( - FILES - src/ripple/crypto/RFC1751.h - src/ripple/crypto/csprng.h - src/ripple/crypto/secure_erase.h - DESTINATION include/ripple/crypto) -install ( - FILES - src/ripple/json/JsonPropertyStream.h - src/ripple/json/Object.h - src/ripple/json/Output.h - src/ripple/json/Writer.h - src/ripple/json/json_forwards.h - src/ripple/json/json_reader.h - src/ripple/json/json_value.h - src/ripple/json/json_writer.h - src/ripple/json/to_string.h - DESTINATION include/ripple/json) -install ( - FILES - src/ripple/json/impl/json_assert.h - DESTINATION include/ripple/json/impl) -install ( - FILES - src/ripple/protocol/AccountID.h - src/ripple/protocol/AMMCore.h - src/ripple/protocol/AmountConversions.h - src/ripple/protocol/ApiVersion.h - src/ripple/protocol/Book.h - src/ripple/protocol/BuildInfo.h - src/ripple/protocol/ErrorCodes.h - src/ripple/protocol/Feature.h - src/ripple/protocol/Fees.h - src/ripple/protocol/HashPrefix.h - src/ripple/protocol/Indexes.h - src/ripple/protocol/InnerObjectFormats.h - src/ripple/protocol/Issue.h - src/ripple/protocol/json_get_or_throw.h - src/ripple/protocol/Keylet.h - src/ripple/protocol/KeyType.h - src/ripple/protocol/KnownFormats.h - src/ripple/protocol/LedgerFormats.h - src/ripple/protocol/LedgerHeader.h - src/ripple/protocol/MultiApiJson.h - src/ripple/protocol/NFTSyntheticSerializer.h - src/ripple/protocol/NFTokenID.h - src/ripple/protocol/NFTokenOfferID.h - src/ripple/protocol/NFTSyntheticSerializer.h - src/ripple/protocol/Protocol.h - src/ripple/protocol/PublicKey.h - src/ripple/protocol/Quality.h - src/ripple/protocol/QualityFunction.h - src/ripple/protocol/Rate.h - src/ripple/protocol/RPCErr.h - src/ripple/protocol/Rules.h - src/ripple/protocol/SecretKey.h - src/ripple/protocol/Seed.h - src/ripple/protocol/SeqProxy.h - src/ripple/protocol/Serializer.h - src/ripple/protocol/SField.h - src/ripple/protocol/Sign.h - src/ripple/protocol/SOTemplate.h - src/ripple/protocol/STAccount.h - src/ripple/protocol/STAmount.h - src/ripple/protocol/STArray.h - src/ripple/protocol/STBase.h - src/ripple/protocol/STBitString.h - src/ripple/protocol/STBlob.h - src/ripple/protocol/STCurrency.h - src/ripple/protocol/STExchange.h - src/ripple/protocol/STInteger.h - src/ripple/protocol/STIssue.h - src/ripple/protocol/STLedgerEntry.h - src/ripple/protocol/STObject.h - src/ripple/protocol/STParsedJSON.h - src/ripple/protocol/STPathSet.h - src/ripple/protocol/STTx.h - src/ripple/protocol/STValidation.h - src/ripple/protocol/STVector256.h - src/ripple/protocol/STXChainBridge.h - src/ripple/protocol/SystemParameters.h - src/ripple/protocol/TER.h - src/ripple/protocol/TxFlags.h - src/ripple/protocol/TxFormats.h - src/ripple/protocol/TxMeta.h - src/ripple/protocol/UintTypes.h - src/ripple/protocol/XChainAttestations.h - src/ripple/protocol/digest.h - src/ripple/protocol/jss.h - src/ripple/protocol/nft.h - src/ripple/protocol/nftPageMask.h - src/ripple/protocol/serialize.h - src/ripple/protocol/tokens.h - DESTINATION include/ripple/protocol) -install ( - FILES - src/ripple/protocol/impl/STVar.h - src/ripple/protocol/impl/b58_utils.h - src/ripple/protocol/impl/secp256k1.h - src/ripple/protocol/impl/token_errors.h - DESTINATION include/ripple/protocol/impl) -install ( - FILES - src/ripple/resource/Charge.h - src/ripple/resource/Consumer.h - src/ripple/resource/Disposition.h - src/ripple/resource/Fees.h - src/ripple/resource/Gossip.h - src/ripple/resource/ResourceManager.h - src/ripple/resource/Types.h - DESTINATION include/ripple/resource) -install ( - FILES - src/ripple/resource/impl/Entry.h - src/ripple/resource/impl/Import.h - src/ripple/resource/impl/Key.h - src/ripple/resource/impl/Kind.h - src/ripple/resource/impl/Logic.h - src/ripple/resource/impl/Tuning.h - DESTINATION include/ripple/resource/impl) -install ( - FILES - src/ripple/server/Handoff.h - src/ripple/server/Port.h - src/ripple/server/Server.h - src/ripple/server/Session.h - src/ripple/server/SimpleWriter.h - src/ripple/server/Writer.h - src/ripple/server/WSSession.h - DESTINATION include/ripple/server) -install ( - FILES - src/ripple/server/impl/BaseHTTPPeer.h - src/ripple/server/impl/BasePeer.h - src/ripple/server/impl/BaseWSPeer.h - src/ripple/server/impl/Door.h - src/ripple/server/impl/JSONRPCUtil.h - src/ripple/server/impl/LowestLayer.h - src/ripple/server/impl/PlainHTTPPeer.h - src/ripple/server/impl/PlainWSPeer.h - src/ripple/server/impl/ServerImpl.h - src/ripple/server/impl/SSLHTTPPeer.h - src/ripple/server/impl/SSLWSPeer.h - src/ripple/server/impl/io_list.h - DESTINATION include/ripple/server/impl) -#[===================================[ - beast/legacy headers installation -#]===================================] -install ( - FILES - src/ripple/beast/clock/abstract_clock.h - src/ripple/beast/clock/basic_seconds_clock.h - src/ripple/beast/clock/manual_clock.h - DESTINATION include/ripple/beast/clock) -install ( - FILES - src/ripple/beast/core/CurrentThreadName.h - src/ripple/beast/core/LexicalCast.h - src/ripple/beast/core/List.h - src/ripple/beast/core/SemanticVersion.h - DESTINATION include/ripple/beast/core) -install ( - FILES - src/ripple/beast/hash/hash_append.h - src/ripple/beast/hash/uhash.h - src/ripple/beast/hash/xxhasher.h - DESTINATION include/ripple/beast/hash) -install ( - FILES - src/ripple/beast/net/IPAddress.h - src/ripple/beast/net/IPAddressConversion.h - src/ripple/beast/net/IPAddressV4.h - src/ripple/beast/net/IPAddressV6.h - src/ripple/beast/net/IPEndpoint.h - DESTINATION include/ripple/beast/net) -install ( - FILES - src/ripple/beast/rfc2616.h - src/ripple/beast/type_name.h - src/ripple/beast/unit_test.h - src/ripple/beast/xor_shift_engine.h - DESTINATION include/ripple/beast) -install ( - FILES - src/ripple/beast/unit_test/amount.h - src/ripple/beast/unit_test/dstream.h - src/ripple/beast/unit_test/global_suites.h - src/ripple/beast/unit_test/match.h - src/ripple/beast/unit_test/recorder.h - src/ripple/beast/unit_test/reporter.h - src/ripple/beast/unit_test/results.h - src/ripple/beast/unit_test/runner.h - src/ripple/beast/unit_test/suite_info.h - src/ripple/beast/unit_test/suite_list.h - src/ripple/beast/unit_test/suite.h - src/ripple/beast/unit_test/thread.h - DESTINATION include/ripple/beast/unit_test) -install ( - FILES - src/ripple/beast/unit_test/detail/const_container.h - DESTINATION include/ripple/beast/unit_test/detail) -install ( - FILES - src/ripple/beast/utility/Journal.h - src/ripple/beast/utility/PropertyStream.h - src/ripple/beast/utility/WrappedSink.h - src/ripple/beast/utility/Zero.h - src/ripple/beast/utility/rngfill.h - DESTINATION include/ripple/beast/utility) -# END LIBXRPL HEADERS -#[===================================================================[ - rippled executable -#]===================================================================] + xxHash::xxhash +) -#[=========================================================[ - this one header is added as source just to keep older - versions of cmake happy. cmake 3.10+ allows - add_executable with no sources -#]=========================================================] -add_executable (rippled src/ripple/app/main/Application.h) -if (unity) +add_executable(rippled) +if(unity) set_target_properties(rippled PROPERTIES UNITY_BUILD ON) -endif () -if (tests) - target_compile_definitions(rippled PUBLIC ENABLE_TESTS) endif() -# BEGIN XRPLD SOURCES -target_sources (rippled PRIVATE - #[===============================[ - main sources: - subdir: app - #]===============================] - src/ripple/app/consensus/RCLConsensus.cpp - src/ripple/app/consensus/RCLCxPeerPos.cpp - src/ripple/app/consensus/RCLValidations.cpp - src/ripple/app/ledger/AcceptedLedger.cpp - src/ripple/app/ledger/AcceptedLedgerTx.cpp - src/ripple/app/ledger/AccountStateSF.cpp - src/ripple/app/ledger/BookListeners.cpp - src/ripple/app/ledger/ConsensusTransSetSF.cpp - src/ripple/app/ledger/Ledger.cpp - src/ripple/app/ledger/LedgerHistory.cpp - src/ripple/app/ledger/OrderBookDB.cpp - src/ripple/app/ledger/TransactionStateSF.cpp - src/ripple/app/ledger/impl/BuildLedger.cpp - src/ripple/app/ledger/impl/InboundLedger.cpp - src/ripple/app/ledger/impl/InboundLedgers.cpp - src/ripple/app/ledger/impl/InboundTransactions.cpp - src/ripple/app/ledger/impl/LedgerCleaner.cpp - src/ripple/app/ledger/impl/LedgerDeltaAcquire.cpp - src/ripple/app/ledger/impl/LedgerMaster.cpp - src/ripple/app/ledger/impl/LedgerReplay.cpp - src/ripple/app/ledger/impl/LedgerReplayer.cpp - src/ripple/app/ledger/impl/LedgerReplayMsgHandler.cpp - src/ripple/app/ledger/impl/LedgerReplayTask.cpp - src/ripple/app/ledger/impl/LedgerToJson.cpp - src/ripple/app/ledger/impl/LocalTxs.cpp - src/ripple/app/ledger/impl/OpenLedger.cpp - src/ripple/app/ledger/impl/SkipListAcquire.cpp - src/ripple/app/ledger/impl/TimeoutCounter.cpp - src/ripple/app/ledger/impl/TransactionAcquire.cpp - src/ripple/app/ledger/impl/TransactionMaster.cpp - src/ripple/app/main/Application.cpp - src/ripple/app/main/BasicApp.cpp - src/ripple/app/main/CollectorManager.cpp - src/ripple/app/main/GRPCServer.cpp - src/ripple/app/main/LoadManager.cpp - src/ripple/app/main/Main.cpp - src/ripple/app/main/NodeIdentity.cpp - src/ripple/app/main/NodeStoreScheduler.cpp - src/ripple/app/reporting/ReportingETL.cpp - src/ripple/app/reporting/ETLSource.cpp - src/ripple/app/reporting/P2pProxy.cpp - src/ripple/app/misc/impl/AMMHelpers.cpp - src/ripple/app/misc/impl/AMMUtils.cpp - src/ripple/app/misc/CanonicalTXSet.cpp - src/ripple/app/misc/FeeVoteImpl.cpp - src/ripple/app/misc/HashRouter.cpp - src/ripple/app/misc/NegativeUNLVote.cpp - src/ripple/app/misc/NetworkOPs.cpp - src/ripple/app/misc/SHAMapStoreImp.cpp - src/ripple/app/misc/detail/impl/WorkSSL.cpp - src/ripple/app/misc/impl/AccountTxPaging.cpp - src/ripple/app/misc/impl/AmendmentTable.cpp - src/ripple/app/misc/impl/DeliverMax.cpp - src/ripple/app/misc/impl/LoadFeeTrack.cpp - src/ripple/app/misc/impl/Manifest.cpp - src/ripple/app/misc/impl/Transaction.cpp - src/ripple/app/misc/impl/TxQ.cpp - src/ripple/app/misc/impl/ValidatorKeys.cpp - src/ripple/app/misc/impl/ValidatorList.cpp - src/ripple/app/misc/impl/ValidatorSite.cpp - src/ripple/app/paths/AccountCurrencies.cpp - src/ripple/app/paths/Credit.cpp - src/ripple/app/paths/Flow.cpp - src/ripple/app/paths/PathRequest.cpp - src/ripple/app/paths/PathRequests.cpp - src/ripple/app/paths/Pathfinder.cpp - src/ripple/app/paths/RippleCalc.cpp - src/ripple/app/paths/RippleLineCache.cpp - src/ripple/app/paths/TrustLine.cpp - src/ripple/app/paths/impl/AMMLiquidity.cpp - src/ripple/app/paths/impl/AMMOffer.cpp - src/ripple/app/paths/impl/BookStep.cpp - src/ripple/app/paths/impl/DirectStep.cpp - src/ripple/app/paths/impl/PaySteps.cpp - src/ripple/app/paths/impl/XRPEndpointStep.cpp - src/ripple/app/rdb/backend/detail/impl/Node.cpp - src/ripple/app/rdb/backend/detail/impl/Shard.cpp - src/ripple/app/rdb/backend/impl/PostgresDatabase.cpp - src/ripple/app/rdb/backend/impl/SQLiteDatabase.cpp - src/ripple/app/rdb/impl/Download.cpp - src/ripple/app/rdb/impl/PeerFinder.cpp - src/ripple/app/rdb/impl/RelationalDatabase.cpp - src/ripple/app/rdb/impl/ShardArchive.cpp - src/ripple/app/rdb/impl/State.cpp - src/ripple/app/rdb/impl/UnitaryShard.cpp - src/ripple/app/rdb/impl/Vacuum.cpp - src/ripple/app/rdb/impl/Wallet.cpp - src/ripple/app/tx/impl/AMMBid.cpp - src/ripple/app/tx/impl/AMMCreate.cpp - src/ripple/app/tx/impl/AMMDelete.cpp - src/ripple/app/tx/impl/AMMDeposit.cpp - src/ripple/app/tx/impl/AMMVote.cpp - src/ripple/app/tx/impl/AMMWithdraw.cpp - src/ripple/app/tx/impl/ApplyContext.cpp - src/ripple/app/tx/impl/BookTip.cpp - src/ripple/app/tx/impl/CancelCheck.cpp - src/ripple/app/tx/impl/CancelOffer.cpp - src/ripple/app/tx/impl/CashCheck.cpp - src/ripple/app/tx/impl/Change.cpp - src/ripple/app/tx/impl/Clawback.cpp - src/ripple/app/tx/impl/CreateCheck.cpp - src/ripple/app/tx/impl/CreateOffer.cpp - src/ripple/app/tx/impl/CreateTicket.cpp - src/ripple/app/tx/impl/DeleteAccount.cpp - src/ripple/app/tx/impl/DeleteOracle.cpp - src/ripple/app/tx/impl/DepositPreauth.cpp - src/ripple/app/tx/impl/DID.cpp - src/ripple/app/tx/impl/Escrow.cpp - src/ripple/app/tx/impl/InvariantCheck.cpp - src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp - src/ripple/app/tx/impl/NFTokenBurn.cpp - src/ripple/app/tx/impl/NFTokenCancelOffer.cpp - src/ripple/app/tx/impl/NFTokenCreateOffer.cpp - src/ripple/app/tx/impl/NFTokenMint.cpp - src/ripple/app/tx/impl/OfferStream.cpp - src/ripple/app/tx/impl/PayChan.cpp - src/ripple/app/tx/impl/Payment.cpp - src/ripple/app/tx/impl/SetAccount.cpp - src/ripple/app/tx/impl/SetOracle.cpp - src/ripple/app/tx/impl/SetRegularKey.cpp - src/ripple/app/tx/impl/SetSignerList.cpp - src/ripple/app/tx/impl/SetTrust.cpp - src/ripple/app/tx/impl/XChainBridge.cpp - src/ripple/app/tx/impl/SignerEntries.cpp - src/ripple/app/tx/impl/Taker.cpp - src/ripple/app/tx/impl/Transactor.cpp - src/ripple/app/tx/impl/apply.cpp - src/ripple/app/tx/impl/applySteps.cpp - src/ripple/app/tx/impl/details/NFTokenUtils.cpp - #[===============================[ - main sources: - subdir: conditions - #]===============================] - src/ripple/conditions/impl/Condition.cpp - src/ripple/conditions/impl/Fulfillment.cpp - src/ripple/conditions/impl/error.cpp - #[===============================[ - main sources: - subdir: core - #]===============================] - src/ripple/core/impl/Config.cpp - src/ripple/core/impl/DatabaseCon.cpp - src/ripple/core/impl/Job.cpp - src/ripple/core/impl/JobQueue.cpp - src/ripple/core/impl/LoadEvent.cpp - src/ripple/core/impl/LoadMonitor.cpp - src/ripple/core/impl/SociDB.cpp - src/ripple/core/impl/Workers.cpp - src/ripple/core/Pg.cpp - #[===============================[ - main sources: - subdir: consensus - #]===============================] - src/ripple/consensus/Consensus.cpp - #[===============================[ - main sources: - subdir: ledger - #]===============================] - src/ripple/ledger/impl/ApplyStateTable.cpp - src/ripple/ledger/impl/ApplyView.cpp - src/ripple/ledger/impl/ApplyViewBase.cpp - src/ripple/ledger/impl/ApplyViewImpl.cpp - src/ripple/ledger/impl/BookDirs.cpp - src/ripple/ledger/impl/CachedView.cpp - src/ripple/ledger/impl/Directory.cpp - src/ripple/ledger/impl/OpenView.cpp - src/ripple/ledger/impl/PaymentSandbox.cpp - src/ripple/ledger/impl/RawStateTable.cpp - src/ripple/ledger/impl/ReadView.cpp - src/ripple/ledger/impl/View.cpp - #[===============================[ - main sources: - subdir: net - #]===============================] - src/ripple/net/impl/DatabaseDownloader.cpp - src/ripple/net/impl/HTTPClient.cpp - src/ripple/net/impl/HTTPDownloader.cpp - src/ripple/net/impl/HTTPStream.cpp - src/ripple/net/impl/InfoSub.cpp - src/ripple/net/impl/RPCCall.cpp - src/ripple/net/impl/RPCSub.cpp - src/ripple/net/impl/RegisterSSLCerts.cpp - #[===============================[ - main sources: - subdir: nodestore - #]===============================] - src/ripple/nodestore/backend/CassandraFactory.cpp - src/ripple/nodestore/backend/MemoryFactory.cpp - src/ripple/nodestore/backend/NuDBFactory.cpp - src/ripple/nodestore/backend/NullFactory.cpp - src/ripple/nodestore/backend/RocksDBFactory.cpp - src/ripple/nodestore/impl/BatchWriter.cpp - src/ripple/nodestore/impl/Database.cpp - src/ripple/nodestore/impl/DatabaseNodeImp.cpp - src/ripple/nodestore/impl/DatabaseRotatingImp.cpp - src/ripple/nodestore/impl/DatabaseShardImp.cpp - src/ripple/nodestore/impl/DeterministicShard.cpp - src/ripple/nodestore/impl/DecodedBlob.cpp - src/ripple/nodestore/impl/DummyScheduler.cpp - src/ripple/nodestore/impl/ManagerImp.cpp - src/ripple/nodestore/impl/NodeObject.cpp - src/ripple/nodestore/impl/Shard.cpp - src/ripple/nodestore/impl/ShardInfo.cpp - src/ripple/nodestore/impl/TaskQueue.cpp - #[===============================[ - main sources: - subdir: overlay - #]===============================] - src/ripple/overlay/impl/Cluster.cpp - src/ripple/overlay/impl/ConnectAttempt.cpp - src/ripple/overlay/impl/Handshake.cpp - src/ripple/overlay/impl/Message.cpp - src/ripple/overlay/impl/OverlayImpl.cpp - src/ripple/overlay/impl/PeerImp.cpp - src/ripple/overlay/impl/PeerReservationTable.cpp - src/ripple/overlay/impl/PeerSet.cpp - src/ripple/overlay/impl/ProtocolVersion.cpp - src/ripple/overlay/impl/TrafficCount.cpp - src/ripple/overlay/impl/TxMetrics.cpp - #[===============================[ - main sources: - subdir: peerfinder - #]===============================] - src/ripple/peerfinder/impl/Bootcache.cpp - src/ripple/peerfinder/impl/Endpoint.cpp - src/ripple/peerfinder/impl/PeerfinderConfig.cpp - src/ripple/peerfinder/impl/PeerfinderManager.cpp - src/ripple/peerfinder/impl/SlotImp.cpp - src/ripple/peerfinder/impl/SourceStrings.cpp - #[===============================[ - main sources: - subdir: rpc - #]===============================] - src/ripple/rpc/handlers/AccountChannels.cpp - src/ripple/rpc/handlers/AccountCurrenciesHandler.cpp - src/ripple/rpc/handlers/AccountInfo.cpp - src/ripple/rpc/handlers/AccountLines.cpp - src/ripple/rpc/handlers/AccountObjects.cpp - src/ripple/rpc/handlers/AccountOffers.cpp - src/ripple/rpc/handlers/AccountTx.cpp - src/ripple/rpc/handlers/AMMInfo.cpp - src/ripple/rpc/handlers/BlackList.cpp - src/ripple/rpc/handlers/BookOffers.cpp - src/ripple/rpc/handlers/CanDelete.cpp - src/ripple/rpc/handlers/Connect.cpp - src/ripple/rpc/handlers/ConsensusInfo.cpp - src/ripple/rpc/handlers/CrawlShards.cpp - src/ripple/rpc/handlers/DepositAuthorized.cpp - src/ripple/rpc/handlers/DownloadShard.cpp - src/ripple/rpc/handlers/Feature1.cpp - src/ripple/rpc/handlers/Fee1.cpp - src/ripple/rpc/handlers/FetchInfo.cpp - src/ripple/rpc/handlers/GatewayBalances.cpp - src/ripple/rpc/handlers/GetCounts.cpp - src/ripple/rpc/handlers/GetAggregatePrice.cpp - src/ripple/rpc/handlers/LedgerAccept.cpp - src/ripple/rpc/handlers/LedgerCleanerHandler.cpp - src/ripple/rpc/handlers/LedgerClosed.cpp - src/ripple/rpc/handlers/LedgerCurrent.cpp - src/ripple/rpc/handlers/LedgerData.cpp - src/ripple/rpc/handlers/LedgerDiff.cpp - src/ripple/rpc/handlers/LedgerEntry.cpp - src/ripple/rpc/handlers/LedgerHandler.cpp - src/ripple/rpc/handlers/LedgerHeader.cpp - src/ripple/rpc/handlers/LedgerRequest.cpp - src/ripple/rpc/handlers/LogLevel.cpp - src/ripple/rpc/handlers/LogRotate.cpp - src/ripple/rpc/handlers/Manifest.cpp - src/ripple/rpc/handlers/NFTOffers.cpp - src/ripple/rpc/handlers/NodeToShard.cpp - src/ripple/rpc/handlers/NoRippleCheck.cpp - src/ripple/rpc/handlers/OwnerInfo.cpp - src/ripple/rpc/handlers/PathFind.cpp - src/ripple/rpc/handlers/PayChanClaim.cpp - src/ripple/rpc/handlers/Peers.cpp - src/ripple/rpc/handlers/Ping.cpp - src/ripple/rpc/handlers/Print.cpp - src/ripple/rpc/handlers/Random.cpp - src/ripple/rpc/handlers/Reservations.cpp - src/ripple/rpc/handlers/RipplePathFind.cpp - src/ripple/rpc/handlers/ServerInfo.cpp - src/ripple/rpc/handlers/ServerState.cpp - src/ripple/rpc/handlers/SignFor.cpp - src/ripple/rpc/handlers/SignHandler.cpp - src/ripple/rpc/handlers/Stop.cpp - src/ripple/rpc/handlers/Submit.cpp - src/ripple/rpc/handlers/SubmitMultiSigned.cpp - src/ripple/rpc/handlers/Subscribe.cpp - src/ripple/rpc/handlers/TransactionEntry.cpp - src/ripple/rpc/handlers/Tx.cpp - src/ripple/rpc/handlers/TxHistory.cpp - src/ripple/rpc/handlers/TxReduceRelay.cpp - src/ripple/rpc/handlers/UnlList.cpp - src/ripple/rpc/handlers/Unsubscribe.cpp - src/ripple/rpc/handlers/ValidationCreate.cpp - src/ripple/rpc/handlers/ValidatorInfo.cpp - src/ripple/rpc/handlers/ValidatorListSites.cpp - src/ripple/rpc/handlers/Validators.cpp - src/ripple/rpc/handlers/WalletPropose.cpp - src/ripple/rpc/impl/DeliveredAmount.cpp - src/ripple/rpc/impl/Handler.cpp - src/ripple/rpc/impl/LegacyPathFind.cpp - src/ripple/rpc/impl/RPCHandler.cpp - src/ripple/rpc/impl/RPCHelpers.cpp - src/ripple/rpc/impl/Role.cpp - src/ripple/rpc/impl/ServerHandler.cpp - src/ripple/rpc/impl/ShardArchiveHandler.cpp - src/ripple/rpc/impl/ShardVerificationScheduler.cpp - src/ripple/rpc/impl/Status.cpp - src/ripple/rpc/impl/TransactionSign.cpp - #[===============================[ - main sources: - subdir: perflog - #]===============================] - src/ripple/perflog/impl/PerfLogImp.cpp - #[===============================[ - main sources: - subdir: shamap - #]===============================] - src/ripple/shamap/impl/NodeFamily.cpp - src/ripple/shamap/impl/SHAMap.cpp - src/ripple/shamap/impl/SHAMapDelta.cpp - src/ripple/shamap/impl/SHAMapInnerNode.cpp - src/ripple/shamap/impl/SHAMapLeafNode.cpp - src/ripple/shamap/impl/SHAMapNodeID.cpp - src/ripple/shamap/impl/SHAMapSync.cpp - src/ripple/shamap/impl/SHAMapTreeNode.cpp - src/ripple/shamap/impl/ShardFamily.cpp) -# END XRPLD SOURCES +if(tests) + target_compile_definitions(rippled PUBLIC ENABLE_TESTS) +endif() +target_include_directories(rippled + PRIVATE + $ +) - #[===============================[ - test sources: - subdir: app - #]===============================] -if (tests) - target_sources (rippled PRIVATE - src/test/app/AccountDelete_test.cpp - src/test/app/AccountTxPaging_test.cpp - src/test/app/AmendmentTable_test.cpp - src/test/app/AMM_test.cpp - src/test/app/AMMCalc_test.cpp - src/test/app/AMMExtended_test.cpp - src/test/app/Check_test.cpp - src/test/app/Clawback_test.cpp - src/test/app/CrossingLimits_test.cpp - src/test/app/DeliverMin_test.cpp - src/test/app/DepositAuth_test.cpp - src/test/app/Discrepancy_test.cpp - src/test/app/DID_test.cpp - src/test/app/DNS_test.cpp - src/test/app/Escrow_test.cpp - src/test/app/FeeVote_test.cpp - src/test/app/Flow_test.cpp - src/test/app/Freeze_test.cpp - src/test/app/HashRouter_test.cpp - src/test/app/LedgerHistory_test.cpp - src/test/app/LedgerLoad_test.cpp - src/test/app/LedgerMaster_test.cpp - src/test/app/LedgerReplay_test.cpp - src/test/app/LoadFeeTrack_test.cpp - src/test/app/Manifest_test.cpp - src/test/app/MultiSign_test.cpp - src/test/app/NetworkID_test.cpp - src/test/app/NFToken_test.cpp - src/test/app/NFTokenBurn_test.cpp - src/test/app/NFTokenDir_test.cpp - src/test/app/OfferStream_test.cpp - src/test/app/Offer_test.cpp - src/test/app/Oracle_test.cpp - src/test/app/OversizeMeta_test.cpp - src/test/app/Path_test.cpp - src/test/app/PayChan_test.cpp - src/test/app/PayStrand_test.cpp - src/test/app/PseudoTx_test.cpp - src/test/app/RCLCensorshipDetector_test.cpp - src/test/app/RCLValidations_test.cpp - src/test/app/ReducedOffer_test.cpp - src/test/app/Regression_test.cpp - src/test/app/SHAMapStore_test.cpp - src/test/app/XChain_test.cpp - src/test/app/SetAuth_test.cpp - src/test/app/SetRegularKey_test.cpp - src/test/app/SetTrust_test.cpp - src/test/app/Taker_test.cpp - src/test/app/TheoreticalQuality_test.cpp - src/test/app/Ticket_test.cpp - src/test/app/Transaction_ordering_test.cpp - src/test/app/TrustAndBalance_test.cpp - src/test/app/TxQ_test.cpp - src/test/app/ValidatorKeys_test.cpp - src/test/app/ValidatorList_test.cpp - src/test/app/ValidatorSite_test.cpp - src/test/app/tx/apply_test.cpp - #[===============================[ - test sources: - subdir: basics - #]===============================] - src/test/basics/Buffer_test.cpp - src/test/basics/DetectCrash_test.cpp - src/test/basics/Expected_test.cpp - src/test/basics/FileUtilities_test.cpp - src/test/basics/IOUAmount_test.cpp - src/test/basics/KeyCache_test.cpp - src/test/basics/Number_test.cpp - src/test/basics/PerfLog_test.cpp - src/test/basics/RangeSet_test.cpp - src/test/basics/scope_test.cpp - src/test/basics/Slice_test.cpp - src/test/basics/StringUtilities_test.cpp - src/test/basics/TaggedCache_test.cpp - src/test/basics/XRPAmount_test.cpp - src/test/basics/base58_test.cpp - src/test/basics/base64_test.cpp - src/test/basics/base_uint_test.cpp - src/test/basics/contract_test.cpp - src/test/basics/FeeUnits_test.cpp - src/test/basics/hardened_hash_test.cpp - src/test/basics/join_test.cpp - src/test/basics/mulDiv_test.cpp - src/test/basics/tagged_integer_test.cpp - #[===============================[ - test sources: - subdir: beast - #]===============================] - src/test/beast/IPEndpoint_test.cpp - src/test/beast/LexicalCast_test.cpp - src/test/beast/SemanticVersion_test.cpp - src/test/beast/aged_associative_container_test.cpp - src/test/beast/beast_CurrentThreadName_test.cpp - src/test/beast/beast_Journal_test.cpp - src/test/beast/beast_PropertyStream_test.cpp - src/test/beast/beast_Zero_test.cpp - src/test/beast/beast_abstract_clock_test.cpp - src/test/beast/beast_basic_seconds_clock_test.cpp - src/test/beast/beast_io_latency_probe_test.cpp - src/test/beast/define_print.cpp - #[===============================[ - test sources: - subdir: conditions - #]===============================] - src/test/conditions/PreimageSha256_test.cpp - #[===============================[ - test sources: - subdir: consensus - #]===============================] - src/test/consensus/ByzantineFailureSim_test.cpp - src/test/consensus/Consensus_test.cpp - src/test/consensus/DistributedValidatorsSim_test.cpp - src/test/consensus/LedgerTiming_test.cpp - src/test/consensus/LedgerTrie_test.cpp - src/test/consensus/NegativeUNL_test.cpp - src/test/consensus/ScaleFreeSim_test.cpp - src/test/consensus/Validations_test.cpp - #[===============================[ - test sources: - subdir: core - #]===============================] - src/test/core/ClosureCounter_test.cpp - src/test/core/Config_test.cpp - src/test/core/Coroutine_test.cpp - src/test/core/CryptoPRNG_test.cpp - src/test/core/JobQueue_test.cpp - src/test/core/SociDB_test.cpp - src/test/core/Workers_test.cpp - #[===============================[ - test sources: - subdir: csf - #]===============================] - src/test/csf/BasicNetwork_test.cpp - src/test/csf/Digraph_test.cpp - src/test/csf/Histogram_test.cpp - src/test/csf/Scheduler_test.cpp - src/test/csf/impl/Sim.cpp - src/test/csf/impl/ledgers.cpp - #[===============================[ - test sources: - subdir: json - #]===============================] - src/test/json/Object_test.cpp - src/test/json/Output_test.cpp - src/test/json/Writer_test.cpp - src/test/json/json_value_test.cpp - #[===============================[ - test sources: - subdir: jtx - #]===============================] - src/test/jtx/Env_test.cpp - src/test/jtx/WSClient_test.cpp - src/test/jtx/impl/Account.cpp - src/test/jtx/impl/AMM.cpp - src/test/jtx/impl/AMMTest.cpp - src/test/jtx/impl/Env.cpp - src/test/jtx/impl/JSONRPCClient.cpp - src/test/jtx/impl/Oracle.cpp - src/test/jtx/impl/TestHelpers.cpp - src/test/jtx/impl/WSClient.cpp - src/test/jtx/impl/acctdelete.cpp - src/test/jtx/impl/account_txn_id.cpp - src/test/jtx/impl/amount.cpp - src/test/jtx/impl/attester.cpp - src/test/jtx/impl/balance.cpp - src/test/jtx/impl/check.cpp - src/test/jtx/impl/delivermin.cpp - src/test/jtx/impl/deposit.cpp - src/test/jtx/impl/did.cpp - src/test/jtx/impl/envconfig.cpp - src/test/jtx/impl/fee.cpp - src/test/jtx/impl/flags.cpp - src/test/jtx/impl/invoice_id.cpp - src/test/jtx/impl/jtx_json.cpp - src/test/jtx/impl/last_ledger_sequence.cpp - src/test/jtx/impl/memo.cpp - src/test/jtx/impl/multisign.cpp - src/test/jtx/impl/offer.cpp - src/test/jtx/impl/owners.cpp - src/test/jtx/impl/paths.cpp - src/test/jtx/impl/pay.cpp - src/test/jtx/impl/quality2.cpp - src/test/jtx/impl/rate.cpp - src/test/jtx/impl/regkey.cpp - src/test/jtx/impl/sendmax.cpp - src/test/jtx/impl/seq.cpp - src/test/jtx/impl/xchain_bridge.cpp - src/test/jtx/impl/sig.cpp - src/test/jtx/impl/tag.cpp - src/test/jtx/impl/ticket.cpp - src/test/jtx/impl/token.cpp - src/test/jtx/impl/trust.cpp - src/test/jtx/impl/txflags.cpp - src/test/jtx/impl/utility.cpp +file(GLOB_RECURSE sources CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/src/xrpld/*.cpp" +) +target_sources(rippled PRIVATE ${sources}) - #[===============================[ - test sources: - subdir: ledger - #]===============================] - src/test/ledger/BookDirs_test.cpp - src/test/ledger/Directory_test.cpp - src/test/ledger/Invariants_test.cpp - src/test/ledger/PaymentSandbox_test.cpp - src/test/ledger/PendingSaves_test.cpp - src/test/ledger/SkipList_test.cpp - src/test/ledger/View_test.cpp - #[===============================[ - test sources: - subdir: net - #]===============================] - src/test/net/DatabaseDownloader_test.cpp - #[===============================[ - test sources: - subdir: nodestore - #]===============================] - src/test/nodestore/Backend_test.cpp - src/test/nodestore/Basics_test.cpp - src/test/nodestore/DatabaseShard_test.cpp - src/test/nodestore/Database_test.cpp - src/test/nodestore/Timing_test.cpp - src/test/nodestore/import_test.cpp - src/test/nodestore/varint_test.cpp - #[===============================[ - test sources: - subdir: overlay - #]===============================] - src/test/overlay/ProtocolVersion_test.cpp - src/test/overlay/cluster_test.cpp - src/test/overlay/short_read_test.cpp - src/test/overlay/compression_test.cpp - src/test/overlay/reduce_relay_test.cpp - src/test/overlay/handshake_test.cpp - src/test/overlay/tx_reduce_relay_test.cpp - #[===============================[ - test sources: - subdir: peerfinder - #]===============================] - src/test/peerfinder/Livecache_test.cpp - src/test/peerfinder/PeerFinder_test.cpp - #[===============================[ - test sources: - subdir: protocol - #]===============================] - src/test/protocol/ApiVersion_test.cpp - src/test/protocol/BuildInfo_test.cpp - src/test/protocol/InnerObjectFormats_test.cpp - src/test/protocol/Issue_test.cpp - src/test/protocol/Hooks_test.cpp - src/test/protocol/Memo_test.cpp - src/test/protocol/MultiApiJson_test.cpp - src/test/protocol/PublicKey_test.cpp - src/test/protocol/Quality_test.cpp - src/test/protocol/STAccount_test.cpp - src/test/protocol/STAmount_test.cpp - src/test/protocol/STObject_test.cpp - src/test/protocol/STTx_test.cpp - src/test/protocol/STValidation_test.cpp - src/test/protocol/SecretKey_test.cpp - src/test/protocol/Seed_test.cpp - src/test/protocol/SeqProxy_test.cpp - src/test/protocol/TER_test.cpp - src/test/protocol/types_test.cpp - #[===============================[ - test sources: - subdir: resource - #]===============================] - src/test/resource/Logic_test.cpp - #[===============================[ - test sources: - subdir: rpc - #]===============================] - src/test/rpc/AccountCurrencies_test.cpp - src/test/rpc/AccountInfo_test.cpp - src/test/rpc/AccountLinesRPC_test.cpp - src/test/rpc/AccountObjects_test.cpp - src/test/rpc/AccountOffers_test.cpp - src/test/rpc/AccountSet_test.cpp - src/test/rpc/AccountTx_test.cpp - src/test/rpc/AmendmentBlocked_test.cpp - src/test/rpc/AMMInfo_test.cpp - src/test/rpc/Book_test.cpp - src/test/rpc/DepositAuthorized_test.cpp - src/test/rpc/DeliveredAmount_test.cpp - src/test/rpc/Feature_test.cpp - src/test/rpc/GatewayBalances_test.cpp - src/test/rpc/GetAggregatePrice_test.cpp - src/test/rpc/GetCounts_test.cpp - src/test/rpc/JSONRPC_test.cpp - src/test/rpc/KeyGeneration_test.cpp - src/test/rpc/LedgerClosed_test.cpp - src/test/rpc/LedgerData_test.cpp - src/test/rpc/LedgerHeader_test.cpp - src/test/rpc/LedgerRPC_test.cpp - src/test/rpc/LedgerRequestRPC_test.cpp - src/test/rpc/ManifestRPC_test.cpp - src/test/rpc/NodeToShardRPC_test.cpp - src/test/rpc/NoRippleCheck_test.cpp - src/test/rpc/NoRipple_test.cpp - src/test/rpc/OwnerInfo_test.cpp - src/test/rpc/Peers_test.cpp - src/test/rpc/ReportingETL_test.cpp - src/test/rpc/Roles_test.cpp - src/test/rpc/RPCCall_test.cpp - src/test/rpc/RPCOverload_test.cpp - src/test/rpc/RobustTransaction_test.cpp - src/test/rpc/ServerInfo_test.cpp - src/test/rpc/ShardArchiveHandler_test.cpp - src/test/rpc/Status_test.cpp - src/test/rpc/Subscribe_test.cpp - src/test/rpc/Transaction_test.cpp - src/test/rpc/TransactionEntry_test.cpp - src/test/rpc/TransactionHistory_test.cpp - src/test/rpc/ValidatorInfo_test.cpp - src/test/rpc/ValidatorRPC_test.cpp - src/test/rpc/Version_test.cpp - src/test/rpc/Handler_test.cpp - #[===============================[ - test sources: - subdir: server - #]===============================] - src/test/server/ServerStatus_test.cpp - src/test/server/Server_test.cpp - #[===============================[ - test sources: - subdir: shamap - #]===============================] - src/test/shamap/FetchPack_test.cpp - src/test/shamap/SHAMapSync_test.cpp - src/test/shamap/SHAMap_test.cpp - #[===============================[ - test sources: - subdir: unit_test - #]===============================] - src/test/unit_test/multi_runner.cpp) -endif () #tests +if(tests) + file(GLOB_RECURSE sources CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/src/test/*.cpp" + ) + target_sources(rippled PRIVATE ${sources}) +endif() -target_link_libraries (rippled +target_link_libraries(rippled Ripple::boost Ripple::opts Ripple::libs - Ripple::xrpl_core - ) -exclude_if_included (rippled) + xrpl.libxrpl +) +exclude_if_included(rippled) # define a macro for tests that might need to # be exluded or run differently in CI environment -if (is_ci) +if(is_ci) target_compile_definitions(rippled PRIVATE RIPPLED_RUNNING_IN_CI) endif () if(reporting) -set_target_properties(rippled PROPERTIES OUTPUT_NAME rippled-reporting) -get_target_property(BIN_NAME rippled OUTPUT_NAME) -message(STATUS "Reporting mode build: rippled renamed ${BIN_NAME}") + set(suffix -reporting) + set_target_properties(rippled PROPERTIES OUTPUT_NAME rippled-reporting) + get_target_property(BIN_NAME rippled OUTPUT_NAME) + message(STATUS "Reporting mode build: rippled renamed ${BIN_NAME}") target_compile_definitions(rippled PRIVATE RIPPLED_REPORTING) endif() # any files that don't play well with unity should be added here -if (tests) +if(tests) set_source_files_properties( # these two seem to produce conflicts in beast teardown template methods src/test/rpc/ValidatorRPC_test.cpp src/test/rpc/ShardArchiveHandler_test.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION TRUE) -endif () #tests +endif() diff --git a/Builds/CMake/RippledDocs.cmake b/Builds/CMake/RippledDocs.cmake index e7c42942a77..a9b8b283bf0 100644 --- a/Builds/CMake/RippledDocs.cmake +++ b/Builds/CMake/RippledDocs.cmake @@ -25,8 +25,7 @@ file(GLOB_RECURSE doxygen_input src/ripple/*.cpp src/ripple/*.md src/test/*.h - src/test/*.md - Builds/*/README.md) + src/test/*.md) list(APPEND doxygen_input README.md RELEASENOTES.md diff --git a/Builds/CMake/RippledInstall.cmake b/Builds/CMake/RippledInstall.cmake index b9dd44cfc2c..d92cecc24eb 100644 --- a/Builds/CMake/RippledInstall.cmake +++ b/Builds/CMake/RippledInstall.cmake @@ -8,14 +8,19 @@ install ( opts ripple_syslibs ripple_boost - xrpl_core xrpl.libpb + xrpl.libxrpl EXPORT RippleExports LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin INCLUDES DESTINATION include) +install( + DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/xrpl" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" +) + install (EXPORT RippleExports FILE RippleTargets.cmake NAMESPACE Ripple:: @@ -31,7 +36,7 @@ if (is_root_project) set_target_properties(rippled PROPERTIES INSTALL_RPATH_USE_LINK_PATH ON) install ( FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Builds/CMake/RippleConfig.cmake + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/RippleConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/RippleConfigVersion.cmake DESTINATION lib/cmake/ripple) # sample configs should not overwrite existing files @@ -49,3 +54,17 @@ if (is_root_project) copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/validators-example.txt\" etc validators.txt) ") endif () + +if(NOT WIN32) + install( + CODE "file(CREATE_LINK xrpl \ + \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/ripple SYMBOLIC)" + ) +endif() + +if(NOT WIN32) + install( + CODE "file(CREATE_LINK rippled${suffix} \ + \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/xrpld${suffix} SYMBOLIC)" + ) +endif() diff --git a/Builds/CMake/RippledMultiConfig.cmake b/Builds/CMake/RippledMultiConfig.cmake deleted file mode 100644 index 6df48a3d964..00000000000 --- a/Builds/CMake/RippledMultiConfig.cmake +++ /dev/null @@ -1,39 +0,0 @@ -#[===================================================================[ - multiconfig misc -#]===================================================================] - -if (is_multiconfig) - # This code finds all source files in the src subdirectory for inclusion - # in the IDE file tree as non-compiled sources. Since this file list will - # have some overlap with files we have already added to our targets to - # be compiled, we explicitly remove any of these target source files from - # this list. - file (GLOB_RECURSE all_sources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - CONFIGURE_DEPENDS - src/*.* Builds/*.md docs/*.md src/*.md Builds/*.cmake) - file(GLOB md_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} CONFIGURE_DEPENDS - *.md) - LIST(APPEND all_sources ${md_files}) - foreach (_target secp256k1::secp256k1 ed25519::ed25519 xrpl_core rippled) - get_target_property (_type ${_target} TYPE) - if(_type STREQUAL "INTERFACE_LIBRARY") - continue() - endif() - get_target_property (_src ${_target} SOURCES) - list (REMOVE_ITEM all_sources ${_src}) - endforeach () - target_sources (rippled PRIVATE ${all_sources}) - set_property ( - SOURCE ${all_sources} - APPEND - PROPERTY HEADER_FILE_ONLY true) - if (MSVC) - set_property( - DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - PROPERTY VS_STARTUP_PROJECT rippled) - endif () - - group_sources(src) - group_sources(docs) - group_sources(Builds) -endif () diff --git a/Builds/CMake/RippledVersion.cmake b/Builds/CMake/RippledVersion.cmake index 936852af58b..fda3cb6ff7b 100644 --- a/Builds/CMake/RippledVersion.cmake +++ b/Builds/CMake/RippledVersion.cmake @@ -2,14 +2,14 @@ read version from source #]===================================================================] -file (STRINGS src/ripple/protocol/impl/BuildInfo.cpp BUILD_INFO) -foreach (line_ ${BUILD_INFO}) - if (line_ MATCHES "versionString[ ]*=[ ]*\"(.+)\"") - set (rippled_version ${CMAKE_MATCH_1}) - endif () -endforeach () -if (rippled_version) - message (STATUS "rippled version: ${rippled_version}") -else () - message (FATAL_ERROR "unable to determine rippled version") -endif () +file(STRINGS src/libxrpl/protocol/BuildInfo.cpp BUILD_INFO) +foreach(line_ ${BUILD_INFO}) + if(line_ MATCHES "versionString[ ]*=[ ]*\"(.+)\"") + set(rippled_version ${CMAKE_MATCH_1}) + endif() +endforeach() +if(rippled_version) + message(STATUS "rippled version: ${rippled_version}") +else() + message(FATAL_ERROR "unable to determine rippled version") +endif() diff --git a/Builds/levelization/levelization.sh b/Builds/levelization/levelization.sh index 34487f7464a..f8f21bb9d23 100755 --- a/Builds/levelization/levelization.sh +++ b/Builds/levelization/levelization.sh @@ -18,7 +18,7 @@ mkdir results includes="$( pwd )/results/rawincludes.txt" pushd ../.. echo Raw includes: -grep -r '#include.*/.*\.h' src/ripple/ src/test/ | \ +grep -r '#include.*/.*\.h' include src | \ grep -v boost | tee ${includes} popd pushd results diff --git a/CMakeLists.txt b/CMakeLists.txt index dcb493e5293..a69583f9cbf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,9 +9,9 @@ endif() # Fix "unrecognized escape" issues when passing CMAKE_MODULE_PATH on Windows. file(TO_CMAKE_PATH "${CMAKE_MODULE_PATH}" CMAKE_MODULE_PATH) -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/Builds/CMake") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -project(rippled) +project(xrpl) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -81,7 +81,6 @@ find_package(lz4 REQUIRED) find_package(LibArchive REQUIRED) find_package(SOCI REQUIRED) find_package(SQLite3 REQUIRED) -find_package(Snappy REQUIRED) option(rocksdb "Enable RocksDB" ON) if(rocksdb) @@ -129,9 +128,7 @@ if(coverage) include(RippledCov) endif() -### - +set(PROJECT_EXPORT_SET RippleExports) include(RippledCore) include(RippledInstall) -include(RippledMultiConfig) include(RippledValidatorKeys) diff --git a/conanfile.py b/conanfile.py index 78eab272a55..68b0a7cd405 100644 --- a/conanfile.py +++ b/conanfile.py @@ -29,10 +29,9 @@ class Xrpl(ConanFile): 'libarchive/3.6.2', 'nudb/2.0.8', 'openssl/1.1.1u', - 'snappy/1.1.10', 'soci/4.0.3', - 'zlib/1.2.13', 'xxhash/0.8.2', + 'zlib/1.2.13', ] tool_requires = [ @@ -91,7 +90,7 @@ class Xrpl(ConanFile): } def set_version(self): - path = f'{self.recipe_folder}/src/ripple/protocol/impl/BuildInfo.cpp' + path = f'{self.recipe_folder}/src/libxrpl/protocol/BuildInfo.cpp' regex = r'versionString\s?=\s?\"(.*)\"' with open(path, 'r') as file: matches = (re.search(regex, line) for line in file) @@ -117,10 +116,11 @@ def requirements(self): exports_sources = ( 'CMakeLists.txt', - 'Builds/*', 'bin/getRippledInfo', 'cfg/*', + 'cmake/*', 'external/*', + 'include/*', 'src/*', ) @@ -158,7 +158,7 @@ def package(self): def package_info(self): libxrpl = self.cpp_info.components['libxrpl'] libxrpl.libs = [ - 'xrpl_core', + 'xrpl', 'xrpl.libpb', 'ed25519', 'secp256k1', @@ -175,7 +175,6 @@ def package_info(self): 'nudb::nudb', 'openssl::crypto', 'protobuf::libprotobuf', - 'snappy::snappy', 'soci::soci', 'sqlite3::sqlite', 'xxhash::xxhash', From f6879da6c9ab27d2b01a584d69f71ce7cf82eee3 Mon Sep 17 00:00:00 2001 From: John Freeman Date: Fri, 29 Mar 2024 20:27:21 -0500 Subject: [PATCH 14/82] Add bin/physical.sh (#4997) --- bin/physical.sh | 218 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100755 bin/physical.sh diff --git a/bin/physical.sh b/bin/physical.sh new file mode 100755 index 00000000000..c2c5aad68db --- /dev/null +++ b/bin/physical.sh @@ -0,0 +1,218 @@ +#!/bin/bash + +set -o errexit + +marker_base=985c80fbc6131f3a8cedd0da7e8af98dfceb13c7 +marker_commit=${1:-${marker_base}} + +if [ $(git merge-base ${marker_commit} ${marker_base}) != ${marker_base} ]; then + echo "first marker commit not an ancestor: ${marker_commit}" + exit 1 +fi + +if [ $(git merge-base ${marker_commit} HEAD) != $(git rev-parse --verify ${marker_commit}) ]; then + echo "given marker commit not an ancestor: ${marker_commit}" + exit 1 +fi + +if [ -e Builds/CMake ]; then + echo move CMake + git mv Builds/CMake cmake + git add --update . + git commit -m 'Move CMake directory' --author 'Pretty Printer ' +fi + +if [ -e src/ripple ]; then + + echo move protocol buffers + mkdir -p include/xrpl + if [ -e src/ripple/proto ]; then + git mv src/ripple/proto include/xrpl + fi + + extract_list() { + git show ${marker_commit}:Builds/CMake/RippledCore.cmake | \ + awk "/END ${1}/ { p = 0 } p && /src\/ripple/; /BEGIN ${1}/ { p = 1 }" | \ + sed -e 's#src/ripple/##' -e 's#[^a-z]\+$##' + } + + move_files() { + oldroot="$1"; shift + newroot="$1"; shift + detail="$1"; shift + files=("$@") + for file in ${files[@]}; do + if [ ! -e ${oldroot}/${file} ]; then + continue + fi + dir=$(dirname ${file}) + if [ $(basename ${dir}) == 'details' ]; then + dir=$(dirname ${dir}) + fi + if [ $(basename ${dir}) == 'impl' ]; then + dir="$(dirname ${dir})/${detail}" + fi + mkdir -p ${newroot}/${dir} + git mv ${oldroot}/${file} ${newroot}/${dir} + done + } + + echo move libxrpl headers + files=$(extract_list 'LIBXRPL HEADERS') + files+=( + basics/SlabAllocator.h + + beast/asio/io_latency_probe.h + beast/container/aged_container.h + beast/container/aged_container_utility.h + beast/container/aged_map.h + beast/container/aged_multimap.h + beast/container/aged_multiset.h + beast/container/aged_set.h + beast/container/aged_unordered_map.h + beast/container/aged_unordered_multimap.h + beast/container/aged_unordered_multiset.h + beast/container/aged_unordered_set.h + beast/container/detail/aged_associative_container.h + beast/container/detail/aged_container_iterator.h + beast/container/detail/aged_ordered_container.h + beast/container/detail/aged_unordered_container.h + beast/container/detail/empty_base_optimization.h + beast/core/LockFreeStack.h + beast/insight/Collector.h + beast/insight/Counter.h + beast/insight/CounterImpl.h + beast/insight/Event.h + beast/insight/EventImpl.h + beast/insight/Gauge.h + beast/insight/GaugeImpl.h + beast/insight/Group.h + beast/insight/Groups.h + beast/insight/Hook.h + beast/insight/HookImpl.h + beast/insight/Insight.h + beast/insight/Meter.h + beast/insight/MeterImpl.h + beast/insight/NullCollector.h + beast/insight/StatsDCollector.h + beast/test/fail_counter.h + beast/test/fail_stream.h + beast/test/pipe_stream.h + beast/test/sig_wait.h + beast/test/string_iostream.h + beast/test/string_istream.h + beast/test/string_ostream.h + beast/test/test_allocator.h + beast/test/yield_to.h + beast/utility/hash_pair.h + beast/utility/maybe_const.h + beast/utility/temp_dir.h + + # included by only json/impl/json_assert.h + json/json_errors.h + + protocol/PayChan.h + protocol/RippleLedgerHash.h + protocol/messages.h + protocol/st.h + ) + files+=( + basics/README.md + crypto/README.md + json/README.md + protocol/README.md + resource/README.md + ) + move_files src/ripple include/xrpl detail ${files[@]} + + echo move libxrpl sources + files=$(extract_list 'LIBXRPL SOURCES') + move_files src/ripple src/libxrpl "" ${files[@]} + + echo check leftovers + dirs=$(cd include/xrpl; ls -d */) + dirs=$(cd src/ripple; ls -d ${dirs} 2>/dev/null || true) + files="$(cd src/ripple; find ${dirs} -type f)" + if [ -n "${files}" ]; then + echo "leftover files:" + echo ${files} + exit + fi + + echo remove empty directories + empty_dirs="$(cd src/ripple; find ${dirs} -depth -type d)" + for dir in ${empty_dirs[@]}; do + if [ -e ${dir} ]; then + rmdir ${dir} + fi + done + + echo move xrpld sources + files=$( + extract_list 'XRPLD SOURCES' + cd src/ripple + find * -regex '.*\.\(h\|ipp\|md\|pu\|uml\|png\)' + ) + move_files src/ripple src/xrpld detail ${files[@]} + + files="$(cd src/ripple; find . -type f)" + if [ -n "${files}" ]; then + echo "leftover files:" + echo ${files} + exit + fi + +fi + +rm -rf src/ripple + +echo rename .hpp to .h +find include src -name '*.hpp' -exec bash -c 'f="{}"; git mv "${f}" "${f%hpp}h"' \; + +echo move PerfLog.h +if [ -e include/xrpl/basics/PerfLog.h ]; then + git mv include/xrpl/basics/PerfLog.h src/xrpld/perflog +fi + +# Make sure all protobuf includes have the correct prefix. +protobuf_replace='s:^#include\s*["<].*org/xrpl\([^">]\+\)[">]:#include :' +# Make sure first-party includes use angle brackets and .h extension. +ripple_replace='s:include\s*["<]ripple/\(.*\)\.h\(pp\)\?[">]:include :' +beast_replace='s:include\s*:#include :" \ + -e "s:^#include ' +find include src -type f \( -name '*.cpp' -o -name '*.h' -o -name '*.ipp' \) -exec clang-format-10 -i {} + +git add --update . +git commit -m 'Rewrite includes' --author 'Pretty Printer ' +./Builds/levelization/levelization.sh +git add --update . +git commit -m 'Recompute loops' --author 'Pretty Printer ' From 2e902dee53aab2a8f27f32971047bb81e022f94f Mon Sep 17 00:00:00 2001 From: Pretty Printer Date: Thu, 20 Jun 2024 09:21:59 -0500 Subject: [PATCH 15/82] Move CMake directory (#4997) --- {Builds/CMake => cmake}/CMakeFuncs.cmake | 0 {Builds/CMake => cmake}/CodeCoverage.cmake | 0 {Builds/CMake => cmake}/RippleConfig.cmake | 0 {Builds/CMake => cmake}/RippledCompiler.cmake | 0 {Builds/CMake => cmake}/RippledCore.cmake | 0 {Builds/CMake => cmake}/RippledCov.cmake | 0 {Builds/CMake => cmake}/RippledDocs.cmake | 0 {Builds/CMake => cmake}/RippledInstall.cmake | 0 {Builds/CMake => cmake}/RippledInterface.cmake | 0 {Builds/CMake => cmake}/RippledSanity.cmake | 0 {Builds/CMake => cmake}/RippledSettings.cmake | 0 {Builds/CMake => cmake}/RippledValidatorKeys.cmake | 0 {Builds/CMake => cmake}/RippledVersion.cmake | 0 {Builds/CMake => cmake}/deps/Boost.cmake | 0 {Builds/CMake => cmake}/target_protobuf_sources.cmake | 0 15 files changed, 0 insertions(+), 0 deletions(-) rename {Builds/CMake => cmake}/CMakeFuncs.cmake (100%) rename {Builds/CMake => cmake}/CodeCoverage.cmake (100%) rename {Builds/CMake => cmake}/RippleConfig.cmake (100%) rename {Builds/CMake => cmake}/RippledCompiler.cmake (100%) rename {Builds/CMake => cmake}/RippledCore.cmake (100%) rename {Builds/CMake => cmake}/RippledCov.cmake (100%) rename {Builds/CMake => cmake}/RippledDocs.cmake (100%) rename {Builds/CMake => cmake}/RippledInstall.cmake (100%) rename {Builds/CMake => cmake}/RippledInterface.cmake (100%) rename {Builds/CMake => cmake}/RippledSanity.cmake (100%) rename {Builds/CMake => cmake}/RippledSettings.cmake (100%) rename {Builds/CMake => cmake}/RippledValidatorKeys.cmake (100%) rename {Builds/CMake => cmake}/RippledVersion.cmake (100%) rename {Builds/CMake => cmake}/deps/Boost.cmake (100%) rename {Builds/CMake => cmake}/target_protobuf_sources.cmake (100%) diff --git a/Builds/CMake/CMakeFuncs.cmake b/cmake/CMakeFuncs.cmake similarity index 100% rename from Builds/CMake/CMakeFuncs.cmake rename to cmake/CMakeFuncs.cmake diff --git a/Builds/CMake/CodeCoverage.cmake b/cmake/CodeCoverage.cmake similarity index 100% rename from Builds/CMake/CodeCoverage.cmake rename to cmake/CodeCoverage.cmake diff --git a/Builds/CMake/RippleConfig.cmake b/cmake/RippleConfig.cmake similarity index 100% rename from Builds/CMake/RippleConfig.cmake rename to cmake/RippleConfig.cmake diff --git a/Builds/CMake/RippledCompiler.cmake b/cmake/RippledCompiler.cmake similarity index 100% rename from Builds/CMake/RippledCompiler.cmake rename to cmake/RippledCompiler.cmake diff --git a/Builds/CMake/RippledCore.cmake b/cmake/RippledCore.cmake similarity index 100% rename from Builds/CMake/RippledCore.cmake rename to cmake/RippledCore.cmake diff --git a/Builds/CMake/RippledCov.cmake b/cmake/RippledCov.cmake similarity index 100% rename from Builds/CMake/RippledCov.cmake rename to cmake/RippledCov.cmake diff --git a/Builds/CMake/RippledDocs.cmake b/cmake/RippledDocs.cmake similarity index 100% rename from Builds/CMake/RippledDocs.cmake rename to cmake/RippledDocs.cmake diff --git a/Builds/CMake/RippledInstall.cmake b/cmake/RippledInstall.cmake similarity index 100% rename from Builds/CMake/RippledInstall.cmake rename to cmake/RippledInstall.cmake diff --git a/Builds/CMake/RippledInterface.cmake b/cmake/RippledInterface.cmake similarity index 100% rename from Builds/CMake/RippledInterface.cmake rename to cmake/RippledInterface.cmake diff --git a/Builds/CMake/RippledSanity.cmake b/cmake/RippledSanity.cmake similarity index 100% rename from Builds/CMake/RippledSanity.cmake rename to cmake/RippledSanity.cmake diff --git a/Builds/CMake/RippledSettings.cmake b/cmake/RippledSettings.cmake similarity index 100% rename from Builds/CMake/RippledSettings.cmake rename to cmake/RippledSettings.cmake diff --git a/Builds/CMake/RippledValidatorKeys.cmake b/cmake/RippledValidatorKeys.cmake similarity index 100% rename from Builds/CMake/RippledValidatorKeys.cmake rename to cmake/RippledValidatorKeys.cmake diff --git a/Builds/CMake/RippledVersion.cmake b/cmake/RippledVersion.cmake similarity index 100% rename from Builds/CMake/RippledVersion.cmake rename to cmake/RippledVersion.cmake diff --git a/Builds/CMake/deps/Boost.cmake b/cmake/deps/Boost.cmake similarity index 100% rename from Builds/CMake/deps/Boost.cmake rename to cmake/deps/Boost.cmake diff --git a/Builds/CMake/target_protobuf_sources.cmake b/cmake/target_protobuf_sources.cmake similarity index 100% rename from Builds/CMake/target_protobuf_sources.cmake rename to cmake/target_protobuf_sources.cmake From e416ee72ca26fa0c09d2aee1b68bdfb2b7046eed Mon Sep 17 00:00:00 2001 From: Pretty Printer Date: Thu, 20 Jun 2024 09:22:15 -0500 Subject: [PATCH 16/82] Rearrange sources (#4997) --- {src/ripple => include/xrpl}/basics/Archive.h | 0 {src/ripple => include/xrpl}/basics/BasicConfig.h | 0 {src/ripple => include/xrpl}/basics/Blob.h | 0 {src/ripple => include/xrpl}/basics/Buffer.h | 0 {src/ripple => include/xrpl}/basics/ByteUtilities.h | 0 .../xrpl}/basics/CompressionAlgorithms.h | 0 {src/ripple => include/xrpl}/basics/CountedObject.h | 0 .../ripple => include/xrpl}/basics/DecayingSample.h | 0 {src/ripple => include/xrpl}/basics/Expected.h | 0 {src/ripple => include/xrpl}/basics/FeeUnits.h | 0 {src/ripple => include/xrpl}/basics/FileUtilities.h | 0 {src/ripple => include/xrpl}/basics/IOUAmount.h | 0 {src/ripple => include/xrpl}/basics/KeyCache.h | 0 {src/ripple => include/xrpl}/basics/LocalValue.h | 0 {src/ripple => include/xrpl}/basics/Log.h | 0 {src/ripple => include/xrpl}/basics/MathUtilities.h | 0 {src/ripple => include/xrpl}/basics/Number.h | 0 {src/ripple => include/xrpl}/basics/README.md | 0 {src/ripple => include/xrpl}/basics/RangeSet.h | 0 {src/ripple => include/xrpl}/basics/Resolver.h | 0 {src/ripple => include/xrpl}/basics/ResolverAsio.h | 0 {src/ripple => include/xrpl}/basics/SHAMapHash.h | 0 {src/ripple => include/xrpl}/basics/SlabAllocator.h | 0 {src/ripple => include/xrpl}/basics/Slice.h | 0 .../xrpl}/basics/StringUtilities.h | 0 {src/ripple => include/xrpl}/basics/TaggedCache.h | 0 .../xrpl}/basics/ThreadSafetyAnalysis.h | 0 {src/ripple => include/xrpl}/basics/ToString.h | 0 .../xrpl}/basics/UnorderedContainers.h | 0 {src/ripple => include/xrpl}/basics/UptimeClock.h | 0 {src/ripple => include/xrpl}/basics/XRPAmount.h | 0 {src/ripple => include/xrpl}/basics/algorithm.h | 0 {src/ripple => include/xrpl}/basics/base64.h | 0 {src/ripple => include/xrpl}/basics/base_uint.h | 0 {src/ripple => include/xrpl}/basics/chrono.h | 0 {src/ripple => include/xrpl}/basics/comparators.h | 0 {src/ripple => include/xrpl}/basics/contract.h | 0 {src/ripple => include/xrpl}/basics/hardened_hash.h | 0 {src/ripple => include/xrpl}/basics/join.h | 0 .../xrpl}/basics/make_SSLContext.h | 0 {src/ripple => include/xrpl}/basics/mulDiv.h | 0 .../xrpl}/basics/partitioned_unordered_map.h | 0 {src/ripple => include/xrpl}/basics/random.h | 0 {src/ripple => include/xrpl}/basics/safe_cast.h | 0 {src/ripple => include/xrpl}/basics/scope.h | 0 {src/ripple => include/xrpl}/basics/spinlock.h | 0 {src/ripple => include/xrpl}/basics/strHex.h | 0 .../ripple => include/xrpl}/basics/tagged_integer.h | 0 .../xrpl}/beast/asio/io_latency_probe.h | 0 .../xrpl}/beast/clock/abstract_clock.h | 0 .../xrpl}/beast/clock/basic_seconds_clock.h | 0 .../xrpl}/beast/clock/manual_clock.h | 0 .../xrpl}/beast/container/aged_container.h | 0 .../xrpl}/beast/container/aged_container_utility.h | 0 .../xrpl}/beast/container/aged_map.h | 0 .../xrpl}/beast/container/aged_multimap.h | 0 .../xrpl}/beast/container/aged_multiset.h | 0 .../xrpl}/beast/container/aged_set.h | 0 .../xrpl}/beast/container/aged_unordered_map.h | 0 .../xrpl}/beast/container/aged_unordered_multimap.h | 0 .../xrpl}/beast/container/aged_unordered_multiset.h | 0 .../xrpl}/beast/container/aged_unordered_set.h | 0 .../container/detail/aged_associative_container.h | 0 .../container/detail/aged_container_iterator.h | 0 .../beast/container/detail/aged_ordered_container.h | 0 .../container/detail/aged_unordered_container.h | 0 .../container/detail/empty_base_optimization.h | 0 .../xrpl}/beast/core/CurrentThreadName.h | 0 .../xrpl}/beast/core/LexicalCast.h | 0 {src/ripple => include/xrpl}/beast/core/List.h | 0 .../xrpl}/beast/core/LockFreeStack.h | 0 .../xrpl}/beast/core/SemanticVersion.h | 0 .../xrpl}/beast/hash/hash_append.h | 0 {src/ripple => include/xrpl}/beast/hash/uhash.h | 0 {src/ripple => include/xrpl}/beast/hash/xxhasher.h | 0 .../xrpl}/beast/insight/Collector.h | 0 .../ripple => include/xrpl}/beast/insight/Counter.h | 0 .../xrpl}/beast/insight/CounterImpl.h | 0 {src/ripple => include/xrpl}/beast/insight/Event.h | 0 .../xrpl}/beast/insight/EventImpl.h | 0 {src/ripple => include/xrpl}/beast/insight/Gauge.h | 0 .../xrpl}/beast/insight/GaugeImpl.h | 0 {src/ripple => include/xrpl}/beast/insight/Group.h | 0 {src/ripple => include/xrpl}/beast/insight/Groups.h | 0 {src/ripple => include/xrpl}/beast/insight/Hook.h | 0 .../xrpl}/beast/insight/HookImpl.h | 0 .../ripple => include/xrpl}/beast/insight/Insight.h | 0 {src/ripple => include/xrpl}/beast/insight/Meter.h | 0 .../xrpl}/beast/insight/MeterImpl.h | 0 .../xrpl}/beast/insight/NullCollector.h | 0 .../xrpl}/beast/insight/StatsDCollector.h | 0 {src/ripple => include/xrpl}/beast/net/IPAddress.h | 0 .../xrpl}/beast/net/IPAddressConversion.h | 0 .../ripple => include/xrpl}/beast/net/IPAddressV4.h | 0 .../ripple => include/xrpl}/beast/net/IPAddressV6.h | 0 {src/ripple => include/xrpl}/beast/net/IPEndpoint.h | 0 {src/ripple => include/xrpl}/beast/rfc2616.h | 0 .../xrpl}/beast/test/fail_counter.h | 0 .../xrpl}/beast/test/fail_stream.h | 0 .../xrpl}/beast/test/pipe_stream.h | 0 {src/ripple => include/xrpl}/beast/test/sig_wait.h | 0 .../xrpl}/beast/test/string_iostream.h | 0 .../xrpl}/beast/test/string_istream.h | 0 .../xrpl}/beast/test/string_ostream.h | 0 .../xrpl}/beast/test/test_allocator.h | 0 {src/ripple => include/xrpl}/beast/test/yield_to.h | 0 {src/ripple => include/xrpl}/beast/type_name.h | 0 {src/ripple => include/xrpl}/beast/unit_test.h | 0 .../xrpl}/beast/unit_test/amount.h | 0 .../xrpl}/beast/unit_test/detail/const_container.h | 0 .../xrpl}/beast/unit_test/dstream.h | 0 .../xrpl}/beast/unit_test/global_suites.h | 0 .../ripple => include/xrpl}/beast/unit_test/match.h | 0 .../xrpl}/beast/unit_test/recorder.h | 0 .../xrpl}/beast/unit_test/reporter.h | 0 .../xrpl}/beast/unit_test/results.h | 0 .../xrpl}/beast/unit_test/runner.h | 0 .../ripple => include/xrpl}/beast/unit_test/suite.h | 0 .../xrpl}/beast/unit_test/suite_info.h | 0 .../xrpl}/beast/unit_test/suite_list.h | 0 .../xrpl}/beast/unit_test/thread.h | 0 .../ripple => include/xrpl}/beast/utility/Journal.h | 0 .../xrpl}/beast/utility/PropertyStream.h | 0 .../xrpl}/beast/utility/WrappedSink.h | 0 {src/ripple => include/xrpl}/beast/utility/Zero.h | 0 .../xrpl}/beast/utility/hash_pair.h | 0 .../xrpl}/beast/utility/maybe_const.h | 0 .../ripple => include/xrpl}/beast/utility/rngfill.h | 0 .../xrpl}/beast/utility/temp_dir.h | 0 .../xrpl}/beast/xor_shift_engine.h | 0 {src/ripple => include/xrpl}/crypto/README.md | 0 {src/ripple => include/xrpl}/crypto/RFC1751.h | 0 {src/ripple => include/xrpl}/crypto/csprng.h | 0 {src/ripple => include/xrpl}/crypto/secure_erase.h | 0 .../xrpl}/json/JsonPropertyStream.h | 0 {src/ripple => include/xrpl}/json/Object.h | 0 {src/ripple => include/xrpl}/json/Output.h | 0 {src/ripple => include/xrpl}/json/README.md | 0 {src/ripple => include/xrpl}/json/Writer.h | 0 .../impl => include/xrpl/json/detail}/json_assert.h | 0 {src/ripple => include/xrpl}/json/json_errors.h | 0 {src/ripple => include/xrpl}/json/json_forwards.h | 0 {src/ripple => include/xrpl}/json/json_reader.h | 0 {src/ripple => include/xrpl}/json/json_value.h | 0 {src/ripple => include/xrpl}/json/json_writer.h | 0 {src/ripple => include/xrpl}/json/to_string.h | 0 {src/ripple => include/xrpl}/proto/README.md | 0 .../xrpl}/proto/org/xrpl/rpc/v1/README.md | 0 .../xrpl}/proto/org/xrpl/rpc/v1/get_ledger.proto | 0 .../proto/org/xrpl/rpc/v1/get_ledger_data.proto | 0 .../proto/org/xrpl/rpc/v1/get_ledger_diff.proto | 0 .../proto/org/xrpl/rpc/v1/get_ledger_entry.proto | 0 .../xrpl}/proto/org/xrpl/rpc/v1/ledger.proto | 0 .../xrpl}/proto/org/xrpl/rpc/v1/xrp_ledger.proto | 0 {src/ripple => include/xrpl}/proto/ripple.proto | 0 {src/ripple => include/xrpl}/protocol/AMMCore.h | 0 {src/ripple => include/xrpl}/protocol/AccountID.h | 0 .../xrpl}/protocol/AmountConversions.h | 0 {src/ripple => include/xrpl}/protocol/ApiVersion.h | 0 {src/ripple => include/xrpl}/protocol/Book.h | 0 {src/ripple => include/xrpl}/protocol/BuildInfo.h | 0 {src/ripple => include/xrpl}/protocol/ErrorCodes.h | 0 {src/ripple => include/xrpl}/protocol/Feature.h | 0 {src/ripple => include/xrpl}/protocol/Fees.h | 0 {src/ripple => include/xrpl}/protocol/HashPrefix.h | 0 {src/ripple => include/xrpl}/protocol/Indexes.h | 0 .../xrpl}/protocol/InnerObjectFormats.h | 0 {src/ripple => include/xrpl}/protocol/Issue.h | 0 {src/ripple => include/xrpl}/protocol/KeyType.h | 0 {src/ripple => include/xrpl}/protocol/Keylet.h | 0 .../ripple => include/xrpl}/protocol/KnownFormats.h | 0 .../xrpl}/protocol/LedgerFormats.h | 0 .../ripple => include/xrpl}/protocol/LedgerHeader.h | 0 .../ripple => include/xrpl}/protocol/MultiApiJson.h | 0 .../xrpl}/protocol/NFTSyntheticSerializer.h | 0 {src/ripple => include/xrpl}/protocol/NFTokenID.h | 0 .../xrpl}/protocol/NFTokenOfferID.h | 0 {src/ripple => include/xrpl}/protocol/PayChan.h | 0 {src/ripple => include/xrpl}/protocol/Protocol.h | 0 {src/ripple => include/xrpl}/protocol/PublicKey.h | 0 {src/ripple => include/xrpl}/protocol/Quality.h | 0 .../xrpl}/protocol/QualityFunction.h | 0 {src/ripple => include/xrpl}/protocol/README.md | 0 {src/ripple => include/xrpl}/protocol/RPCErr.h | 0 {src/ripple => include/xrpl}/protocol/Rate.h | 0 .../xrpl}/protocol/RippleLedgerHash.h | 0 {src/ripple => include/xrpl}/protocol/Rules.h | 0 {src/ripple => include/xrpl}/protocol/SField.h | 0 {src/ripple => include/xrpl}/protocol/SOTemplate.h | 0 {src/ripple => include/xrpl}/protocol/STAccount.h | 0 {src/ripple => include/xrpl}/protocol/STAmount.h | 0 {src/ripple => include/xrpl}/protocol/STArray.h | 0 {src/ripple => include/xrpl}/protocol/STBase.h | 0 {src/ripple => include/xrpl}/protocol/STBitString.h | 0 {src/ripple => include/xrpl}/protocol/STBlob.h | 0 {src/ripple => include/xrpl}/protocol/STCurrency.h | 0 {src/ripple => include/xrpl}/protocol/STExchange.h | 0 {src/ripple => include/xrpl}/protocol/STInteger.h | 0 {src/ripple => include/xrpl}/protocol/STIssue.h | 0 .../xrpl}/protocol/STLedgerEntry.h | 0 {src/ripple => include/xrpl}/protocol/STObject.h | 0 .../ripple => include/xrpl}/protocol/STParsedJSON.h | 0 {src/ripple => include/xrpl}/protocol/STPathSet.h | 0 {src/ripple => include/xrpl}/protocol/STTx.h | 0 .../ripple => include/xrpl}/protocol/STValidation.h | 0 {src/ripple => include/xrpl}/protocol/STVector256.h | 0 .../xrpl}/protocol/STXChainBridge.h | 0 {src/ripple => include/xrpl}/protocol/SecretKey.h | 0 {src/ripple => include/xrpl}/protocol/Seed.h | 0 {src/ripple => include/xrpl}/protocol/SeqProxy.h | 0 {src/ripple => include/xrpl}/protocol/Serializer.h | 0 {src/ripple => include/xrpl}/protocol/Sign.h | 0 .../xrpl}/protocol/SystemParameters.h | 0 {src/ripple => include/xrpl}/protocol/TER.h | 0 {src/ripple => include/xrpl}/protocol/TxFlags.h | 0 {src/ripple => include/xrpl}/protocol/TxFormats.h | 0 {src/ripple => include/xrpl}/protocol/TxMeta.h | 0 {src/ripple => include/xrpl}/protocol/UintTypes.h | 0 .../xrpl}/protocol/XChainAttestations.h | 0 .../impl => include/xrpl/protocol/detail}/STVar.h | 0 .../xrpl/protocol/detail}/b58_utils.h | 0 .../xrpl/protocol/detail}/secp256k1.h | 0 .../xrpl/protocol/detail}/token_errors.h | 0 {src/ripple => include/xrpl}/protocol/digest.h | 0 .../xrpl}/protocol/json_get_or_throw.h | 0 {src/ripple => include/xrpl}/protocol/jss.h | 0 {src/ripple => include/xrpl}/protocol/messages.h | 0 {src/ripple => include/xrpl}/protocol/nft.h | 0 {src/ripple => include/xrpl}/protocol/nftPageMask.h | 0 {src/ripple => include/xrpl}/protocol/serialize.h | 0 {src/ripple => include/xrpl}/protocol/st.h | 0 {src/ripple => include/xrpl}/protocol/tokens.h | 0 {src/ripple => include/xrpl}/resource/Charge.h | 0 {src/ripple => include/xrpl}/resource/Consumer.h | 0 {src/ripple => include/xrpl}/resource/Disposition.h | 0 {src/ripple => include/xrpl}/resource/Fees.h | 0 {src/ripple => include/xrpl}/resource/Gossip.h | 0 {src/ripple => include/xrpl}/resource/README.md | 0 .../xrpl}/resource/ResourceManager.h | 0 {src/ripple => include/xrpl}/resource/Types.h | 0 .../impl => include/xrpl/resource/detail}/Entry.h | 0 .../impl => include/xrpl/resource/detail}/Import.h | 0 .../impl => include/xrpl/resource/detail}/Key.h | 0 .../impl => include/xrpl/resource/detail}/Kind.h | 0 .../impl => include/xrpl/resource/detail}/Logic.h | 0 .../impl => include/xrpl/resource/detail}/Tuning.h | 0 {src/ripple => include/xrpl}/server/Handoff.h | 0 {src/ripple => include/xrpl}/server/Port.h | 0 {src/ripple => include/xrpl}/server/Server.h | 0 {src/ripple => include/xrpl}/server/Session.h | 0 {src/ripple => include/xrpl}/server/SimpleWriter.h | 0 {src/ripple => include/xrpl}/server/WSSession.h | 0 {src/ripple => include/xrpl}/server/Writer.h | 0 .../xrpl/server/detail}/BaseHTTPPeer.h | 0 .../impl => include/xrpl/server/detail}/BasePeer.h | 0 .../xrpl/server/detail}/BaseWSPeer.h | 0 .../impl => include/xrpl/server/detail}/Door.h | 0 .../xrpl/server/detail}/JSONRPCUtil.h | 0 .../xrpl/server/detail}/LowestLayer.h | 0 .../xrpl/server/detail}/PlainHTTPPeer.h | 0 .../xrpl/server/detail}/PlainWSPeer.h | 0 .../xrpl/server/detail}/SSLHTTPPeer.h | 0 .../impl => include/xrpl/server/detail}/SSLWSPeer.h | 0 .../xrpl/server/detail}/ServerImpl.h | 0 .../impl => include/xrpl/server/detail}/io_list.h | 0 .../basics/impl => libxrpl/basics}/Archive.cpp | 0 .../basics/impl => libxrpl/basics}/BasicConfig.cpp | 0 .../impl => libxrpl/basics}/CountedObject.cpp | 0 .../impl => libxrpl/basics}/FileUtilities.cpp | 0 .../basics/impl => libxrpl/basics}/IOUAmount.cpp | 0 src/{ripple/basics/impl => libxrpl/basics}/Log.cpp | 0 .../basics/impl => libxrpl/basics}/Number.cpp | 0 .../basics/impl => libxrpl/basics}/ResolverAsio.cpp | 0 .../impl => libxrpl/basics}/StringUtilities.cpp | 0 .../basics/impl => libxrpl/basics}/UptimeClock.cpp | 0 .../basics/impl => libxrpl/basics}/base64.cpp | 0 .../basics/impl => libxrpl/basics}/contract.cpp | 0 .../impl => libxrpl/basics}/make_SSLContext.cpp | 0 .../basics/impl => libxrpl/basics}/mulDiv.cpp | 0 .../basics}/partitioned_unordered_map.cpp | 0 .../beast/clock/basic_seconds_clock.cpp | 0 .../beast/core/CurrentThreadName.cpp | 0 .../beast/core/SemanticVersion.cpp | 0 .../impl => libxrpl/beast/insight}/Collector.cpp | 0 .../impl => libxrpl/beast/insight}/Groups.cpp | 0 .../insight/impl => libxrpl/beast/insight}/Hook.cpp | 0 .../impl => libxrpl/beast/insight}/Metric.cpp | 0 .../beast/insight}/NullCollector.cpp | 0 .../beast/insight}/StatsDCollector.cpp | 0 .../beast/net}/IPAddressConversion.cpp | 0 .../net/impl => libxrpl/beast/net}/IPAddressV4.cpp | 0 .../net/impl => libxrpl/beast/net}/IPAddressV6.cpp | 0 .../net/impl => libxrpl/beast/net}/IPEndpoint.cpp | 0 .../beast/utility/src/beast_Journal.cpp | 0 .../beast/utility/src/beast_PropertyStream.cpp | 0 .../crypto/impl => libxrpl/crypto}/RFC1751.cpp | 0 .../crypto/impl => libxrpl/crypto}/csprng.cpp | 0 .../crypto/impl => libxrpl/crypto}/secure_erase.cpp | 0 .../impl => libxrpl/json}/JsonPropertyStream.cpp | 0 src/{ripple/json/impl => libxrpl/json}/Object.cpp | 0 src/{ripple/json/impl => libxrpl/json}/Output.cpp | 0 src/{ripple/json/impl => libxrpl/json}/Writer.cpp | 0 .../json/impl => libxrpl/json}/json_reader.cpp | 0 .../json/impl => libxrpl/json}/json_value.cpp | 0 .../impl => libxrpl/json}/json_valueiterator.cpp | 0 .../json/impl => libxrpl/json}/json_writer.cpp | 0 .../json/impl => libxrpl/json}/to_string.cpp | 0 .../protocol/impl => libxrpl/protocol}/AMMCore.cpp | 0 .../impl => libxrpl/protocol}/AccountID.cpp | 0 .../protocol/impl => libxrpl/protocol}/Book.cpp | 0 .../impl => libxrpl/protocol}/BuildInfo.cpp | 0 .../impl => libxrpl/protocol}/ErrorCodes.cpp | 0 .../protocol/impl => libxrpl/protocol}/Feature.cpp | 0 .../protocol/impl => libxrpl/protocol}/Indexes.cpp | 0 .../protocol}/InnerObjectFormats.cpp | 0 .../protocol/impl => libxrpl/protocol}/Issue.cpp | 0 .../protocol/impl => libxrpl/protocol}/Keylet.cpp | 0 .../impl => libxrpl/protocol}/LedgerFormats.cpp | 0 .../impl => libxrpl/protocol}/LedgerHeader.cpp | 0 .../protocol}/NFTSyntheticSerializer.cpp | 0 .../impl => libxrpl/protocol}/NFTokenID.cpp | 0 .../impl => libxrpl/protocol}/NFTokenOfferID.cpp | 0 .../impl => libxrpl/protocol}/PublicKey.cpp | 0 .../protocol/impl => libxrpl/protocol}/Quality.cpp | 0 .../impl => libxrpl/protocol}/QualityFunction.cpp | 0 .../protocol/impl => libxrpl/protocol}/RPCErr.cpp | 0 .../protocol/impl => libxrpl/protocol}/Rate2.cpp | 0 .../protocol/impl => libxrpl/protocol}/Rules.cpp | 0 .../protocol/impl => libxrpl/protocol}/SField.cpp | 0 .../impl => libxrpl/protocol}/SOTemplate.cpp | 0 .../impl => libxrpl/protocol}/STAccount.cpp | 0 .../protocol/impl => libxrpl/protocol}/STAmount.cpp | 0 .../protocol/impl => libxrpl/protocol}/STArray.cpp | 0 .../protocol/impl => libxrpl/protocol}/STBase.cpp | 0 .../protocol/impl => libxrpl/protocol}/STBlob.cpp | 0 .../impl => libxrpl/protocol}/STCurrency.cpp | 0 .../impl => libxrpl/protocol}/STInteger.cpp | 0 .../protocol/impl => libxrpl/protocol}/STIssue.cpp | 0 .../impl => libxrpl/protocol}/STLedgerEntry.cpp | 0 .../protocol/impl => libxrpl/protocol}/STObject.cpp | 0 .../impl => libxrpl/protocol}/STParsedJSON.cpp | 0 .../impl => libxrpl/protocol}/STPathSet.cpp | 0 .../protocol/impl => libxrpl/protocol}/STTx.cpp | 0 .../impl => libxrpl/protocol}/STValidation.cpp | 0 .../protocol/impl => libxrpl/protocol}/STVar.cpp | 0 .../impl => libxrpl/protocol}/STVector256.cpp | 0 .../impl => libxrpl/protocol}/STXChainBridge.cpp | 0 .../impl => libxrpl/protocol}/SecretKey.cpp | 0 .../protocol/impl => libxrpl/protocol}/Seed.cpp | 0 .../impl => libxrpl/protocol}/Serializer.cpp | 0 .../protocol/impl => libxrpl/protocol}/Sign.cpp | 0 .../protocol/impl => libxrpl/protocol}/TER.cpp | 0 .../impl => libxrpl/protocol}/TxFormats.cpp | 0 .../protocol/impl => libxrpl/protocol}/TxMeta.cpp | 0 .../impl => libxrpl/protocol}/UintTypes.cpp | 0 .../protocol}/XChainAttestations.cpp | 0 .../protocol/impl => libxrpl/protocol}/digest.cpp | 0 .../protocol/impl => libxrpl/protocol}/tokens.cpp | 0 .../resource/impl => libxrpl/resource}/Charge.cpp | 0 .../resource/impl => libxrpl/resource}/Consumer.cpp | 0 .../resource/impl => libxrpl/resource}/Fees.cpp | 0 .../impl => libxrpl/resource}/ResourceManager.cpp | 0 .../server/impl => libxrpl/server}/JSONRPCUtil.cpp | 0 src/{ripple/server/impl => libxrpl/server}/Port.cpp | 0 src/{ripple => xrpld}/README.md | 0 .../app/consensus/RCLCensorshipDetector.h | 0 .../app/consensus/RCLConsensus.cpp | 0 src/{ripple => xrpld}/app/consensus/RCLConsensus.h | 0 src/{ripple => xrpld}/app/consensus/RCLCxLedger.h | 0 .../app/consensus/RCLCxPeerPos.cpp | 0 src/{ripple => xrpld}/app/consensus/RCLCxPeerPos.h | 0 src/{ripple => xrpld}/app/consensus/RCLCxTx.h | 0 .../app/consensus/RCLValidations.cpp | 0 .../app/consensus/RCLValidations.h | 0 src/{ripple => xrpld}/app/consensus/README.md | 0 .../app/ledger/AbstractFetchPackContainer.h | 0 src/{ripple => xrpld}/app/ledger/AcceptedLedger.cpp | 0 src/{ripple => xrpld}/app/ledger/AcceptedLedger.h | 0 .../app/ledger/AcceptedLedgerTx.cpp | 0 src/{ripple => xrpld}/app/ledger/AcceptedLedgerTx.h | 0 src/{ripple => xrpld}/app/ledger/AccountStateSF.cpp | 0 src/{ripple => xrpld}/app/ledger/AccountStateSF.h | 0 src/{ripple => xrpld}/app/ledger/BookListeners.cpp | 0 src/{ripple => xrpld}/app/ledger/BookListeners.h | 0 src/{ripple => xrpld}/app/ledger/BuildLedger.h | 0 .../app/ledger/ConsensusTransSetSF.cpp | 0 .../app/ledger/ConsensusTransSetSF.h | 0 src/{ripple => xrpld}/app/ledger/InboundLedger.h | 0 src/{ripple => xrpld}/app/ledger/InboundLedgers.h | 0 .../app/ledger/InboundTransactions.h | 0 .../app/ledger/InboundTransactions.uml | 0 src/{ripple => xrpld}/app/ledger/Ledger.cpp | 0 src/{ripple => xrpld}/app/ledger/Ledger.h | 0 src/{ripple => xrpld}/app/ledger/LedgerCleaner.h | 0 src/{ripple => xrpld}/app/ledger/LedgerHistory.cpp | 0 src/{ripple => xrpld}/app/ledger/LedgerHistory.h | 0 src/{ripple => xrpld}/app/ledger/LedgerHolder.h | 0 src/{ripple => xrpld}/app/ledger/LedgerMaster.h | 0 src/{ripple => xrpld}/app/ledger/LedgerReplay.h | 0 src/{ripple => xrpld}/app/ledger/LedgerReplayTask.h | 0 src/{ripple => xrpld}/app/ledger/LedgerReplayer.h | 0 src/{ripple => xrpld}/app/ledger/LedgerToJson.h | 0 src/{ripple => xrpld}/app/ledger/LocalTxs.h | 0 src/{ripple => xrpld}/app/ledger/OpenLedger.h | 0 src/{ripple => xrpld}/app/ledger/OrderBookDB.cpp | 0 src/{ripple => xrpld}/app/ledger/OrderBookDB.h | 0 src/{ripple => xrpld}/app/ledger/PendingSaves.h | 0 src/{ripple => xrpld}/app/ledger/README.md | 0 .../app/ledger/TransactionMaster.h | 0 .../app/ledger/TransactionStateSF.cpp | 0 .../app/ledger/TransactionStateSF.h | 0 .../app/ledger/detail}/BuildLedger.cpp | 0 .../app/ledger/detail}/InboundLedger.cpp | 0 .../app/ledger/detail}/InboundLedgers.cpp | 0 .../app/ledger/detail}/InboundTransactions.cpp | 0 .../app/ledger/detail}/LedgerCleaner.cpp | 0 .../app/ledger/detail}/LedgerDeltaAcquire.cpp | 0 .../app/ledger/detail}/LedgerDeltaAcquire.h | 0 .../app/ledger/detail}/LedgerMaster.cpp | 0 .../app/ledger/detail}/LedgerReplay.cpp | 0 .../app/ledger/detail}/LedgerReplayMsgHandler.cpp | 0 .../app/ledger/detail}/LedgerReplayMsgHandler.h | 0 .../app/ledger/detail}/LedgerReplayTask.cpp | 0 .../app/ledger/detail}/LedgerReplayer.cpp | 0 .../app/ledger/detail}/LedgerToJson.cpp | 0 .../impl => xrpld/app/ledger/detail}/LocalTxs.cpp | 0 .../impl => xrpld/app/ledger/detail}/OpenLedger.cpp | 0 .../app/ledger/detail}/SkipListAcquire.cpp | 0 .../app/ledger/detail}/SkipListAcquire.h | 0 .../app/ledger/detail}/TimeoutCounter.cpp | 0 .../app/ledger/detail}/TimeoutCounter.h | 0 .../app/ledger/detail}/TransactionAcquire.cpp | 0 .../app/ledger/detail}/TransactionAcquire.h | 0 .../app/ledger/detail}/TransactionMaster.cpp | 0 src/{ripple => xrpld}/app/main/Application.cpp | 0 src/{ripple => xrpld}/app/main/Application.h | 0 src/{ripple => xrpld}/app/main/BasicApp.cpp | 0 src/{ripple => xrpld}/app/main/BasicApp.h | 0 src/{ripple => xrpld}/app/main/CollectorManager.cpp | 0 src/{ripple => xrpld}/app/main/CollectorManager.h | 0 src/{ripple => xrpld}/app/main/DBInit.h | 0 src/{ripple => xrpld}/app/main/GRPCServer.cpp | 0 src/{ripple => xrpld}/app/main/GRPCServer.h | 0 src/{ripple => xrpld}/app/main/LoadManager.cpp | 0 src/{ripple => xrpld}/app/main/LoadManager.h | 0 src/{ripple => xrpld}/app/main/Main.cpp | 0 src/{ripple => xrpld}/app/main/NodeIdentity.cpp | 0 src/{ripple => xrpld}/app/main/NodeIdentity.h | 0 .../app/main/NodeStoreScheduler.cpp | 0 src/{ripple => xrpld}/app/main/NodeStoreScheduler.h | 0 src/{ripple => xrpld}/app/main/Tuning.h | 0 src/{ripple => xrpld}/app/misc/AMMHelpers.h | 0 src/{ripple => xrpld}/app/misc/AMMUtils.h | 0 src/{ripple => xrpld}/app/misc/AmendmentTable.h | 0 src/{ripple => xrpld}/app/misc/CanonicalTXSet.cpp | 0 src/{ripple => xrpld}/app/misc/CanonicalTXSet.h | 0 src/{ripple => xrpld}/app/misc/DeliverMax.h | 0 src/{ripple => xrpld}/app/misc/FeeEscalation.md | 0 src/{ripple => xrpld}/app/misc/FeeVote.h | 0 src/{ripple => xrpld}/app/misc/FeeVoteImpl.cpp | 0 src/{ripple => xrpld}/app/misc/HashRouter.cpp | 0 src/{ripple => xrpld}/app/misc/HashRouter.h | 0 src/{ripple => xrpld}/app/misc/LoadFeeTrack.h | 0 src/{ripple => xrpld}/app/misc/Manifest.h | 0 src/{ripple => xrpld}/app/misc/NegativeUNLVote.cpp | 0 src/{ripple => xrpld}/app/misc/NegativeUNLVote.h | 0 src/{ripple => xrpld}/app/misc/NetworkOPs.cpp | 0 src/{ripple => xrpld}/app/misc/NetworkOPs.h | 0 src/{ripple => xrpld}/app/misc/README.md | 0 src/{ripple => xrpld}/app/misc/SHAMapStore.h | 0 src/{ripple => xrpld}/app/misc/SHAMapStoreImp.cpp | 0 src/{ripple => xrpld}/app/misc/SHAMapStoreImp.h | 0 src/{ripple => xrpld}/app/misc/Transaction.h | 0 src/{ripple => xrpld}/app/misc/TxQ.h | 0 src/{ripple => xrpld}/app/misc/ValidatorKeys.h | 0 src/{ripple => xrpld}/app/misc/ValidatorList.h | 0 src/{ripple => xrpld}/app/misc/ValidatorSite.h | 0 .../impl => xrpld/app/misc/detail}/AMMHelpers.cpp | 0 .../impl => xrpld/app/misc/detail}/AMMUtils.cpp | 0 .../app/misc/detail}/AccountTxPaging.cpp | 0 .../app/misc/detail}/AccountTxPaging.h | 0 .../app/misc/detail}/AmendmentTable.cpp | 0 .../impl => xrpld/app/misc/detail}/DeliverMax.cpp | 0 .../impl => xrpld/app/misc/detail}/LoadFeeTrack.cpp | 0 .../impl => xrpld/app/misc/detail}/Manifest.cpp | 0 .../impl => xrpld/app/misc/detail}/Transaction.cpp | 0 .../app/misc/impl => xrpld/app/misc/detail}/TxQ.cpp | 0 .../app/misc/detail}/ValidatorKeys.cpp | 0 .../app/misc/detail}/ValidatorList.cpp | 0 .../app/misc/detail}/ValidatorSite.cpp | 0 src/{ripple => xrpld}/app/misc/detail/Work.h | 0 src/{ripple => xrpld}/app/misc/detail/WorkBase.h | 0 src/{ripple => xrpld}/app/misc/detail/WorkFile.h | 0 src/{ripple => xrpld}/app/misc/detail/WorkPlain.h | 0 src/{ripple => xrpld}/app/misc/detail/WorkSSL.h | 0 .../app/misc/detail/detail}/WorkSSL.cpp | 0 src/{ripple => xrpld}/app/paths/AMMContext.h | 0 src/{ripple => xrpld}/app/paths/AMMLiquidity.h | 0 src/{ripple => xrpld}/app/paths/AMMOffer.h | 0 .../app/paths/AccountCurrencies.cpp | 0 src/{ripple => xrpld}/app/paths/AccountCurrencies.h | 0 src/{ripple => xrpld}/app/paths/Credit.cpp | 0 src/{ripple => xrpld}/app/paths/Credit.h | 0 src/{ripple => xrpld}/app/paths/Flow.cpp | 0 src/{ripple => xrpld}/app/paths/Flow.h | 0 src/{ripple => xrpld}/app/paths/PathRequest.cpp | 0 src/{ripple => xrpld}/app/paths/PathRequest.h | 0 src/{ripple => xrpld}/app/paths/PathRequests.cpp | 0 src/{ripple => xrpld}/app/paths/PathRequests.h | 0 src/{ripple => xrpld}/app/paths/Pathfinder.cpp | 0 src/{ripple => xrpld}/app/paths/Pathfinder.h | 0 src/{ripple => xrpld}/app/paths/RippleCalc.cpp | 0 src/{ripple => xrpld}/app/paths/RippleCalc.h | 0 src/{ripple => xrpld}/app/paths/RippleLineCache.cpp | 0 src/{ripple => xrpld}/app/paths/RippleLineCache.h | 0 src/{ripple => xrpld}/app/paths/TrustLine.cpp | 0 src/{ripple => xrpld}/app/paths/TrustLine.h | 0 .../app/paths/detail}/AMMLiquidity.cpp | 0 .../impl => xrpld/app/paths/detail}/AMMOffer.cpp | 0 .../impl => xrpld/app/paths/detail}/AmountSpec.h | 0 .../impl => xrpld/app/paths/detail}/BookStep.cpp | 0 .../impl => xrpld/app/paths/detail}/DirectStep.cpp | 0 .../impl => xrpld/app/paths/detail}/FlatSets.h | 0 .../impl => xrpld/app/paths/detail}/FlowDebugInfo.h | 0 .../app/paths/detail}/PathfinderUtils.h | 0 .../impl => xrpld/app/paths/detail}/PaySteps.cpp | 0 .../impl => xrpld/app/paths/detail}/StepChecks.h | 0 .../paths/impl => xrpld/app/paths/detail}/Steps.h | 0 .../impl => xrpld/app/paths/detail}/StrandFlow.h | 0 .../app/paths/detail}/XRPEndpointStep.cpp | 0 src/{ripple => xrpld}/app/rdb/Download.h | 0 src/{ripple => xrpld}/app/rdb/PeerFinder.h | 0 src/{ripple => xrpld}/app/rdb/README.md | 0 src/{ripple => xrpld}/app/rdb/RelationalDatabase.h | 0 src/{ripple => xrpld}/app/rdb/ShardArchive.h | 0 src/{ripple => xrpld}/app/rdb/State.h | 0 src/{ripple => xrpld}/app/rdb/UnitaryShard.h | 0 src/{ripple => xrpld}/app/rdb/Vacuum.h | 0 src/{ripple => xrpld}/app/rdb/Wallet.h | 0 .../app/rdb/backend/PostgresDatabase.h | 0 .../app/rdb/backend/SQLiteDatabase.h | 0 src/{ripple => xrpld}/app/rdb/backend/detail/Node.h | 0 .../app/rdb/backend/detail}/PostgresDatabase.cpp | 0 .../app/rdb/backend/detail}/SQLiteDatabase.cpp | 0 .../app/rdb/backend/detail/Shard.h | 0 .../app/rdb/backend/detail/detail}/Node.cpp | 0 .../app/rdb/backend/detail/detail}/Shard.cpp | 0 .../rdb/impl => xrpld/app/rdb/detail}/Download.cpp | 0 .../impl => xrpld/app/rdb/detail}/PeerFinder.cpp | 0 .../app/rdb/detail}/RelationalDatabase.cpp | 0 .../impl => xrpld/app/rdb/detail}/ShardArchive.cpp | 0 .../app/rdb/impl => xrpld/app/rdb/detail}/State.cpp | 0 .../impl => xrpld/app/rdb/detail}/UnitaryShard.cpp | 0 .../rdb/impl => xrpld/app/rdb/detail}/Vacuum.cpp | 0 .../rdb/impl => xrpld/app/rdb/detail}/Wallet.cpp | 0 src/{ripple => xrpld}/app/reporting/ETLHelpers.h | 0 src/{ripple => xrpld}/app/reporting/ETLSource.cpp | 0 src/{ripple => xrpld}/app/reporting/ETLSource.h | 0 src/{ripple => xrpld}/app/reporting/P2pProxy.cpp | 0 src/{ripple => xrpld}/app/reporting/P2pProxy.h | 0 src/{ripple => xrpld}/app/reporting/README.md | 0 .../app/reporting/ReportingETL.cpp | 0 src/{ripple => xrpld}/app/reporting/ReportingETL.h | 0 src/{ripple => xrpld}/app/tx/apply.h | 0 src/{ripple => xrpld}/app/tx/applySteps.h | 0 .../app/tx/impl => xrpld/app/tx/detail}/AMMBid.cpp | 0 .../app/tx/impl => xrpld/app/tx/detail}/AMMBid.h | 0 .../tx/impl => xrpld/app/tx/detail}/AMMCreate.cpp | 0 .../app/tx/impl => xrpld/app/tx/detail}/AMMCreate.h | 0 .../tx/impl => xrpld/app/tx/detail}/AMMDelete.cpp | 0 .../app/tx/impl => xrpld/app/tx/detail}/AMMDelete.h | 0 .../tx/impl => xrpld/app/tx/detail}/AMMDeposit.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/AMMDeposit.h | 0 .../app/tx/impl => xrpld/app/tx/detail}/AMMVote.cpp | 0 .../app/tx/impl => xrpld/app/tx/detail}/AMMVote.h | 0 .../tx/impl => xrpld/app/tx/detail}/AMMWithdraw.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/AMMWithdraw.h | 0 .../impl => xrpld/app/tx/detail}/ApplyContext.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/ApplyContext.h | 0 .../app/tx/impl => xrpld/app/tx/detail}/BookTip.cpp | 0 .../app/tx/impl => xrpld/app/tx/detail}/BookTip.h | 0 .../tx/impl => xrpld/app/tx/detail}/CancelCheck.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/CancelCheck.h | 0 .../tx/impl => xrpld/app/tx/detail}/CancelOffer.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/CancelOffer.h | 0 .../tx/impl => xrpld/app/tx/detail}/CashCheck.cpp | 0 .../app/tx/impl => xrpld/app/tx/detail}/CashCheck.h | 0 .../app/tx/impl => xrpld/app/tx/detail}/Change.cpp | 0 .../app/tx/impl => xrpld/app/tx/detail}/Change.h | 0 .../tx/impl => xrpld/app/tx/detail}/Clawback.cpp | 0 .../app/tx/impl => xrpld/app/tx/detail}/Clawback.h | 0 .../tx/impl => xrpld/app/tx/detail}/CreateCheck.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/CreateCheck.h | 0 .../tx/impl => xrpld/app/tx/detail}/CreateOffer.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/CreateOffer.h | 0 .../impl => xrpld/app/tx/detail}/CreateTicket.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/CreateTicket.h | 0 .../app/tx/impl => xrpld/app/tx/detail}/DID.cpp | 0 .../app/tx/impl => xrpld/app/tx/detail}/DID.h | 0 .../impl => xrpld/app/tx/detail}/DeleteAccount.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/DeleteAccount.h | 0 .../impl => xrpld/app/tx/detail}/DeleteOracle.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/DeleteOracle.h | 0 .../impl => xrpld/app/tx/detail}/DepositPreauth.cpp | 0 .../impl => xrpld/app/tx/detail}/DepositPreauth.h | 0 .../app/tx/impl => xrpld/app/tx/detail}/Escrow.cpp | 0 .../app/tx/impl => xrpld/app/tx/detail}/Escrow.h | 0 .../impl => xrpld/app/tx/detail}/InvariantCheck.cpp | 0 .../impl => xrpld/app/tx/detail}/InvariantCheck.h | 0 .../app/tx/detail}/NFTokenAcceptOffer.cpp | 0 .../app/tx/detail}/NFTokenAcceptOffer.h | 0 .../tx/impl => xrpld/app/tx/detail}/NFTokenBurn.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/NFTokenBurn.h | 0 .../app/tx/detail}/NFTokenCancelOffer.cpp | 0 .../app/tx/detail}/NFTokenCancelOffer.h | 0 .../app/tx/detail}/NFTokenCreateOffer.cpp | 0 .../app/tx/detail}/NFTokenCreateOffer.h | 0 .../tx/impl => xrpld/app/tx/detail}/NFTokenMint.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/NFTokenMint.h | 0 .../app/tx/detail}/NFTokenUtils.cpp | 0 .../details => xrpld/app/tx/detail}/NFTokenUtils.h | 0 .../app/tx/impl => xrpld/app/tx/detail}/Offer.h | 0 .../tx/impl => xrpld/app/tx/detail}/OfferStream.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/OfferStream.h | 0 .../app/tx/impl => xrpld/app/tx/detail}/PayChan.cpp | 0 .../app/tx/impl => xrpld/app/tx/detail}/PayChan.h | 0 .../app/tx/impl => xrpld/app/tx/detail}/Payment.cpp | 0 .../app/tx/impl => xrpld/app/tx/detail}/Payment.h | 0 .../tx/impl => xrpld/app/tx/detail}/SetAccount.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/SetAccount.h | 0 .../tx/impl => xrpld/app/tx/detail}/SetOracle.cpp | 0 .../app/tx/impl => xrpld/app/tx/detail}/SetOracle.h | 0 .../impl => xrpld/app/tx/detail}/SetRegularKey.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/SetRegularKey.h | 0 .../impl => xrpld/app/tx/detail}/SetSignerList.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/SetSignerList.h | 0 .../tx/impl => xrpld/app/tx/detail}/SetTrust.cpp | 0 .../app/tx/impl => xrpld/app/tx/detail}/SetTrust.h | 0 .../impl => xrpld/app/tx/detail}/SignerEntries.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/SignerEntries.h | 0 .../app/tx/impl => xrpld/app/tx/detail}/Taker.cpp | 0 .../app/tx/impl => xrpld/app/tx/detail}/Taker.h | 0 .../tx/impl => xrpld/app/tx/detail}/Transactor.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/Transactor.h | 0 .../impl => xrpld/app/tx/detail}/XChainBridge.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/XChainBridge.h | 0 .../app/tx/impl => xrpld/app/tx/detail}/apply.cpp | 0 .../tx/impl => xrpld/app/tx/detail}/applySteps.cpp | 0 src/{ripple => xrpld}/conditions/Condition.h | 0 src/{ripple => xrpld}/conditions/Fulfillment.h | 0 .../impl => xrpld/conditions/detail}/Condition.cpp | 0 .../conditions/detail}/Fulfillment.cpp | 0 .../conditions/detail}/PreimageSha256.h | 0 .../impl => xrpld/conditions/detail}/error.cpp | 0 .../impl => xrpld/conditions/detail}/error.h | 0 .../impl => xrpld/conditions/detail}/utils.h | 0 src/{ripple => xrpld}/consensus/Consensus.cpp | 0 src/{ripple => xrpld}/consensus/Consensus.h | 0 src/{ripple => xrpld}/consensus/ConsensusParms.h | 0 src/{ripple => xrpld}/consensus/ConsensusProposal.h | 0 src/{ripple => xrpld}/consensus/ConsensusTypes.h | 0 src/{ripple => xrpld}/consensus/DisputedTx.h | 0 src/{ripple => xrpld}/consensus/LedgerTiming.h | 0 src/{ripple => xrpld}/consensus/LedgerTrie.h | 0 src/{ripple => xrpld}/consensus/README.md | 0 src/{ripple => xrpld}/consensus/Validations.h | 0 src/{ripple => xrpld}/core/ClosureCounter.h | 0 src/{ripple => xrpld}/core/Config.h | 0 src/{ripple => xrpld}/core/ConfigSections.h | 0 src/{ripple => xrpld}/core/Coro.ipp | 0 src/{ripple => xrpld}/core/DatabaseCon.h | 0 src/{ripple => xrpld}/core/Job.h | 0 src/{ripple => xrpld}/core/JobQueue.h | 0 src/{ripple => xrpld}/core/JobTypeData.h | 0 src/{ripple => xrpld}/core/JobTypeInfo.h | 0 src/{ripple => xrpld}/core/JobTypes.h | 0 src/{ripple => xrpld}/core/LoadEvent.h | 0 src/{ripple => xrpld}/core/LoadMonitor.h | 0 src/{ripple => xrpld}/core/Pg.cpp | 0 src/{ripple => xrpld}/core/Pg.h | 0 src/{ripple => xrpld}/core/SociDB.h | 0 src/{ripple => xrpld}/core/TimeKeeper.h | 0 .../core/impl => xrpld/core/detail}/Config.cpp | 0 .../core/impl => xrpld/core/detail}/DatabaseCon.cpp | 0 src/{ripple/core/impl => xrpld/core/detail}/Job.cpp | 0 .../core/impl => xrpld/core/detail}/JobQueue.cpp | 0 .../core/impl => xrpld/core/detail}/LoadEvent.cpp | 0 .../core/impl => xrpld/core/detail}/LoadMonitor.cpp | 0 .../core/impl => xrpld/core/detail}/SociDB.cpp | 0 .../core/impl => xrpld/core/detail}/Workers.cpp | 0 .../core/impl => xrpld/core/detail}/Workers.h | 0 .../core/impl => xrpld/core/detail}/semaphore.h | 0 src/{ripple => xrpld}/ledger/ApplyView.h | 0 src/{ripple => xrpld}/ledger/ApplyViewImpl.h | 0 src/{ripple => xrpld}/ledger/BookDirs.h | 0 src/{ripple => xrpld}/ledger/CachedSLEs.h | 0 src/{ripple => xrpld}/ledger/CachedView.h | 0 src/{ripple => xrpld}/ledger/Directory.h | 0 src/{ripple => xrpld}/ledger/OpenView.h | 0 src/{ripple => xrpld}/ledger/PaymentSandbox.h | 0 src/{ripple => xrpld}/ledger/RawView.h | 0 src/{ripple => xrpld}/ledger/ReadView.h | 0 src/{ripple => xrpld}/ledger/Sandbox.h | 0 src/{ripple => xrpld}/ledger/View.h | 0 .../ledger/detail}/ApplyStateTable.cpp | 0 .../ledger/detail/ApplyStateTable.h | 0 .../impl => xrpld/ledger/detail}/ApplyView.cpp | 0 .../impl => xrpld/ledger/detail}/ApplyViewBase.cpp | 0 src/{ripple => xrpld}/ledger/detail/ApplyViewBase.h | 0 .../impl => xrpld/ledger/detail}/ApplyViewImpl.cpp | 0 .../impl => xrpld/ledger/detail}/BookDirs.cpp | 0 .../impl => xrpld/ledger/detail}/CachedView.cpp | 0 .../impl => xrpld/ledger/detail}/Directory.cpp | 0 .../impl => xrpld/ledger/detail}/OpenView.cpp | 0 .../impl => xrpld/ledger/detail}/PaymentSandbox.cpp | 0 .../impl => xrpld/ledger/detail}/RawStateTable.cpp | 0 src/{ripple => xrpld}/ledger/detail/RawStateTable.h | 0 .../impl => xrpld/ledger/detail}/ReadView.cpp | 0 .../ledger/detail/ReadViewFwdRange.h | 0 .../ledger/detail/ReadViewFwdRange.ipp | 0 .../ledger/impl => xrpld/ledger/detail}/View.cpp | 0 src/{ripple => xrpld}/net/AutoSocket.h | 0 src/{ripple => xrpld}/net/DatabaseBody.h | 0 src/{ripple => xrpld}/net/DatabaseDownloader.h | 0 src/{ripple => xrpld}/net/HTTPClient.h | 0 src/{ripple => xrpld}/net/HTTPClientSSLContext.h | 0 src/{ripple => xrpld}/net/HTTPDownloader.h | 0 src/{ripple => xrpld}/net/HTTPStream.h | 0 src/{ripple => xrpld}/net/InfoSub.h | 0 src/{ripple => xrpld}/net/RPCCall.h | 0 src/{ripple => xrpld}/net/RPCSub.h | 0 src/{ripple => xrpld}/net/RegisterSSLCerts.h | 0 src/{ripple => xrpld}/net/ShardDownloader.md | 0 .../net/impl => xrpld/net/detail}/DatabaseBody.ipp | 0 .../net/detail}/DatabaseDownloader.cpp | 0 .../net/impl => xrpld/net/detail}/HTTPClient.cpp | 0 .../impl => xrpld/net/detail}/HTTPDownloader.cpp | 0 .../net/impl => xrpld/net/detail}/HTTPStream.cpp | 0 .../net/impl => xrpld/net/detail}/InfoSub.cpp | 0 .../net/impl => xrpld/net/detail}/RPCCall.cpp | 0 .../net/impl => xrpld/net/detail}/RPCSub.cpp | 0 .../impl => xrpld/net/detail}/RegisterSSLCerts.cpp | 0 .../net/images/interrupt_sequence.png | Bin src/{ripple => xrpld}/net/images/states.png | Bin src/{ripple => xrpld}/net/uml/interrupt_sequence.pu | 0 src/{ripple => xrpld}/net/uml/states.pu | 0 src/{ripple => xrpld}/nodestore/Backend.h | 0 src/{ripple => xrpld}/nodestore/Database.h | 0 src/{ripple => xrpld}/nodestore/DatabaseRotating.h | 0 src/{ripple => xrpld}/nodestore/DatabaseShard.h | 0 .../nodestore/DeterministicShard.md | 0 src/{ripple => xrpld}/nodestore/DummyScheduler.h | 0 src/{ripple => xrpld}/nodestore/Factory.h | 0 src/{ripple => xrpld}/nodestore/Manager.h | 0 src/{ripple => xrpld}/nodestore/NodeObject.h | 0 src/{ripple => xrpld}/nodestore/README.md | 0 src/{ripple => xrpld}/nodestore/Scheduler.h | 0 src/{ripple => xrpld}/nodestore/ShardInfo.h | 0 src/{ripple => xrpld}/nodestore/ShardPool.md | 0 src/{ripple => xrpld}/nodestore/ShardSizeTuning.md | 0 src/{ripple => xrpld}/nodestore/Task.h | 0 src/{ripple => xrpld}/nodestore/Types.h | 0 .../nodestore/backend/CassandraFactory.cpp | 0 .../nodestore/backend/MemoryFactory.cpp | 0 .../nodestore/backend/NuDBFactory.cpp | 0 .../nodestore/backend/NullFactory.cpp | 0 .../nodestore/backend/RocksDBFactory.cpp | 0 .../impl => xrpld/nodestore/detail}/BatchWriter.cpp | 0 .../impl => xrpld/nodestore/detail}/BatchWriter.h | 0 .../impl => xrpld/nodestore/detail}/Database.cpp | 0 .../nodestore/detail}/DatabaseNodeImp.cpp | 0 .../nodestore/detail}/DatabaseNodeImp.h | 0 .../nodestore/detail}/DatabaseRotatingImp.cpp | 0 .../nodestore/detail}/DatabaseRotatingImp.h | 0 .../nodestore/detail}/DatabaseShardImp.cpp | 0 .../nodestore/detail}/DatabaseShardImp.h | 0 .../impl => xrpld/nodestore/detail}/DecodedBlob.cpp | 0 .../impl => xrpld/nodestore/detail}/DecodedBlob.h | 0 .../nodestore/detail}/DeterministicShard.cpp | 0 .../nodestore/detail}/DeterministicShard.h | 0 .../nodestore/detail}/DummyScheduler.cpp | 0 .../impl => xrpld/nodestore/detail}/EncodedBlob.h | 0 .../impl => xrpld/nodestore/detail}/ManagerImp.cpp | 0 .../impl => xrpld/nodestore/detail}/ManagerImp.h | 0 .../impl => xrpld/nodestore/detail}/NodeObject.cpp | 0 .../impl => xrpld/nodestore/detail}/Shard.cpp | 0 .../impl => xrpld/nodestore/detail}/Shard.h | 0 .../impl => xrpld/nodestore/detail}/ShardInfo.cpp | 0 .../impl => xrpld/nodestore/detail}/TaskQueue.cpp | 0 .../impl => xrpld/nodestore/detail}/TaskQueue.h | 0 .../impl => xrpld/nodestore/detail}/codec.h | 0 .../impl => xrpld/nodestore/detail}/varint.h | 0 src/{ripple => xrpld}/overlay/Cluster.h | 0 src/{ripple => xrpld}/overlay/ClusterNode.h | 0 src/{ripple => xrpld}/overlay/Compression.h | 0 src/{ripple => xrpld}/overlay/Message.h | 0 src/{ripple => xrpld}/overlay/Overlay.h | 0 src/{ripple => xrpld}/overlay/Peer.h | 0 .../overlay/PeerReservationTable.h | 0 src/{ripple => xrpld}/overlay/PeerSet.h | 0 src/{ripple => xrpld}/overlay/README.md | 0 src/{ripple => xrpld}/overlay/ReduceRelayCommon.h | 0 src/{ripple => xrpld}/overlay/Slot.h | 0 src/{ripple => xrpld}/overlay/Squelch.h | 0 .../impl => xrpld/overlay/detail}/Cluster.cpp | 0 .../overlay/detail}/ConnectAttempt.cpp | 0 .../impl => xrpld/overlay/detail}/ConnectAttempt.h | 0 .../impl => xrpld/overlay/detail}/Handshake.cpp | 0 .../impl => xrpld/overlay/detail}/Handshake.h | 0 .../impl => xrpld/overlay/detail}/Message.cpp | 0 .../impl => xrpld/overlay/detail}/OverlayImpl.cpp | 0 .../impl => xrpld/overlay/detail}/OverlayImpl.h | 0 .../impl => xrpld/overlay/detail}/PeerImp.cpp | 0 .../overlay/impl => xrpld/overlay/detail}/PeerImp.h | 0 .../overlay/detail}/PeerReservationTable.cpp | 0 .../impl => xrpld/overlay/detail}/PeerSet.cpp | 0 .../impl => xrpld/overlay/detail}/ProtocolMessage.h | 0 .../overlay/detail}/ProtocolVersion.cpp | 0 .../impl => xrpld/overlay/detail}/ProtocolVersion.h | 0 .../impl => xrpld/overlay/detail}/TrafficCount.cpp | 0 .../impl => xrpld/overlay/detail}/TrafficCount.h | 0 .../overlay/impl => xrpld/overlay/detail}/Tuning.h | 0 .../impl => xrpld/overlay/detail}/TxMetrics.cpp | 0 .../impl => xrpld/overlay/detail}/TxMetrics.h | 0 .../impl => xrpld/overlay/detail}/ZeroCopyStream.h | 0 src/{ripple => xrpld}/overlay/make_Overlay.h | 0 src/{ripple => xrpld}/overlay/predicates.h | 0 .../peerfinder/PeerfinderManager.h | 0 src/{ripple => xrpld}/peerfinder/README.md | 0 src/{ripple => xrpld}/peerfinder/Slot.h | 0 .../impl => xrpld/peerfinder/detail}/Bootcache.cpp | 0 .../impl => xrpld/peerfinder/detail}/Bootcache.h | 0 .../impl => xrpld/peerfinder/detail}/Checker.h | 0 .../impl => xrpld/peerfinder/detail}/Counts.h | 0 .../impl => xrpld/peerfinder/detail}/Endpoint.cpp | 0 .../impl => xrpld/peerfinder/detail}/Fixed.h | 0 .../impl => xrpld/peerfinder/detail}/Handouts.h | 0 .../impl => xrpld/peerfinder/detail}/Livecache.h | 0 .../impl => xrpld/peerfinder/detail}/Logic.h | 0 .../peerfinder/detail}/PeerfinderConfig.cpp | 0 .../peerfinder/detail}/PeerfinderManager.cpp | 0 .../impl => xrpld/peerfinder/detail}/Reporting.h | 0 .../impl => xrpld/peerfinder/detail}/SlotImp.cpp | 0 .../impl => xrpld/peerfinder/detail}/SlotImp.h | 0 .../impl => xrpld/peerfinder/detail}/Source.h | 0 .../peerfinder/detail}/SourceStrings.cpp | 0 .../peerfinder/detail}/SourceStrings.h | 0 .../impl => xrpld/peerfinder/detail}/Store.h | 0 .../impl => xrpld/peerfinder/detail}/StoreSqdb.h | 0 .../impl => xrpld/peerfinder/detail}/Tuning.h | 0 .../impl => xrpld/peerfinder/detail}/iosformat.h | 0 src/{ripple => xrpld}/peerfinder/make_Manager.h | 0 .../peerfinder/sim/FunctionQueue.h | 0 .../peerfinder/sim/GraphAlgorithms.h | 0 src/{ripple => xrpld}/peerfinder/sim/Message.h | 0 src/{ripple => xrpld}/peerfinder/sim/NodeSnapshot.h | 0 src/{ripple => xrpld}/peerfinder/sim/Params.h | 0 src/{ripple => xrpld}/peerfinder/sim/Predicates.h | 0 src/{ripple/basics => xrpld/perflog}/PerfLog.h | 0 .../impl => xrpld/perflog/detail}/PerfLogImp.cpp | 0 .../impl => xrpld/perflog/detail}/PerfLogImp.h | 0 src/{ripple => xrpld}/rpc/BookChanges.h | 0 src/{ripple => xrpld}/rpc/CTID.h | 0 src/{ripple => xrpld}/rpc/Context.h | 0 src/{ripple => xrpld}/rpc/DeliveredAmount.h | 0 src/{ripple => xrpld}/rpc/GRPCHandlers.h | 0 src/{ripple => xrpld}/rpc/Output.h | 0 src/{ripple => xrpld}/rpc/README.md | 0 src/{ripple => xrpld}/rpc/RPCHandler.h | 0 src/{ripple => xrpld}/rpc/Request.h | 0 src/{ripple => xrpld}/rpc/Role.h | 0 src/{ripple => xrpld}/rpc/ServerHandler.h | 0 src/{ripple => xrpld}/rpc/ShardArchiveHandler.h | 0 .../rpc/ShardVerificationScheduler.h | 0 src/{ripple => xrpld}/rpc/Status.h | 0 .../impl => xrpld/rpc/detail}/DeliveredAmount.cpp | 0 .../rpc/impl => xrpld/rpc/detail}/Handler.cpp | 0 src/{ripple/rpc/impl => xrpld/rpc/detail}/Handler.h | 0 .../impl => xrpld/rpc/detail}/LegacyPathFind.cpp | 0 .../rpc/impl => xrpld/rpc/detail}/LegacyPathFind.h | 0 .../rpc/impl => xrpld/rpc/detail}/RPCHandler.cpp | 0 .../rpc/impl => xrpld/rpc/detail}/RPCHelpers.cpp | 0 .../rpc/impl => xrpld/rpc/detail}/RPCHelpers.h | 0 src/{ripple/rpc/impl => xrpld/rpc/detail}/Role.cpp | 0 .../rpc/impl => xrpld/rpc/detail}/ServerHandler.cpp | 0 .../rpc/detail}/ShardArchiveHandler.cpp | 0 .../rpc/detail}/ShardVerificationScheduler.cpp | 0 .../rpc/impl => xrpld/rpc/detail}/Status.cpp | 0 .../impl => xrpld/rpc/detail}/TransactionSign.cpp | 0 .../rpc/impl => xrpld/rpc/detail}/TransactionSign.h | 0 src/{ripple/rpc/impl => xrpld/rpc/detail}/Tuning.h | 0 .../rpc/impl => xrpld/rpc/detail}/WSInfoSub.h | 0 src/{ripple => xrpld}/rpc/handlers/AMMInfo.cpp | 0 .../rpc/handlers/AccountChannels.cpp | 0 .../rpc/handlers/AccountCurrenciesHandler.cpp | 0 src/{ripple => xrpld}/rpc/handlers/AccountInfo.cpp | 0 src/{ripple => xrpld}/rpc/handlers/AccountLines.cpp | 0 .../rpc/handlers/AccountObjects.cpp | 0 .../rpc/handlers/AccountOffers.cpp | 0 src/{ripple => xrpld}/rpc/handlers/AccountTx.cpp | 0 src/{ripple => xrpld}/rpc/handlers/BlackList.cpp | 0 src/{ripple => xrpld}/rpc/handlers/BookOffers.cpp | 0 src/{ripple => xrpld}/rpc/handlers/CanDelete.cpp | 0 src/{ripple => xrpld}/rpc/handlers/Connect.cpp | 0 .../rpc/handlers/ConsensusInfo.cpp | 0 src/{ripple => xrpld}/rpc/handlers/CrawlShards.cpp | 0 .../rpc/handlers/DepositAuthorized.cpp | 0 .../rpc/handlers/DownloadShard.cpp | 0 src/{ripple => xrpld}/rpc/handlers/Feature1.cpp | 0 src/{ripple => xrpld}/rpc/handlers/Fee1.cpp | 0 src/{ripple => xrpld}/rpc/handlers/FetchInfo.cpp | 0 .../rpc/handlers/GatewayBalances.cpp | 0 .../rpc/handlers/GetAggregatePrice.cpp | 0 src/{ripple => xrpld}/rpc/handlers/GetCounts.cpp | 0 src/{ripple => xrpld}/rpc/handlers/GetCounts.h | 0 src/{ripple => xrpld}/rpc/handlers/Handlers.h | 0 src/{ripple => xrpld}/rpc/handlers/LedgerAccept.cpp | 0 .../rpc/handlers/LedgerCleanerHandler.cpp | 0 src/{ripple => xrpld}/rpc/handlers/LedgerClosed.cpp | 0 .../rpc/handlers/LedgerCurrent.cpp | 0 src/{ripple => xrpld}/rpc/handlers/LedgerData.cpp | 0 src/{ripple => xrpld}/rpc/handlers/LedgerDiff.cpp | 0 src/{ripple => xrpld}/rpc/handlers/LedgerEntry.cpp | 0 .../rpc/handlers/LedgerHandler.cpp | 0 src/{ripple => xrpld}/rpc/handlers/LedgerHandler.h | 0 src/{ripple => xrpld}/rpc/handlers/LedgerHeader.cpp | 0 .../rpc/handlers/LedgerRequest.cpp | 0 src/{ripple => xrpld}/rpc/handlers/LogLevel.cpp | 0 src/{ripple => xrpld}/rpc/handlers/LogRotate.cpp | 0 src/{ripple => xrpld}/rpc/handlers/Manifest.cpp | 0 src/{ripple => xrpld}/rpc/handlers/NFTOffers.cpp | 0 .../rpc/handlers/NoRippleCheck.cpp | 0 src/{ripple => xrpld}/rpc/handlers/NodeToShard.cpp | 0 src/{ripple => xrpld}/rpc/handlers/OwnerInfo.cpp | 0 src/{ripple => xrpld}/rpc/handlers/PathFind.cpp | 0 src/{ripple => xrpld}/rpc/handlers/PayChanClaim.cpp | 0 src/{ripple => xrpld}/rpc/handlers/Peers.cpp | 0 src/{ripple => xrpld}/rpc/handlers/Ping.cpp | 0 src/{ripple => xrpld}/rpc/handlers/Print.cpp | 0 src/{ripple => xrpld}/rpc/handlers/Random.cpp | 0 src/{ripple => xrpld}/rpc/handlers/Reservations.cpp | 0 .../rpc/handlers/RipplePathFind.cpp | 0 src/{ripple => xrpld}/rpc/handlers/ServerInfo.cpp | 0 src/{ripple => xrpld}/rpc/handlers/ServerState.cpp | 0 src/{ripple => xrpld}/rpc/handlers/SignFor.cpp | 0 src/{ripple => xrpld}/rpc/handlers/SignHandler.cpp | 0 src/{ripple => xrpld}/rpc/handlers/Stop.cpp | 0 src/{ripple => xrpld}/rpc/handlers/Submit.cpp | 0 .../rpc/handlers/SubmitMultiSigned.cpp | 0 src/{ripple => xrpld}/rpc/handlers/Subscribe.cpp | 0 .../rpc/handlers/TransactionEntry.cpp | 0 src/{ripple => xrpld}/rpc/handlers/Tx.cpp | 0 src/{ripple => xrpld}/rpc/handlers/TxHistory.cpp | 0 .../rpc/handlers/TxReduceRelay.cpp | 0 src/{ripple => xrpld}/rpc/handlers/UnlList.cpp | 0 src/{ripple => xrpld}/rpc/handlers/Unsubscribe.cpp | 0 .../rpc/handlers/ValidationCreate.cpp | 0 .../rpc/handlers/ValidatorInfo.cpp | 0 .../rpc/handlers/ValidatorListSites.cpp | 0 src/{ripple => xrpld}/rpc/handlers/Validators.cpp | 0 src/{ripple => xrpld}/rpc/handlers/Version.h | 0 .../rpc/handlers/WalletPropose.cpp | 0 src/{ripple => xrpld}/rpc/handlers/WalletPropose.h | 0 src/{ripple => xrpld}/rpc/json_body.h | 0 src/{ripple => xrpld}/shamap/Family.h | 0 src/{ripple => xrpld}/shamap/FullBelowCache.h | 0 src/{ripple => xrpld}/shamap/NodeFamily.h | 0 src/{ripple => xrpld}/shamap/README.md | 0 src/{ripple => xrpld}/shamap/SHAMap.h | 0 .../shamap/SHAMapAccountStateLeafNode.h | 0 src/{ripple => xrpld}/shamap/SHAMapAddNode.h | 0 src/{ripple => xrpld}/shamap/SHAMapInnerNode.h | 0 src/{ripple => xrpld}/shamap/SHAMapItem.h | 0 src/{ripple => xrpld}/shamap/SHAMapLeafNode.h | 0 src/{ripple => xrpld}/shamap/SHAMapMissingNode.h | 0 src/{ripple => xrpld}/shamap/SHAMapNodeID.h | 0 src/{ripple => xrpld}/shamap/SHAMapSyncFilter.h | 0 src/{ripple => xrpld}/shamap/SHAMapTreeNode.h | 0 src/{ripple => xrpld}/shamap/SHAMapTxLeafNode.h | 0 .../shamap/SHAMapTxPlusMetaLeafNode.h | 0 src/{ripple => xrpld}/shamap/ShardFamily.h | 0 src/{ripple => xrpld}/shamap/TreeNodeCache.h | 0 .../impl => xrpld/shamap/detail}/NodeFamily.cpp | 0 .../shamap/impl => xrpld/shamap/detail}/SHAMap.cpp | 0 .../impl => xrpld/shamap/detail}/SHAMapDelta.cpp | 0 .../shamap/detail}/SHAMapInnerNode.cpp | 0 .../impl => xrpld/shamap/detail}/SHAMapLeafNode.cpp | 0 .../impl => xrpld/shamap/detail}/SHAMapNodeID.cpp | 0 .../impl => xrpld/shamap/detail}/SHAMapSync.cpp | 0 .../impl => xrpld/shamap/detail}/SHAMapTreeNode.cpp | 0 .../impl => xrpld/shamap/detail}/ShardFamily.cpp | 0 .../impl => xrpld/shamap/detail}/TaggedPointer.h | 0 .../impl => xrpld/shamap/detail}/TaggedPointer.ipp | 0 src/{ripple => xrpld}/unity/rocksdb.h | 0 994 files changed, 0 insertions(+), 0 deletions(-) rename {src/ripple => include/xrpl}/basics/Archive.h (100%) rename {src/ripple => include/xrpl}/basics/BasicConfig.h (100%) rename {src/ripple => include/xrpl}/basics/Blob.h (100%) rename {src/ripple => include/xrpl}/basics/Buffer.h (100%) rename {src/ripple => include/xrpl}/basics/ByteUtilities.h (100%) rename {src/ripple => include/xrpl}/basics/CompressionAlgorithms.h (100%) rename {src/ripple => include/xrpl}/basics/CountedObject.h (100%) rename {src/ripple => include/xrpl}/basics/DecayingSample.h (100%) rename {src/ripple => include/xrpl}/basics/Expected.h (100%) rename {src/ripple => include/xrpl}/basics/FeeUnits.h (100%) rename {src/ripple => include/xrpl}/basics/FileUtilities.h (100%) rename {src/ripple => include/xrpl}/basics/IOUAmount.h (100%) rename {src/ripple => include/xrpl}/basics/KeyCache.h (100%) rename {src/ripple => include/xrpl}/basics/LocalValue.h (100%) rename {src/ripple => include/xrpl}/basics/Log.h (100%) rename {src/ripple => include/xrpl}/basics/MathUtilities.h (100%) rename {src/ripple => include/xrpl}/basics/Number.h (100%) rename {src/ripple => include/xrpl}/basics/README.md (100%) rename {src/ripple => include/xrpl}/basics/RangeSet.h (100%) rename {src/ripple => include/xrpl}/basics/Resolver.h (100%) rename {src/ripple => include/xrpl}/basics/ResolverAsio.h (100%) rename {src/ripple => include/xrpl}/basics/SHAMapHash.h (100%) rename {src/ripple => include/xrpl}/basics/SlabAllocator.h (100%) rename {src/ripple => include/xrpl}/basics/Slice.h (100%) rename {src/ripple => include/xrpl}/basics/StringUtilities.h (100%) rename {src/ripple => include/xrpl}/basics/TaggedCache.h (100%) rename {src/ripple => include/xrpl}/basics/ThreadSafetyAnalysis.h (100%) rename {src/ripple => include/xrpl}/basics/ToString.h (100%) rename {src/ripple => include/xrpl}/basics/UnorderedContainers.h (100%) rename {src/ripple => include/xrpl}/basics/UptimeClock.h (100%) rename {src/ripple => include/xrpl}/basics/XRPAmount.h (100%) rename {src/ripple => include/xrpl}/basics/algorithm.h (100%) rename {src/ripple => include/xrpl}/basics/base64.h (100%) rename {src/ripple => include/xrpl}/basics/base_uint.h (100%) rename {src/ripple => include/xrpl}/basics/chrono.h (100%) rename {src/ripple => include/xrpl}/basics/comparators.h (100%) rename {src/ripple => include/xrpl}/basics/contract.h (100%) rename {src/ripple => include/xrpl}/basics/hardened_hash.h (100%) rename {src/ripple => include/xrpl}/basics/join.h (100%) rename {src/ripple => include/xrpl}/basics/make_SSLContext.h (100%) rename {src/ripple => include/xrpl}/basics/mulDiv.h (100%) rename {src/ripple => include/xrpl}/basics/partitioned_unordered_map.h (100%) rename {src/ripple => include/xrpl}/basics/random.h (100%) rename {src/ripple => include/xrpl}/basics/safe_cast.h (100%) rename {src/ripple => include/xrpl}/basics/scope.h (100%) rename {src/ripple => include/xrpl}/basics/spinlock.h (100%) rename {src/ripple => include/xrpl}/basics/strHex.h (100%) rename {src/ripple => include/xrpl}/basics/tagged_integer.h (100%) rename {src/ripple => include/xrpl}/beast/asio/io_latency_probe.h (100%) rename {src/ripple => include/xrpl}/beast/clock/abstract_clock.h (100%) rename {src/ripple => include/xrpl}/beast/clock/basic_seconds_clock.h (100%) rename {src/ripple => include/xrpl}/beast/clock/manual_clock.h (100%) rename {src/ripple => include/xrpl}/beast/container/aged_container.h (100%) rename {src/ripple => include/xrpl}/beast/container/aged_container_utility.h (100%) rename {src/ripple => include/xrpl}/beast/container/aged_map.h (100%) rename {src/ripple => include/xrpl}/beast/container/aged_multimap.h (100%) rename {src/ripple => include/xrpl}/beast/container/aged_multiset.h (100%) rename {src/ripple => include/xrpl}/beast/container/aged_set.h (100%) rename {src/ripple => include/xrpl}/beast/container/aged_unordered_map.h (100%) rename {src/ripple => include/xrpl}/beast/container/aged_unordered_multimap.h (100%) rename {src/ripple => include/xrpl}/beast/container/aged_unordered_multiset.h (100%) rename {src/ripple => include/xrpl}/beast/container/aged_unordered_set.h (100%) rename {src/ripple => include/xrpl}/beast/container/detail/aged_associative_container.h (100%) rename {src/ripple => include/xrpl}/beast/container/detail/aged_container_iterator.h (100%) rename {src/ripple => include/xrpl}/beast/container/detail/aged_ordered_container.h (100%) rename {src/ripple => include/xrpl}/beast/container/detail/aged_unordered_container.h (100%) rename {src/ripple => include/xrpl}/beast/container/detail/empty_base_optimization.h (100%) rename {src/ripple => include/xrpl}/beast/core/CurrentThreadName.h (100%) rename {src/ripple => include/xrpl}/beast/core/LexicalCast.h (100%) rename {src/ripple => include/xrpl}/beast/core/List.h (100%) rename {src/ripple => include/xrpl}/beast/core/LockFreeStack.h (100%) rename {src/ripple => include/xrpl}/beast/core/SemanticVersion.h (100%) rename {src/ripple => include/xrpl}/beast/hash/hash_append.h (100%) rename {src/ripple => include/xrpl}/beast/hash/uhash.h (100%) rename {src/ripple => include/xrpl}/beast/hash/xxhasher.h (100%) rename {src/ripple => include/xrpl}/beast/insight/Collector.h (100%) rename {src/ripple => include/xrpl}/beast/insight/Counter.h (100%) rename {src/ripple => include/xrpl}/beast/insight/CounterImpl.h (100%) rename {src/ripple => include/xrpl}/beast/insight/Event.h (100%) rename {src/ripple => include/xrpl}/beast/insight/EventImpl.h (100%) rename {src/ripple => include/xrpl}/beast/insight/Gauge.h (100%) rename {src/ripple => include/xrpl}/beast/insight/GaugeImpl.h (100%) rename {src/ripple => include/xrpl}/beast/insight/Group.h (100%) rename {src/ripple => include/xrpl}/beast/insight/Groups.h (100%) rename {src/ripple => include/xrpl}/beast/insight/Hook.h (100%) rename {src/ripple => include/xrpl}/beast/insight/HookImpl.h (100%) rename {src/ripple => include/xrpl}/beast/insight/Insight.h (100%) rename {src/ripple => include/xrpl}/beast/insight/Meter.h (100%) rename {src/ripple => include/xrpl}/beast/insight/MeterImpl.h (100%) rename {src/ripple => include/xrpl}/beast/insight/NullCollector.h (100%) rename {src/ripple => include/xrpl}/beast/insight/StatsDCollector.h (100%) rename {src/ripple => include/xrpl}/beast/net/IPAddress.h (100%) rename {src/ripple => include/xrpl}/beast/net/IPAddressConversion.h (100%) rename {src/ripple => include/xrpl}/beast/net/IPAddressV4.h (100%) rename {src/ripple => include/xrpl}/beast/net/IPAddressV6.h (100%) rename {src/ripple => include/xrpl}/beast/net/IPEndpoint.h (100%) rename {src/ripple => include/xrpl}/beast/rfc2616.h (100%) rename {src/ripple => include/xrpl}/beast/test/fail_counter.h (100%) rename {src/ripple => include/xrpl}/beast/test/fail_stream.h (100%) rename {src/ripple => include/xrpl}/beast/test/pipe_stream.h (100%) rename {src/ripple => include/xrpl}/beast/test/sig_wait.h (100%) rename {src/ripple => include/xrpl}/beast/test/string_iostream.h (100%) rename {src/ripple => include/xrpl}/beast/test/string_istream.h (100%) rename {src/ripple => include/xrpl}/beast/test/string_ostream.h (100%) rename {src/ripple => include/xrpl}/beast/test/test_allocator.h (100%) rename {src/ripple => include/xrpl}/beast/test/yield_to.h (100%) rename {src/ripple => include/xrpl}/beast/type_name.h (100%) rename {src/ripple => include/xrpl}/beast/unit_test.h (100%) rename {src/ripple => include/xrpl}/beast/unit_test/amount.h (100%) rename {src/ripple => include/xrpl}/beast/unit_test/detail/const_container.h (100%) rename {src/ripple => include/xrpl}/beast/unit_test/dstream.h (100%) rename {src/ripple => include/xrpl}/beast/unit_test/global_suites.h (100%) rename {src/ripple => include/xrpl}/beast/unit_test/match.h (100%) rename {src/ripple => include/xrpl}/beast/unit_test/recorder.h (100%) rename {src/ripple => include/xrpl}/beast/unit_test/reporter.h (100%) rename {src/ripple => include/xrpl}/beast/unit_test/results.h (100%) rename {src/ripple => include/xrpl}/beast/unit_test/runner.h (100%) rename {src/ripple => include/xrpl}/beast/unit_test/suite.h (100%) rename {src/ripple => include/xrpl}/beast/unit_test/suite_info.h (100%) rename {src/ripple => include/xrpl}/beast/unit_test/suite_list.h (100%) rename {src/ripple => include/xrpl}/beast/unit_test/thread.h (100%) rename {src/ripple => include/xrpl}/beast/utility/Journal.h (100%) rename {src/ripple => include/xrpl}/beast/utility/PropertyStream.h (100%) rename {src/ripple => include/xrpl}/beast/utility/WrappedSink.h (100%) rename {src/ripple => include/xrpl}/beast/utility/Zero.h (100%) rename {src/ripple => include/xrpl}/beast/utility/hash_pair.h (100%) rename {src/ripple => include/xrpl}/beast/utility/maybe_const.h (100%) rename {src/ripple => include/xrpl}/beast/utility/rngfill.h (100%) rename {src/ripple => include/xrpl}/beast/utility/temp_dir.h (100%) rename {src/ripple => include/xrpl}/beast/xor_shift_engine.h (100%) rename {src/ripple => include/xrpl}/crypto/README.md (100%) rename {src/ripple => include/xrpl}/crypto/RFC1751.h (100%) rename {src/ripple => include/xrpl}/crypto/csprng.h (100%) rename {src/ripple => include/xrpl}/crypto/secure_erase.h (100%) rename {src/ripple => include/xrpl}/json/JsonPropertyStream.h (100%) rename {src/ripple => include/xrpl}/json/Object.h (100%) rename {src/ripple => include/xrpl}/json/Output.h (100%) rename {src/ripple => include/xrpl}/json/README.md (100%) rename {src/ripple => include/xrpl}/json/Writer.h (100%) rename {src/ripple/json/impl => include/xrpl/json/detail}/json_assert.h (100%) rename {src/ripple => include/xrpl}/json/json_errors.h (100%) rename {src/ripple => include/xrpl}/json/json_forwards.h (100%) rename {src/ripple => include/xrpl}/json/json_reader.h (100%) rename {src/ripple => include/xrpl}/json/json_value.h (100%) rename {src/ripple => include/xrpl}/json/json_writer.h (100%) rename {src/ripple => include/xrpl}/json/to_string.h (100%) rename {src/ripple => include/xrpl}/proto/README.md (100%) rename {src/ripple => include/xrpl}/proto/org/xrpl/rpc/v1/README.md (100%) rename {src/ripple => include/xrpl}/proto/org/xrpl/rpc/v1/get_ledger.proto (100%) rename {src/ripple => include/xrpl}/proto/org/xrpl/rpc/v1/get_ledger_data.proto (100%) rename {src/ripple => include/xrpl}/proto/org/xrpl/rpc/v1/get_ledger_diff.proto (100%) rename {src/ripple => include/xrpl}/proto/org/xrpl/rpc/v1/get_ledger_entry.proto (100%) rename {src/ripple => include/xrpl}/proto/org/xrpl/rpc/v1/ledger.proto (100%) rename {src/ripple => include/xrpl}/proto/org/xrpl/rpc/v1/xrp_ledger.proto (100%) rename {src/ripple => include/xrpl}/proto/ripple.proto (100%) rename {src/ripple => include/xrpl}/protocol/AMMCore.h (100%) rename {src/ripple => include/xrpl}/protocol/AccountID.h (100%) rename {src/ripple => include/xrpl}/protocol/AmountConversions.h (100%) rename {src/ripple => include/xrpl}/protocol/ApiVersion.h (100%) rename {src/ripple => include/xrpl}/protocol/Book.h (100%) rename {src/ripple => include/xrpl}/protocol/BuildInfo.h (100%) rename {src/ripple => include/xrpl}/protocol/ErrorCodes.h (100%) rename {src/ripple => include/xrpl}/protocol/Feature.h (100%) rename {src/ripple => include/xrpl}/protocol/Fees.h (100%) rename {src/ripple => include/xrpl}/protocol/HashPrefix.h (100%) rename {src/ripple => include/xrpl}/protocol/Indexes.h (100%) rename {src/ripple => include/xrpl}/protocol/InnerObjectFormats.h (100%) rename {src/ripple => include/xrpl}/protocol/Issue.h (100%) rename {src/ripple => include/xrpl}/protocol/KeyType.h (100%) rename {src/ripple => include/xrpl}/protocol/Keylet.h (100%) rename {src/ripple => include/xrpl}/protocol/KnownFormats.h (100%) rename {src/ripple => include/xrpl}/protocol/LedgerFormats.h (100%) rename {src/ripple => include/xrpl}/protocol/LedgerHeader.h (100%) rename {src/ripple => include/xrpl}/protocol/MultiApiJson.h (100%) rename {src/ripple => include/xrpl}/protocol/NFTSyntheticSerializer.h (100%) rename {src/ripple => include/xrpl}/protocol/NFTokenID.h (100%) rename {src/ripple => include/xrpl}/protocol/NFTokenOfferID.h (100%) rename {src/ripple => include/xrpl}/protocol/PayChan.h (100%) rename {src/ripple => include/xrpl}/protocol/Protocol.h (100%) rename {src/ripple => include/xrpl}/protocol/PublicKey.h (100%) rename {src/ripple => include/xrpl}/protocol/Quality.h (100%) rename {src/ripple => include/xrpl}/protocol/QualityFunction.h (100%) rename {src/ripple => include/xrpl}/protocol/README.md (100%) rename {src/ripple => include/xrpl}/protocol/RPCErr.h (100%) rename {src/ripple => include/xrpl}/protocol/Rate.h (100%) rename {src/ripple => include/xrpl}/protocol/RippleLedgerHash.h (100%) rename {src/ripple => include/xrpl}/protocol/Rules.h (100%) rename {src/ripple => include/xrpl}/protocol/SField.h (100%) rename {src/ripple => include/xrpl}/protocol/SOTemplate.h (100%) rename {src/ripple => include/xrpl}/protocol/STAccount.h (100%) rename {src/ripple => include/xrpl}/protocol/STAmount.h (100%) rename {src/ripple => include/xrpl}/protocol/STArray.h (100%) rename {src/ripple => include/xrpl}/protocol/STBase.h (100%) rename {src/ripple => include/xrpl}/protocol/STBitString.h (100%) rename {src/ripple => include/xrpl}/protocol/STBlob.h (100%) rename {src/ripple => include/xrpl}/protocol/STCurrency.h (100%) rename {src/ripple => include/xrpl}/protocol/STExchange.h (100%) rename {src/ripple => include/xrpl}/protocol/STInteger.h (100%) rename {src/ripple => include/xrpl}/protocol/STIssue.h (100%) rename {src/ripple => include/xrpl}/protocol/STLedgerEntry.h (100%) rename {src/ripple => include/xrpl}/protocol/STObject.h (100%) rename {src/ripple => include/xrpl}/protocol/STParsedJSON.h (100%) rename {src/ripple => include/xrpl}/protocol/STPathSet.h (100%) rename {src/ripple => include/xrpl}/protocol/STTx.h (100%) rename {src/ripple => include/xrpl}/protocol/STValidation.h (100%) rename {src/ripple => include/xrpl}/protocol/STVector256.h (100%) rename {src/ripple => include/xrpl}/protocol/STXChainBridge.h (100%) rename {src/ripple => include/xrpl}/protocol/SecretKey.h (100%) rename {src/ripple => include/xrpl}/protocol/Seed.h (100%) rename {src/ripple => include/xrpl}/protocol/SeqProxy.h (100%) rename {src/ripple => include/xrpl}/protocol/Serializer.h (100%) rename {src/ripple => include/xrpl}/protocol/Sign.h (100%) rename {src/ripple => include/xrpl}/protocol/SystemParameters.h (100%) rename {src/ripple => include/xrpl}/protocol/TER.h (100%) rename {src/ripple => include/xrpl}/protocol/TxFlags.h (100%) rename {src/ripple => include/xrpl}/protocol/TxFormats.h (100%) rename {src/ripple => include/xrpl}/protocol/TxMeta.h (100%) rename {src/ripple => include/xrpl}/protocol/UintTypes.h (100%) rename {src/ripple => include/xrpl}/protocol/XChainAttestations.h (100%) rename {src/ripple/protocol/impl => include/xrpl/protocol/detail}/STVar.h (100%) rename {src/ripple/protocol/impl => include/xrpl/protocol/detail}/b58_utils.h (100%) rename {src/ripple/protocol/impl => include/xrpl/protocol/detail}/secp256k1.h (100%) rename {src/ripple/protocol/impl => include/xrpl/protocol/detail}/token_errors.h (100%) rename {src/ripple => include/xrpl}/protocol/digest.h (100%) rename {src/ripple => include/xrpl}/protocol/json_get_or_throw.h (100%) rename {src/ripple => include/xrpl}/protocol/jss.h (100%) rename {src/ripple => include/xrpl}/protocol/messages.h (100%) rename {src/ripple => include/xrpl}/protocol/nft.h (100%) rename {src/ripple => include/xrpl}/protocol/nftPageMask.h (100%) rename {src/ripple => include/xrpl}/protocol/serialize.h (100%) rename {src/ripple => include/xrpl}/protocol/st.h (100%) rename {src/ripple => include/xrpl}/protocol/tokens.h (100%) rename {src/ripple => include/xrpl}/resource/Charge.h (100%) rename {src/ripple => include/xrpl}/resource/Consumer.h (100%) rename {src/ripple => include/xrpl}/resource/Disposition.h (100%) rename {src/ripple => include/xrpl}/resource/Fees.h (100%) rename {src/ripple => include/xrpl}/resource/Gossip.h (100%) rename {src/ripple => include/xrpl}/resource/README.md (100%) rename {src/ripple => include/xrpl}/resource/ResourceManager.h (100%) rename {src/ripple => include/xrpl}/resource/Types.h (100%) rename {src/ripple/resource/impl => include/xrpl/resource/detail}/Entry.h (100%) rename {src/ripple/resource/impl => include/xrpl/resource/detail}/Import.h (100%) rename {src/ripple/resource/impl => include/xrpl/resource/detail}/Key.h (100%) rename {src/ripple/resource/impl => include/xrpl/resource/detail}/Kind.h (100%) rename {src/ripple/resource/impl => include/xrpl/resource/detail}/Logic.h (100%) rename {src/ripple/resource/impl => include/xrpl/resource/detail}/Tuning.h (100%) rename {src/ripple => include/xrpl}/server/Handoff.h (100%) rename {src/ripple => include/xrpl}/server/Port.h (100%) rename {src/ripple => include/xrpl}/server/Server.h (100%) rename {src/ripple => include/xrpl}/server/Session.h (100%) rename {src/ripple => include/xrpl}/server/SimpleWriter.h (100%) rename {src/ripple => include/xrpl}/server/WSSession.h (100%) rename {src/ripple => include/xrpl}/server/Writer.h (100%) rename {src/ripple/server/impl => include/xrpl/server/detail}/BaseHTTPPeer.h (100%) rename {src/ripple/server/impl => include/xrpl/server/detail}/BasePeer.h (100%) rename {src/ripple/server/impl => include/xrpl/server/detail}/BaseWSPeer.h (100%) rename {src/ripple/server/impl => include/xrpl/server/detail}/Door.h (100%) rename {src/ripple/server/impl => include/xrpl/server/detail}/JSONRPCUtil.h (100%) rename {src/ripple/server/impl => include/xrpl/server/detail}/LowestLayer.h (100%) rename {src/ripple/server/impl => include/xrpl/server/detail}/PlainHTTPPeer.h (100%) rename {src/ripple/server/impl => include/xrpl/server/detail}/PlainWSPeer.h (100%) rename {src/ripple/server/impl => include/xrpl/server/detail}/SSLHTTPPeer.h (100%) rename {src/ripple/server/impl => include/xrpl/server/detail}/SSLWSPeer.h (100%) rename {src/ripple/server/impl => include/xrpl/server/detail}/ServerImpl.h (100%) rename {src/ripple/server/impl => include/xrpl/server/detail}/io_list.h (100%) rename src/{ripple/basics/impl => libxrpl/basics}/Archive.cpp (100%) rename src/{ripple/basics/impl => libxrpl/basics}/BasicConfig.cpp (100%) rename src/{ripple/basics/impl => libxrpl/basics}/CountedObject.cpp (100%) rename src/{ripple/basics/impl => libxrpl/basics}/FileUtilities.cpp (100%) rename src/{ripple/basics/impl => libxrpl/basics}/IOUAmount.cpp (100%) rename src/{ripple/basics/impl => libxrpl/basics}/Log.cpp (100%) rename src/{ripple/basics/impl => libxrpl/basics}/Number.cpp (100%) rename src/{ripple/basics/impl => libxrpl/basics}/ResolverAsio.cpp (100%) rename src/{ripple/basics/impl => libxrpl/basics}/StringUtilities.cpp (100%) rename src/{ripple/basics/impl => libxrpl/basics}/UptimeClock.cpp (100%) rename src/{ripple/basics/impl => libxrpl/basics}/base64.cpp (100%) rename src/{ripple/basics/impl => libxrpl/basics}/contract.cpp (100%) rename src/{ripple/basics/impl => libxrpl/basics}/make_SSLContext.cpp (100%) rename src/{ripple/basics/impl => libxrpl/basics}/mulDiv.cpp (100%) rename src/{ripple/basics/impl => libxrpl/basics}/partitioned_unordered_map.cpp (100%) rename src/{ripple => libxrpl}/beast/clock/basic_seconds_clock.cpp (100%) rename src/{ripple => libxrpl}/beast/core/CurrentThreadName.cpp (100%) rename src/{ripple => libxrpl}/beast/core/SemanticVersion.cpp (100%) rename src/{ripple/beast/insight/impl => libxrpl/beast/insight}/Collector.cpp (100%) rename src/{ripple/beast/insight/impl => libxrpl/beast/insight}/Groups.cpp (100%) rename src/{ripple/beast/insight/impl => libxrpl/beast/insight}/Hook.cpp (100%) rename src/{ripple/beast/insight/impl => libxrpl/beast/insight}/Metric.cpp (100%) rename src/{ripple/beast/insight/impl => libxrpl/beast/insight}/NullCollector.cpp (100%) rename src/{ripple/beast/insight/impl => libxrpl/beast/insight}/StatsDCollector.cpp (100%) rename src/{ripple/beast/net/impl => libxrpl/beast/net}/IPAddressConversion.cpp (100%) rename src/{ripple/beast/net/impl => libxrpl/beast/net}/IPAddressV4.cpp (100%) rename src/{ripple/beast/net/impl => libxrpl/beast/net}/IPAddressV6.cpp (100%) rename src/{ripple/beast/net/impl => libxrpl/beast/net}/IPEndpoint.cpp (100%) rename src/{ripple => libxrpl}/beast/utility/src/beast_Journal.cpp (100%) rename src/{ripple => libxrpl}/beast/utility/src/beast_PropertyStream.cpp (100%) rename src/{ripple/crypto/impl => libxrpl/crypto}/RFC1751.cpp (100%) rename src/{ripple/crypto/impl => libxrpl/crypto}/csprng.cpp (100%) rename src/{ripple/crypto/impl => libxrpl/crypto}/secure_erase.cpp (100%) rename src/{ripple/json/impl => libxrpl/json}/JsonPropertyStream.cpp (100%) rename src/{ripple/json/impl => libxrpl/json}/Object.cpp (100%) rename src/{ripple/json/impl => libxrpl/json}/Output.cpp (100%) rename src/{ripple/json/impl => libxrpl/json}/Writer.cpp (100%) rename src/{ripple/json/impl => libxrpl/json}/json_reader.cpp (100%) rename src/{ripple/json/impl => libxrpl/json}/json_value.cpp (100%) rename src/{ripple/json/impl => libxrpl/json}/json_valueiterator.cpp (100%) rename src/{ripple/json/impl => libxrpl/json}/json_writer.cpp (100%) rename src/{ripple/json/impl => libxrpl/json}/to_string.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/AMMCore.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/AccountID.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/Book.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/BuildInfo.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/ErrorCodes.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/Feature.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/Indexes.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/InnerObjectFormats.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/Issue.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/Keylet.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/LedgerFormats.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/LedgerHeader.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/NFTSyntheticSerializer.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/NFTokenID.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/NFTokenOfferID.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/PublicKey.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/Quality.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/QualityFunction.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/RPCErr.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/Rate2.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/Rules.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/SField.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/SOTemplate.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/STAccount.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/STAmount.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/STArray.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/STBase.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/STBlob.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/STCurrency.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/STInteger.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/STIssue.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/STLedgerEntry.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/STObject.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/STParsedJSON.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/STPathSet.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/STTx.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/STValidation.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/STVar.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/STVector256.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/STXChainBridge.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/SecretKey.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/Seed.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/Serializer.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/Sign.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/TER.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/TxFormats.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/TxMeta.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/UintTypes.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/XChainAttestations.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/digest.cpp (100%) rename src/{ripple/protocol/impl => libxrpl/protocol}/tokens.cpp (100%) rename src/{ripple/resource/impl => libxrpl/resource}/Charge.cpp (100%) rename src/{ripple/resource/impl => libxrpl/resource}/Consumer.cpp (100%) rename src/{ripple/resource/impl => libxrpl/resource}/Fees.cpp (100%) rename src/{ripple/resource/impl => libxrpl/resource}/ResourceManager.cpp (100%) rename src/{ripple/server/impl => libxrpl/server}/JSONRPCUtil.cpp (100%) rename src/{ripple/server/impl => libxrpl/server}/Port.cpp (100%) rename src/{ripple => xrpld}/README.md (100%) rename src/{ripple => xrpld}/app/consensus/RCLCensorshipDetector.h (100%) rename src/{ripple => xrpld}/app/consensus/RCLConsensus.cpp (100%) rename src/{ripple => xrpld}/app/consensus/RCLConsensus.h (100%) rename src/{ripple => xrpld}/app/consensus/RCLCxLedger.h (100%) rename src/{ripple => xrpld}/app/consensus/RCLCxPeerPos.cpp (100%) rename src/{ripple => xrpld}/app/consensus/RCLCxPeerPos.h (100%) rename src/{ripple => xrpld}/app/consensus/RCLCxTx.h (100%) rename src/{ripple => xrpld}/app/consensus/RCLValidations.cpp (100%) rename src/{ripple => xrpld}/app/consensus/RCLValidations.h (100%) rename src/{ripple => xrpld}/app/consensus/README.md (100%) rename src/{ripple => xrpld}/app/ledger/AbstractFetchPackContainer.h (100%) rename src/{ripple => xrpld}/app/ledger/AcceptedLedger.cpp (100%) rename src/{ripple => xrpld}/app/ledger/AcceptedLedger.h (100%) rename src/{ripple => xrpld}/app/ledger/AcceptedLedgerTx.cpp (100%) rename src/{ripple => xrpld}/app/ledger/AcceptedLedgerTx.h (100%) rename src/{ripple => xrpld}/app/ledger/AccountStateSF.cpp (100%) rename src/{ripple => xrpld}/app/ledger/AccountStateSF.h (100%) rename src/{ripple => xrpld}/app/ledger/BookListeners.cpp (100%) rename src/{ripple => xrpld}/app/ledger/BookListeners.h (100%) rename src/{ripple => xrpld}/app/ledger/BuildLedger.h (100%) rename src/{ripple => xrpld}/app/ledger/ConsensusTransSetSF.cpp (100%) rename src/{ripple => xrpld}/app/ledger/ConsensusTransSetSF.h (100%) rename src/{ripple => xrpld}/app/ledger/InboundLedger.h (100%) rename src/{ripple => xrpld}/app/ledger/InboundLedgers.h (100%) rename src/{ripple => xrpld}/app/ledger/InboundTransactions.h (100%) rename src/{ripple => xrpld}/app/ledger/InboundTransactions.uml (100%) rename src/{ripple => xrpld}/app/ledger/Ledger.cpp (100%) rename src/{ripple => xrpld}/app/ledger/Ledger.h (100%) rename src/{ripple => xrpld}/app/ledger/LedgerCleaner.h (100%) rename src/{ripple => xrpld}/app/ledger/LedgerHistory.cpp (100%) rename src/{ripple => xrpld}/app/ledger/LedgerHistory.h (100%) rename src/{ripple => xrpld}/app/ledger/LedgerHolder.h (100%) rename src/{ripple => xrpld}/app/ledger/LedgerMaster.h (100%) rename src/{ripple => xrpld}/app/ledger/LedgerReplay.h (100%) rename src/{ripple => xrpld}/app/ledger/LedgerReplayTask.h (100%) rename src/{ripple => xrpld}/app/ledger/LedgerReplayer.h (100%) rename src/{ripple => xrpld}/app/ledger/LedgerToJson.h (100%) rename src/{ripple => xrpld}/app/ledger/LocalTxs.h (100%) rename src/{ripple => xrpld}/app/ledger/OpenLedger.h (100%) rename src/{ripple => xrpld}/app/ledger/OrderBookDB.cpp (100%) rename src/{ripple => xrpld}/app/ledger/OrderBookDB.h (100%) rename src/{ripple => xrpld}/app/ledger/PendingSaves.h (100%) rename src/{ripple => xrpld}/app/ledger/README.md (100%) rename src/{ripple => xrpld}/app/ledger/TransactionMaster.h (100%) rename src/{ripple => xrpld}/app/ledger/TransactionStateSF.cpp (100%) rename src/{ripple => xrpld}/app/ledger/TransactionStateSF.h (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/BuildLedger.cpp (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/InboundLedger.cpp (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/InboundLedgers.cpp (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/InboundTransactions.cpp (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/LedgerCleaner.cpp (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/LedgerDeltaAcquire.cpp (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/LedgerDeltaAcquire.h (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/LedgerMaster.cpp (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/LedgerReplay.cpp (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/LedgerReplayMsgHandler.cpp (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/LedgerReplayMsgHandler.h (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/LedgerReplayTask.cpp (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/LedgerReplayer.cpp (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/LedgerToJson.cpp (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/LocalTxs.cpp (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/OpenLedger.cpp (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/SkipListAcquire.cpp (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/SkipListAcquire.h (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/TimeoutCounter.cpp (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/TimeoutCounter.h (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/TransactionAcquire.cpp (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/TransactionAcquire.h (100%) rename src/{ripple/app/ledger/impl => xrpld/app/ledger/detail}/TransactionMaster.cpp (100%) rename src/{ripple => xrpld}/app/main/Application.cpp (100%) rename src/{ripple => xrpld}/app/main/Application.h (100%) rename src/{ripple => xrpld}/app/main/BasicApp.cpp (100%) rename src/{ripple => xrpld}/app/main/BasicApp.h (100%) rename src/{ripple => xrpld}/app/main/CollectorManager.cpp (100%) rename src/{ripple => xrpld}/app/main/CollectorManager.h (100%) rename src/{ripple => xrpld}/app/main/DBInit.h (100%) rename src/{ripple => xrpld}/app/main/GRPCServer.cpp (100%) rename src/{ripple => xrpld}/app/main/GRPCServer.h (100%) rename src/{ripple => xrpld}/app/main/LoadManager.cpp (100%) rename src/{ripple => xrpld}/app/main/LoadManager.h (100%) rename src/{ripple => xrpld}/app/main/Main.cpp (100%) rename src/{ripple => xrpld}/app/main/NodeIdentity.cpp (100%) rename src/{ripple => xrpld}/app/main/NodeIdentity.h (100%) rename src/{ripple => xrpld}/app/main/NodeStoreScheduler.cpp (100%) rename src/{ripple => xrpld}/app/main/NodeStoreScheduler.h (100%) rename src/{ripple => xrpld}/app/main/Tuning.h (100%) rename src/{ripple => xrpld}/app/misc/AMMHelpers.h (100%) rename src/{ripple => xrpld}/app/misc/AMMUtils.h (100%) rename src/{ripple => xrpld}/app/misc/AmendmentTable.h (100%) rename src/{ripple => xrpld}/app/misc/CanonicalTXSet.cpp (100%) rename src/{ripple => xrpld}/app/misc/CanonicalTXSet.h (100%) rename src/{ripple => xrpld}/app/misc/DeliverMax.h (100%) rename src/{ripple => xrpld}/app/misc/FeeEscalation.md (100%) rename src/{ripple => xrpld}/app/misc/FeeVote.h (100%) rename src/{ripple => xrpld}/app/misc/FeeVoteImpl.cpp (100%) rename src/{ripple => xrpld}/app/misc/HashRouter.cpp (100%) rename src/{ripple => xrpld}/app/misc/HashRouter.h (100%) rename src/{ripple => xrpld}/app/misc/LoadFeeTrack.h (100%) rename src/{ripple => xrpld}/app/misc/Manifest.h (100%) rename src/{ripple => xrpld}/app/misc/NegativeUNLVote.cpp (100%) rename src/{ripple => xrpld}/app/misc/NegativeUNLVote.h (100%) rename src/{ripple => xrpld}/app/misc/NetworkOPs.cpp (100%) rename src/{ripple => xrpld}/app/misc/NetworkOPs.h (100%) rename src/{ripple => xrpld}/app/misc/README.md (100%) rename src/{ripple => xrpld}/app/misc/SHAMapStore.h (100%) rename src/{ripple => xrpld}/app/misc/SHAMapStoreImp.cpp (100%) rename src/{ripple => xrpld}/app/misc/SHAMapStoreImp.h (100%) rename src/{ripple => xrpld}/app/misc/Transaction.h (100%) rename src/{ripple => xrpld}/app/misc/TxQ.h (100%) rename src/{ripple => xrpld}/app/misc/ValidatorKeys.h (100%) rename src/{ripple => xrpld}/app/misc/ValidatorList.h (100%) rename src/{ripple => xrpld}/app/misc/ValidatorSite.h (100%) rename src/{ripple/app/misc/impl => xrpld/app/misc/detail}/AMMHelpers.cpp (100%) rename src/{ripple/app/misc/impl => xrpld/app/misc/detail}/AMMUtils.cpp (100%) rename src/{ripple/app/misc/impl => xrpld/app/misc/detail}/AccountTxPaging.cpp (100%) rename src/{ripple/app/misc/impl => xrpld/app/misc/detail}/AccountTxPaging.h (100%) rename src/{ripple/app/misc/impl => xrpld/app/misc/detail}/AmendmentTable.cpp (100%) rename src/{ripple/app/misc/impl => xrpld/app/misc/detail}/DeliverMax.cpp (100%) rename src/{ripple/app/misc/impl => xrpld/app/misc/detail}/LoadFeeTrack.cpp (100%) rename src/{ripple/app/misc/impl => xrpld/app/misc/detail}/Manifest.cpp (100%) rename src/{ripple/app/misc/impl => xrpld/app/misc/detail}/Transaction.cpp (100%) rename src/{ripple/app/misc/impl => xrpld/app/misc/detail}/TxQ.cpp (100%) rename src/{ripple/app/misc/impl => xrpld/app/misc/detail}/ValidatorKeys.cpp (100%) rename src/{ripple/app/misc/impl => xrpld/app/misc/detail}/ValidatorList.cpp (100%) rename src/{ripple/app/misc/impl => xrpld/app/misc/detail}/ValidatorSite.cpp (100%) rename src/{ripple => xrpld}/app/misc/detail/Work.h (100%) rename src/{ripple => xrpld}/app/misc/detail/WorkBase.h (100%) rename src/{ripple => xrpld}/app/misc/detail/WorkFile.h (100%) rename src/{ripple => xrpld}/app/misc/detail/WorkPlain.h (100%) rename src/{ripple => xrpld}/app/misc/detail/WorkSSL.h (100%) rename src/{ripple/app/misc/detail/impl => xrpld/app/misc/detail/detail}/WorkSSL.cpp (100%) rename src/{ripple => xrpld}/app/paths/AMMContext.h (100%) rename src/{ripple => xrpld}/app/paths/AMMLiquidity.h (100%) rename src/{ripple => xrpld}/app/paths/AMMOffer.h (100%) rename src/{ripple => xrpld}/app/paths/AccountCurrencies.cpp (100%) rename src/{ripple => xrpld}/app/paths/AccountCurrencies.h (100%) rename src/{ripple => xrpld}/app/paths/Credit.cpp (100%) rename src/{ripple => xrpld}/app/paths/Credit.h (100%) rename src/{ripple => xrpld}/app/paths/Flow.cpp (100%) rename src/{ripple => xrpld}/app/paths/Flow.h (100%) rename src/{ripple => xrpld}/app/paths/PathRequest.cpp (100%) rename src/{ripple => xrpld}/app/paths/PathRequest.h (100%) rename src/{ripple => xrpld}/app/paths/PathRequests.cpp (100%) rename src/{ripple => xrpld}/app/paths/PathRequests.h (100%) rename src/{ripple => xrpld}/app/paths/Pathfinder.cpp (100%) rename src/{ripple => xrpld}/app/paths/Pathfinder.h (100%) rename src/{ripple => xrpld}/app/paths/RippleCalc.cpp (100%) rename src/{ripple => xrpld}/app/paths/RippleCalc.h (100%) rename src/{ripple => xrpld}/app/paths/RippleLineCache.cpp (100%) rename src/{ripple => xrpld}/app/paths/RippleLineCache.h (100%) rename src/{ripple => xrpld}/app/paths/TrustLine.cpp (100%) rename src/{ripple => xrpld}/app/paths/TrustLine.h (100%) rename src/{ripple/app/paths/impl => xrpld/app/paths/detail}/AMMLiquidity.cpp (100%) rename src/{ripple/app/paths/impl => xrpld/app/paths/detail}/AMMOffer.cpp (100%) rename src/{ripple/app/paths/impl => xrpld/app/paths/detail}/AmountSpec.h (100%) rename src/{ripple/app/paths/impl => xrpld/app/paths/detail}/BookStep.cpp (100%) rename src/{ripple/app/paths/impl => xrpld/app/paths/detail}/DirectStep.cpp (100%) rename src/{ripple/app/paths/impl => xrpld/app/paths/detail}/FlatSets.h (100%) rename src/{ripple/app/paths/impl => xrpld/app/paths/detail}/FlowDebugInfo.h (100%) rename src/{ripple/app/paths/impl => xrpld/app/paths/detail}/PathfinderUtils.h (100%) rename src/{ripple/app/paths/impl => xrpld/app/paths/detail}/PaySteps.cpp (100%) rename src/{ripple/app/paths/impl => xrpld/app/paths/detail}/StepChecks.h (100%) rename src/{ripple/app/paths/impl => xrpld/app/paths/detail}/Steps.h (100%) rename src/{ripple/app/paths/impl => xrpld/app/paths/detail}/StrandFlow.h (100%) rename src/{ripple/app/paths/impl => xrpld/app/paths/detail}/XRPEndpointStep.cpp (100%) rename src/{ripple => xrpld}/app/rdb/Download.h (100%) rename src/{ripple => xrpld}/app/rdb/PeerFinder.h (100%) rename src/{ripple => xrpld}/app/rdb/README.md (100%) rename src/{ripple => xrpld}/app/rdb/RelationalDatabase.h (100%) rename src/{ripple => xrpld}/app/rdb/ShardArchive.h (100%) rename src/{ripple => xrpld}/app/rdb/State.h (100%) rename src/{ripple => xrpld}/app/rdb/UnitaryShard.h (100%) rename src/{ripple => xrpld}/app/rdb/Vacuum.h (100%) rename src/{ripple => xrpld}/app/rdb/Wallet.h (100%) rename src/{ripple => xrpld}/app/rdb/backend/PostgresDatabase.h (100%) rename src/{ripple => xrpld}/app/rdb/backend/SQLiteDatabase.h (100%) rename src/{ripple => xrpld}/app/rdb/backend/detail/Node.h (100%) rename src/{ripple/app/rdb/backend/impl => xrpld/app/rdb/backend/detail}/PostgresDatabase.cpp (100%) rename src/{ripple/app/rdb/backend/impl => xrpld/app/rdb/backend/detail}/SQLiteDatabase.cpp (100%) rename src/{ripple => xrpld}/app/rdb/backend/detail/Shard.h (100%) rename src/{ripple/app/rdb/backend/detail/impl => xrpld/app/rdb/backend/detail/detail}/Node.cpp (100%) rename src/{ripple/app/rdb/backend/detail/impl => xrpld/app/rdb/backend/detail/detail}/Shard.cpp (100%) rename src/{ripple/app/rdb/impl => xrpld/app/rdb/detail}/Download.cpp (100%) rename src/{ripple/app/rdb/impl => xrpld/app/rdb/detail}/PeerFinder.cpp (100%) rename src/{ripple/app/rdb/impl => xrpld/app/rdb/detail}/RelationalDatabase.cpp (100%) rename src/{ripple/app/rdb/impl => xrpld/app/rdb/detail}/ShardArchive.cpp (100%) rename src/{ripple/app/rdb/impl => xrpld/app/rdb/detail}/State.cpp (100%) rename src/{ripple/app/rdb/impl => xrpld/app/rdb/detail}/UnitaryShard.cpp (100%) rename src/{ripple/app/rdb/impl => xrpld/app/rdb/detail}/Vacuum.cpp (100%) rename src/{ripple/app/rdb/impl => xrpld/app/rdb/detail}/Wallet.cpp (100%) rename src/{ripple => xrpld}/app/reporting/ETLHelpers.h (100%) rename src/{ripple => xrpld}/app/reporting/ETLSource.cpp (100%) rename src/{ripple => xrpld}/app/reporting/ETLSource.h (100%) rename src/{ripple => xrpld}/app/reporting/P2pProxy.cpp (100%) rename src/{ripple => xrpld}/app/reporting/P2pProxy.h (100%) rename src/{ripple => xrpld}/app/reporting/README.md (100%) rename src/{ripple => xrpld}/app/reporting/ReportingETL.cpp (100%) rename src/{ripple => xrpld}/app/reporting/ReportingETL.h (100%) rename src/{ripple => xrpld}/app/tx/apply.h (100%) rename src/{ripple => xrpld}/app/tx/applySteps.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/AMMBid.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/AMMBid.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/AMMCreate.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/AMMCreate.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/AMMDelete.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/AMMDelete.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/AMMDeposit.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/AMMDeposit.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/AMMVote.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/AMMVote.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/AMMWithdraw.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/AMMWithdraw.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/ApplyContext.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/ApplyContext.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/BookTip.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/BookTip.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/CancelCheck.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/CancelCheck.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/CancelOffer.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/CancelOffer.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/CashCheck.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/CashCheck.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/Change.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/Change.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/Clawback.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/Clawback.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/CreateCheck.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/CreateCheck.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/CreateOffer.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/CreateOffer.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/CreateTicket.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/CreateTicket.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/DID.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/DID.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/DeleteAccount.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/DeleteAccount.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/DeleteOracle.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/DeleteOracle.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/DepositPreauth.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/DepositPreauth.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/Escrow.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/Escrow.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/InvariantCheck.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/InvariantCheck.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/NFTokenAcceptOffer.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/NFTokenAcceptOffer.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/NFTokenBurn.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/NFTokenBurn.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/NFTokenCancelOffer.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/NFTokenCancelOffer.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/NFTokenCreateOffer.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/NFTokenCreateOffer.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/NFTokenMint.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/NFTokenMint.h (100%) rename src/{ripple/app/tx/impl/details => xrpld/app/tx/detail}/NFTokenUtils.cpp (100%) rename src/{ripple/app/tx/impl/details => xrpld/app/tx/detail}/NFTokenUtils.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/Offer.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/OfferStream.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/OfferStream.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/PayChan.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/PayChan.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/Payment.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/Payment.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/SetAccount.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/SetAccount.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/SetOracle.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/SetOracle.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/SetRegularKey.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/SetRegularKey.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/SetSignerList.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/SetSignerList.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/SetTrust.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/SetTrust.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/SignerEntries.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/SignerEntries.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/Taker.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/Taker.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/Transactor.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/Transactor.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/XChainBridge.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/XChainBridge.h (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/apply.cpp (100%) rename src/{ripple/app/tx/impl => xrpld/app/tx/detail}/applySteps.cpp (100%) rename src/{ripple => xrpld}/conditions/Condition.h (100%) rename src/{ripple => xrpld}/conditions/Fulfillment.h (100%) rename src/{ripple/conditions/impl => xrpld/conditions/detail}/Condition.cpp (100%) rename src/{ripple/conditions/impl => xrpld/conditions/detail}/Fulfillment.cpp (100%) rename src/{ripple/conditions/impl => xrpld/conditions/detail}/PreimageSha256.h (100%) rename src/{ripple/conditions/impl => xrpld/conditions/detail}/error.cpp (100%) rename src/{ripple/conditions/impl => xrpld/conditions/detail}/error.h (100%) rename src/{ripple/conditions/impl => xrpld/conditions/detail}/utils.h (100%) rename src/{ripple => xrpld}/consensus/Consensus.cpp (100%) rename src/{ripple => xrpld}/consensus/Consensus.h (100%) rename src/{ripple => xrpld}/consensus/ConsensusParms.h (100%) rename src/{ripple => xrpld}/consensus/ConsensusProposal.h (100%) rename src/{ripple => xrpld}/consensus/ConsensusTypes.h (100%) rename src/{ripple => xrpld}/consensus/DisputedTx.h (100%) rename src/{ripple => xrpld}/consensus/LedgerTiming.h (100%) rename src/{ripple => xrpld}/consensus/LedgerTrie.h (100%) rename src/{ripple => xrpld}/consensus/README.md (100%) rename src/{ripple => xrpld}/consensus/Validations.h (100%) rename src/{ripple => xrpld}/core/ClosureCounter.h (100%) rename src/{ripple => xrpld}/core/Config.h (100%) rename src/{ripple => xrpld}/core/ConfigSections.h (100%) rename src/{ripple => xrpld}/core/Coro.ipp (100%) rename src/{ripple => xrpld}/core/DatabaseCon.h (100%) rename src/{ripple => xrpld}/core/Job.h (100%) rename src/{ripple => xrpld}/core/JobQueue.h (100%) rename src/{ripple => xrpld}/core/JobTypeData.h (100%) rename src/{ripple => xrpld}/core/JobTypeInfo.h (100%) rename src/{ripple => xrpld}/core/JobTypes.h (100%) rename src/{ripple => xrpld}/core/LoadEvent.h (100%) rename src/{ripple => xrpld}/core/LoadMonitor.h (100%) rename src/{ripple => xrpld}/core/Pg.cpp (100%) rename src/{ripple => xrpld}/core/Pg.h (100%) rename src/{ripple => xrpld}/core/SociDB.h (100%) rename src/{ripple => xrpld}/core/TimeKeeper.h (100%) rename src/{ripple/core/impl => xrpld/core/detail}/Config.cpp (100%) rename src/{ripple/core/impl => xrpld/core/detail}/DatabaseCon.cpp (100%) rename src/{ripple/core/impl => xrpld/core/detail}/Job.cpp (100%) rename src/{ripple/core/impl => xrpld/core/detail}/JobQueue.cpp (100%) rename src/{ripple/core/impl => xrpld/core/detail}/LoadEvent.cpp (100%) rename src/{ripple/core/impl => xrpld/core/detail}/LoadMonitor.cpp (100%) rename src/{ripple/core/impl => xrpld/core/detail}/SociDB.cpp (100%) rename src/{ripple/core/impl => xrpld/core/detail}/Workers.cpp (100%) rename src/{ripple/core/impl => xrpld/core/detail}/Workers.h (100%) rename src/{ripple/core/impl => xrpld/core/detail}/semaphore.h (100%) rename src/{ripple => xrpld}/ledger/ApplyView.h (100%) rename src/{ripple => xrpld}/ledger/ApplyViewImpl.h (100%) rename src/{ripple => xrpld}/ledger/BookDirs.h (100%) rename src/{ripple => xrpld}/ledger/CachedSLEs.h (100%) rename src/{ripple => xrpld}/ledger/CachedView.h (100%) rename src/{ripple => xrpld}/ledger/Directory.h (100%) rename src/{ripple => xrpld}/ledger/OpenView.h (100%) rename src/{ripple => xrpld}/ledger/PaymentSandbox.h (100%) rename src/{ripple => xrpld}/ledger/RawView.h (100%) rename src/{ripple => xrpld}/ledger/ReadView.h (100%) rename src/{ripple => xrpld}/ledger/Sandbox.h (100%) rename src/{ripple => xrpld}/ledger/View.h (100%) rename src/{ripple/ledger/impl => xrpld/ledger/detail}/ApplyStateTable.cpp (100%) rename src/{ripple => xrpld}/ledger/detail/ApplyStateTable.h (100%) rename src/{ripple/ledger/impl => xrpld/ledger/detail}/ApplyView.cpp (100%) rename src/{ripple/ledger/impl => xrpld/ledger/detail}/ApplyViewBase.cpp (100%) rename src/{ripple => xrpld}/ledger/detail/ApplyViewBase.h (100%) rename src/{ripple/ledger/impl => xrpld/ledger/detail}/ApplyViewImpl.cpp (100%) rename src/{ripple/ledger/impl => xrpld/ledger/detail}/BookDirs.cpp (100%) rename src/{ripple/ledger/impl => xrpld/ledger/detail}/CachedView.cpp (100%) rename src/{ripple/ledger/impl => xrpld/ledger/detail}/Directory.cpp (100%) rename src/{ripple/ledger/impl => xrpld/ledger/detail}/OpenView.cpp (100%) rename src/{ripple/ledger/impl => xrpld/ledger/detail}/PaymentSandbox.cpp (100%) rename src/{ripple/ledger/impl => xrpld/ledger/detail}/RawStateTable.cpp (100%) rename src/{ripple => xrpld}/ledger/detail/RawStateTable.h (100%) rename src/{ripple/ledger/impl => xrpld/ledger/detail}/ReadView.cpp (100%) rename src/{ripple => xrpld}/ledger/detail/ReadViewFwdRange.h (100%) rename src/{ripple => xrpld}/ledger/detail/ReadViewFwdRange.ipp (100%) rename src/{ripple/ledger/impl => xrpld/ledger/detail}/View.cpp (100%) rename src/{ripple => xrpld}/net/AutoSocket.h (100%) rename src/{ripple => xrpld}/net/DatabaseBody.h (100%) rename src/{ripple => xrpld}/net/DatabaseDownloader.h (100%) rename src/{ripple => xrpld}/net/HTTPClient.h (100%) rename src/{ripple => xrpld}/net/HTTPClientSSLContext.h (100%) rename src/{ripple => xrpld}/net/HTTPDownloader.h (100%) rename src/{ripple => xrpld}/net/HTTPStream.h (100%) rename src/{ripple => xrpld}/net/InfoSub.h (100%) rename src/{ripple => xrpld}/net/RPCCall.h (100%) rename src/{ripple => xrpld}/net/RPCSub.h (100%) rename src/{ripple => xrpld}/net/RegisterSSLCerts.h (100%) rename src/{ripple => xrpld}/net/ShardDownloader.md (100%) rename src/{ripple/net/impl => xrpld/net/detail}/DatabaseBody.ipp (100%) rename src/{ripple/net/impl => xrpld/net/detail}/DatabaseDownloader.cpp (100%) rename src/{ripple/net/impl => xrpld/net/detail}/HTTPClient.cpp (100%) rename src/{ripple/net/impl => xrpld/net/detail}/HTTPDownloader.cpp (100%) rename src/{ripple/net/impl => xrpld/net/detail}/HTTPStream.cpp (100%) rename src/{ripple/net/impl => xrpld/net/detail}/InfoSub.cpp (100%) rename src/{ripple/net/impl => xrpld/net/detail}/RPCCall.cpp (100%) rename src/{ripple/net/impl => xrpld/net/detail}/RPCSub.cpp (100%) rename src/{ripple/net/impl => xrpld/net/detail}/RegisterSSLCerts.cpp (100%) rename src/{ripple => xrpld}/net/images/interrupt_sequence.png (100%) rename src/{ripple => xrpld}/net/images/states.png (100%) rename src/{ripple => xrpld}/net/uml/interrupt_sequence.pu (100%) rename src/{ripple => xrpld}/net/uml/states.pu (100%) rename src/{ripple => xrpld}/nodestore/Backend.h (100%) rename src/{ripple => xrpld}/nodestore/Database.h (100%) rename src/{ripple => xrpld}/nodestore/DatabaseRotating.h (100%) rename src/{ripple => xrpld}/nodestore/DatabaseShard.h (100%) rename src/{ripple => xrpld}/nodestore/DeterministicShard.md (100%) rename src/{ripple => xrpld}/nodestore/DummyScheduler.h (100%) rename src/{ripple => xrpld}/nodestore/Factory.h (100%) rename src/{ripple => xrpld}/nodestore/Manager.h (100%) rename src/{ripple => xrpld}/nodestore/NodeObject.h (100%) rename src/{ripple => xrpld}/nodestore/README.md (100%) rename src/{ripple => xrpld}/nodestore/Scheduler.h (100%) rename src/{ripple => xrpld}/nodestore/ShardInfo.h (100%) rename src/{ripple => xrpld}/nodestore/ShardPool.md (100%) rename src/{ripple => xrpld}/nodestore/ShardSizeTuning.md (100%) rename src/{ripple => xrpld}/nodestore/Task.h (100%) rename src/{ripple => xrpld}/nodestore/Types.h (100%) rename src/{ripple => xrpld}/nodestore/backend/CassandraFactory.cpp (100%) rename src/{ripple => xrpld}/nodestore/backend/MemoryFactory.cpp (100%) rename src/{ripple => xrpld}/nodestore/backend/NuDBFactory.cpp (100%) rename src/{ripple => xrpld}/nodestore/backend/NullFactory.cpp (100%) rename src/{ripple => xrpld}/nodestore/backend/RocksDBFactory.cpp (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/BatchWriter.cpp (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/BatchWriter.h (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/Database.cpp (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/DatabaseNodeImp.cpp (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/DatabaseNodeImp.h (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/DatabaseRotatingImp.cpp (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/DatabaseRotatingImp.h (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/DatabaseShardImp.cpp (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/DatabaseShardImp.h (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/DecodedBlob.cpp (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/DecodedBlob.h (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/DeterministicShard.cpp (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/DeterministicShard.h (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/DummyScheduler.cpp (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/EncodedBlob.h (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/ManagerImp.cpp (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/ManagerImp.h (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/NodeObject.cpp (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/Shard.cpp (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/Shard.h (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/ShardInfo.cpp (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/TaskQueue.cpp (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/TaskQueue.h (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/codec.h (100%) rename src/{ripple/nodestore/impl => xrpld/nodestore/detail}/varint.h (100%) rename src/{ripple => xrpld}/overlay/Cluster.h (100%) rename src/{ripple => xrpld}/overlay/ClusterNode.h (100%) rename src/{ripple => xrpld}/overlay/Compression.h (100%) rename src/{ripple => xrpld}/overlay/Message.h (100%) rename src/{ripple => xrpld}/overlay/Overlay.h (100%) rename src/{ripple => xrpld}/overlay/Peer.h (100%) rename src/{ripple => xrpld}/overlay/PeerReservationTable.h (100%) rename src/{ripple => xrpld}/overlay/PeerSet.h (100%) rename src/{ripple => xrpld}/overlay/README.md (100%) rename src/{ripple => xrpld}/overlay/ReduceRelayCommon.h (100%) rename src/{ripple => xrpld}/overlay/Slot.h (100%) rename src/{ripple => xrpld}/overlay/Squelch.h (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/Cluster.cpp (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/ConnectAttempt.cpp (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/ConnectAttempt.h (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/Handshake.cpp (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/Handshake.h (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/Message.cpp (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/OverlayImpl.cpp (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/OverlayImpl.h (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/PeerImp.cpp (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/PeerImp.h (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/PeerReservationTable.cpp (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/PeerSet.cpp (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/ProtocolMessage.h (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/ProtocolVersion.cpp (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/ProtocolVersion.h (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/TrafficCount.cpp (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/TrafficCount.h (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/Tuning.h (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/TxMetrics.cpp (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/TxMetrics.h (100%) rename src/{ripple/overlay/impl => xrpld/overlay/detail}/ZeroCopyStream.h (100%) rename src/{ripple => xrpld}/overlay/make_Overlay.h (100%) rename src/{ripple => xrpld}/overlay/predicates.h (100%) rename src/{ripple => xrpld}/peerfinder/PeerfinderManager.h (100%) rename src/{ripple => xrpld}/peerfinder/README.md (100%) rename src/{ripple => xrpld}/peerfinder/Slot.h (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/Bootcache.cpp (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/Bootcache.h (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/Checker.h (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/Counts.h (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/Endpoint.cpp (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/Fixed.h (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/Handouts.h (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/Livecache.h (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/Logic.h (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/PeerfinderConfig.cpp (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/PeerfinderManager.cpp (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/Reporting.h (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/SlotImp.cpp (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/SlotImp.h (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/Source.h (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/SourceStrings.cpp (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/SourceStrings.h (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/Store.h (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/StoreSqdb.h (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/Tuning.h (100%) rename src/{ripple/peerfinder/impl => xrpld/peerfinder/detail}/iosformat.h (100%) rename src/{ripple => xrpld}/peerfinder/make_Manager.h (100%) rename src/{ripple => xrpld}/peerfinder/sim/FunctionQueue.h (100%) rename src/{ripple => xrpld}/peerfinder/sim/GraphAlgorithms.h (100%) rename src/{ripple => xrpld}/peerfinder/sim/Message.h (100%) rename src/{ripple => xrpld}/peerfinder/sim/NodeSnapshot.h (100%) rename src/{ripple => xrpld}/peerfinder/sim/Params.h (100%) rename src/{ripple => xrpld}/peerfinder/sim/Predicates.h (100%) rename src/{ripple/basics => xrpld/perflog}/PerfLog.h (100%) rename src/{ripple/perflog/impl => xrpld/perflog/detail}/PerfLogImp.cpp (100%) rename src/{ripple/perflog/impl => xrpld/perflog/detail}/PerfLogImp.h (100%) rename src/{ripple => xrpld}/rpc/BookChanges.h (100%) rename src/{ripple => xrpld}/rpc/CTID.h (100%) rename src/{ripple => xrpld}/rpc/Context.h (100%) rename src/{ripple => xrpld}/rpc/DeliveredAmount.h (100%) rename src/{ripple => xrpld}/rpc/GRPCHandlers.h (100%) rename src/{ripple => xrpld}/rpc/Output.h (100%) rename src/{ripple => xrpld}/rpc/README.md (100%) rename src/{ripple => xrpld}/rpc/RPCHandler.h (100%) rename src/{ripple => xrpld}/rpc/Request.h (100%) rename src/{ripple => xrpld}/rpc/Role.h (100%) rename src/{ripple => xrpld}/rpc/ServerHandler.h (100%) rename src/{ripple => xrpld}/rpc/ShardArchiveHandler.h (100%) rename src/{ripple => xrpld}/rpc/ShardVerificationScheduler.h (100%) rename src/{ripple => xrpld}/rpc/Status.h (100%) rename src/{ripple/rpc/impl => xrpld/rpc/detail}/DeliveredAmount.cpp (100%) rename src/{ripple/rpc/impl => xrpld/rpc/detail}/Handler.cpp (100%) rename src/{ripple/rpc/impl => xrpld/rpc/detail}/Handler.h (100%) rename src/{ripple/rpc/impl => xrpld/rpc/detail}/LegacyPathFind.cpp (100%) rename src/{ripple/rpc/impl => xrpld/rpc/detail}/LegacyPathFind.h (100%) rename src/{ripple/rpc/impl => xrpld/rpc/detail}/RPCHandler.cpp (100%) rename src/{ripple/rpc/impl => xrpld/rpc/detail}/RPCHelpers.cpp (100%) rename src/{ripple/rpc/impl => xrpld/rpc/detail}/RPCHelpers.h (100%) rename src/{ripple/rpc/impl => xrpld/rpc/detail}/Role.cpp (100%) rename src/{ripple/rpc/impl => xrpld/rpc/detail}/ServerHandler.cpp (100%) rename src/{ripple/rpc/impl => xrpld/rpc/detail}/ShardArchiveHandler.cpp (100%) rename src/{ripple/rpc/impl => xrpld/rpc/detail}/ShardVerificationScheduler.cpp (100%) rename src/{ripple/rpc/impl => xrpld/rpc/detail}/Status.cpp (100%) rename src/{ripple/rpc/impl => xrpld/rpc/detail}/TransactionSign.cpp (100%) rename src/{ripple/rpc/impl => xrpld/rpc/detail}/TransactionSign.h (100%) rename src/{ripple/rpc/impl => xrpld/rpc/detail}/Tuning.h (100%) rename src/{ripple/rpc/impl => xrpld/rpc/detail}/WSInfoSub.h (100%) rename src/{ripple => xrpld}/rpc/handlers/AMMInfo.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/AccountChannels.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/AccountCurrenciesHandler.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/AccountInfo.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/AccountLines.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/AccountObjects.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/AccountOffers.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/AccountTx.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/BlackList.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/BookOffers.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/CanDelete.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/Connect.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/ConsensusInfo.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/CrawlShards.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/DepositAuthorized.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/DownloadShard.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/Feature1.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/Fee1.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/FetchInfo.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/GatewayBalances.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/GetAggregatePrice.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/GetCounts.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/GetCounts.h (100%) rename src/{ripple => xrpld}/rpc/handlers/Handlers.h (100%) rename src/{ripple => xrpld}/rpc/handlers/LedgerAccept.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/LedgerCleanerHandler.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/LedgerClosed.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/LedgerCurrent.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/LedgerData.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/LedgerDiff.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/LedgerEntry.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/LedgerHandler.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/LedgerHandler.h (100%) rename src/{ripple => xrpld}/rpc/handlers/LedgerHeader.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/LedgerRequest.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/LogLevel.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/LogRotate.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/Manifest.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/NFTOffers.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/NoRippleCheck.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/NodeToShard.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/OwnerInfo.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/PathFind.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/PayChanClaim.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/Peers.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/Ping.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/Print.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/Random.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/Reservations.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/RipplePathFind.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/ServerInfo.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/ServerState.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/SignFor.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/SignHandler.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/Stop.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/Submit.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/SubmitMultiSigned.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/Subscribe.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/TransactionEntry.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/Tx.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/TxHistory.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/TxReduceRelay.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/UnlList.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/Unsubscribe.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/ValidationCreate.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/ValidatorInfo.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/ValidatorListSites.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/Validators.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/Version.h (100%) rename src/{ripple => xrpld}/rpc/handlers/WalletPropose.cpp (100%) rename src/{ripple => xrpld}/rpc/handlers/WalletPropose.h (100%) rename src/{ripple => xrpld}/rpc/json_body.h (100%) rename src/{ripple => xrpld}/shamap/Family.h (100%) rename src/{ripple => xrpld}/shamap/FullBelowCache.h (100%) rename src/{ripple => xrpld}/shamap/NodeFamily.h (100%) rename src/{ripple => xrpld}/shamap/README.md (100%) rename src/{ripple => xrpld}/shamap/SHAMap.h (100%) rename src/{ripple => xrpld}/shamap/SHAMapAccountStateLeafNode.h (100%) rename src/{ripple => xrpld}/shamap/SHAMapAddNode.h (100%) rename src/{ripple => xrpld}/shamap/SHAMapInnerNode.h (100%) rename src/{ripple => xrpld}/shamap/SHAMapItem.h (100%) rename src/{ripple => xrpld}/shamap/SHAMapLeafNode.h (100%) rename src/{ripple => xrpld}/shamap/SHAMapMissingNode.h (100%) rename src/{ripple => xrpld}/shamap/SHAMapNodeID.h (100%) rename src/{ripple => xrpld}/shamap/SHAMapSyncFilter.h (100%) rename src/{ripple => xrpld}/shamap/SHAMapTreeNode.h (100%) rename src/{ripple => xrpld}/shamap/SHAMapTxLeafNode.h (100%) rename src/{ripple => xrpld}/shamap/SHAMapTxPlusMetaLeafNode.h (100%) rename src/{ripple => xrpld}/shamap/ShardFamily.h (100%) rename src/{ripple => xrpld}/shamap/TreeNodeCache.h (100%) rename src/{ripple/shamap/impl => xrpld/shamap/detail}/NodeFamily.cpp (100%) rename src/{ripple/shamap/impl => xrpld/shamap/detail}/SHAMap.cpp (100%) rename src/{ripple/shamap/impl => xrpld/shamap/detail}/SHAMapDelta.cpp (100%) rename src/{ripple/shamap/impl => xrpld/shamap/detail}/SHAMapInnerNode.cpp (100%) rename src/{ripple/shamap/impl => xrpld/shamap/detail}/SHAMapLeafNode.cpp (100%) rename src/{ripple/shamap/impl => xrpld/shamap/detail}/SHAMapNodeID.cpp (100%) rename src/{ripple/shamap/impl => xrpld/shamap/detail}/SHAMapSync.cpp (100%) rename src/{ripple/shamap/impl => xrpld/shamap/detail}/SHAMapTreeNode.cpp (100%) rename src/{ripple/shamap/impl => xrpld/shamap/detail}/ShardFamily.cpp (100%) rename src/{ripple/shamap/impl => xrpld/shamap/detail}/TaggedPointer.h (100%) rename src/{ripple/shamap/impl => xrpld/shamap/detail}/TaggedPointer.ipp (100%) rename src/{ripple => xrpld}/unity/rocksdb.h (100%) diff --git a/src/ripple/basics/Archive.h b/include/xrpl/basics/Archive.h similarity index 100% rename from src/ripple/basics/Archive.h rename to include/xrpl/basics/Archive.h diff --git a/src/ripple/basics/BasicConfig.h b/include/xrpl/basics/BasicConfig.h similarity index 100% rename from src/ripple/basics/BasicConfig.h rename to include/xrpl/basics/BasicConfig.h diff --git a/src/ripple/basics/Blob.h b/include/xrpl/basics/Blob.h similarity index 100% rename from src/ripple/basics/Blob.h rename to include/xrpl/basics/Blob.h diff --git a/src/ripple/basics/Buffer.h b/include/xrpl/basics/Buffer.h similarity index 100% rename from src/ripple/basics/Buffer.h rename to include/xrpl/basics/Buffer.h diff --git a/src/ripple/basics/ByteUtilities.h b/include/xrpl/basics/ByteUtilities.h similarity index 100% rename from src/ripple/basics/ByteUtilities.h rename to include/xrpl/basics/ByteUtilities.h diff --git a/src/ripple/basics/CompressionAlgorithms.h b/include/xrpl/basics/CompressionAlgorithms.h similarity index 100% rename from src/ripple/basics/CompressionAlgorithms.h rename to include/xrpl/basics/CompressionAlgorithms.h diff --git a/src/ripple/basics/CountedObject.h b/include/xrpl/basics/CountedObject.h similarity index 100% rename from src/ripple/basics/CountedObject.h rename to include/xrpl/basics/CountedObject.h diff --git a/src/ripple/basics/DecayingSample.h b/include/xrpl/basics/DecayingSample.h similarity index 100% rename from src/ripple/basics/DecayingSample.h rename to include/xrpl/basics/DecayingSample.h diff --git a/src/ripple/basics/Expected.h b/include/xrpl/basics/Expected.h similarity index 100% rename from src/ripple/basics/Expected.h rename to include/xrpl/basics/Expected.h diff --git a/src/ripple/basics/FeeUnits.h b/include/xrpl/basics/FeeUnits.h similarity index 100% rename from src/ripple/basics/FeeUnits.h rename to include/xrpl/basics/FeeUnits.h diff --git a/src/ripple/basics/FileUtilities.h b/include/xrpl/basics/FileUtilities.h similarity index 100% rename from src/ripple/basics/FileUtilities.h rename to include/xrpl/basics/FileUtilities.h diff --git a/src/ripple/basics/IOUAmount.h b/include/xrpl/basics/IOUAmount.h similarity index 100% rename from src/ripple/basics/IOUAmount.h rename to include/xrpl/basics/IOUAmount.h diff --git a/src/ripple/basics/KeyCache.h b/include/xrpl/basics/KeyCache.h similarity index 100% rename from src/ripple/basics/KeyCache.h rename to include/xrpl/basics/KeyCache.h diff --git a/src/ripple/basics/LocalValue.h b/include/xrpl/basics/LocalValue.h similarity index 100% rename from src/ripple/basics/LocalValue.h rename to include/xrpl/basics/LocalValue.h diff --git a/src/ripple/basics/Log.h b/include/xrpl/basics/Log.h similarity index 100% rename from src/ripple/basics/Log.h rename to include/xrpl/basics/Log.h diff --git a/src/ripple/basics/MathUtilities.h b/include/xrpl/basics/MathUtilities.h similarity index 100% rename from src/ripple/basics/MathUtilities.h rename to include/xrpl/basics/MathUtilities.h diff --git a/src/ripple/basics/Number.h b/include/xrpl/basics/Number.h similarity index 100% rename from src/ripple/basics/Number.h rename to include/xrpl/basics/Number.h diff --git a/src/ripple/basics/README.md b/include/xrpl/basics/README.md similarity index 100% rename from src/ripple/basics/README.md rename to include/xrpl/basics/README.md diff --git a/src/ripple/basics/RangeSet.h b/include/xrpl/basics/RangeSet.h similarity index 100% rename from src/ripple/basics/RangeSet.h rename to include/xrpl/basics/RangeSet.h diff --git a/src/ripple/basics/Resolver.h b/include/xrpl/basics/Resolver.h similarity index 100% rename from src/ripple/basics/Resolver.h rename to include/xrpl/basics/Resolver.h diff --git a/src/ripple/basics/ResolverAsio.h b/include/xrpl/basics/ResolverAsio.h similarity index 100% rename from src/ripple/basics/ResolverAsio.h rename to include/xrpl/basics/ResolverAsio.h diff --git a/src/ripple/basics/SHAMapHash.h b/include/xrpl/basics/SHAMapHash.h similarity index 100% rename from src/ripple/basics/SHAMapHash.h rename to include/xrpl/basics/SHAMapHash.h diff --git a/src/ripple/basics/SlabAllocator.h b/include/xrpl/basics/SlabAllocator.h similarity index 100% rename from src/ripple/basics/SlabAllocator.h rename to include/xrpl/basics/SlabAllocator.h diff --git a/src/ripple/basics/Slice.h b/include/xrpl/basics/Slice.h similarity index 100% rename from src/ripple/basics/Slice.h rename to include/xrpl/basics/Slice.h diff --git a/src/ripple/basics/StringUtilities.h b/include/xrpl/basics/StringUtilities.h similarity index 100% rename from src/ripple/basics/StringUtilities.h rename to include/xrpl/basics/StringUtilities.h diff --git a/src/ripple/basics/TaggedCache.h b/include/xrpl/basics/TaggedCache.h similarity index 100% rename from src/ripple/basics/TaggedCache.h rename to include/xrpl/basics/TaggedCache.h diff --git a/src/ripple/basics/ThreadSafetyAnalysis.h b/include/xrpl/basics/ThreadSafetyAnalysis.h similarity index 100% rename from src/ripple/basics/ThreadSafetyAnalysis.h rename to include/xrpl/basics/ThreadSafetyAnalysis.h diff --git a/src/ripple/basics/ToString.h b/include/xrpl/basics/ToString.h similarity index 100% rename from src/ripple/basics/ToString.h rename to include/xrpl/basics/ToString.h diff --git a/src/ripple/basics/UnorderedContainers.h b/include/xrpl/basics/UnorderedContainers.h similarity index 100% rename from src/ripple/basics/UnorderedContainers.h rename to include/xrpl/basics/UnorderedContainers.h diff --git a/src/ripple/basics/UptimeClock.h b/include/xrpl/basics/UptimeClock.h similarity index 100% rename from src/ripple/basics/UptimeClock.h rename to include/xrpl/basics/UptimeClock.h diff --git a/src/ripple/basics/XRPAmount.h b/include/xrpl/basics/XRPAmount.h similarity index 100% rename from src/ripple/basics/XRPAmount.h rename to include/xrpl/basics/XRPAmount.h diff --git a/src/ripple/basics/algorithm.h b/include/xrpl/basics/algorithm.h similarity index 100% rename from src/ripple/basics/algorithm.h rename to include/xrpl/basics/algorithm.h diff --git a/src/ripple/basics/base64.h b/include/xrpl/basics/base64.h similarity index 100% rename from src/ripple/basics/base64.h rename to include/xrpl/basics/base64.h diff --git a/src/ripple/basics/base_uint.h b/include/xrpl/basics/base_uint.h similarity index 100% rename from src/ripple/basics/base_uint.h rename to include/xrpl/basics/base_uint.h diff --git a/src/ripple/basics/chrono.h b/include/xrpl/basics/chrono.h similarity index 100% rename from src/ripple/basics/chrono.h rename to include/xrpl/basics/chrono.h diff --git a/src/ripple/basics/comparators.h b/include/xrpl/basics/comparators.h similarity index 100% rename from src/ripple/basics/comparators.h rename to include/xrpl/basics/comparators.h diff --git a/src/ripple/basics/contract.h b/include/xrpl/basics/contract.h similarity index 100% rename from src/ripple/basics/contract.h rename to include/xrpl/basics/contract.h diff --git a/src/ripple/basics/hardened_hash.h b/include/xrpl/basics/hardened_hash.h similarity index 100% rename from src/ripple/basics/hardened_hash.h rename to include/xrpl/basics/hardened_hash.h diff --git a/src/ripple/basics/join.h b/include/xrpl/basics/join.h similarity index 100% rename from src/ripple/basics/join.h rename to include/xrpl/basics/join.h diff --git a/src/ripple/basics/make_SSLContext.h b/include/xrpl/basics/make_SSLContext.h similarity index 100% rename from src/ripple/basics/make_SSLContext.h rename to include/xrpl/basics/make_SSLContext.h diff --git a/src/ripple/basics/mulDiv.h b/include/xrpl/basics/mulDiv.h similarity index 100% rename from src/ripple/basics/mulDiv.h rename to include/xrpl/basics/mulDiv.h diff --git a/src/ripple/basics/partitioned_unordered_map.h b/include/xrpl/basics/partitioned_unordered_map.h similarity index 100% rename from src/ripple/basics/partitioned_unordered_map.h rename to include/xrpl/basics/partitioned_unordered_map.h diff --git a/src/ripple/basics/random.h b/include/xrpl/basics/random.h similarity index 100% rename from src/ripple/basics/random.h rename to include/xrpl/basics/random.h diff --git a/src/ripple/basics/safe_cast.h b/include/xrpl/basics/safe_cast.h similarity index 100% rename from src/ripple/basics/safe_cast.h rename to include/xrpl/basics/safe_cast.h diff --git a/src/ripple/basics/scope.h b/include/xrpl/basics/scope.h similarity index 100% rename from src/ripple/basics/scope.h rename to include/xrpl/basics/scope.h diff --git a/src/ripple/basics/spinlock.h b/include/xrpl/basics/spinlock.h similarity index 100% rename from src/ripple/basics/spinlock.h rename to include/xrpl/basics/spinlock.h diff --git a/src/ripple/basics/strHex.h b/include/xrpl/basics/strHex.h similarity index 100% rename from src/ripple/basics/strHex.h rename to include/xrpl/basics/strHex.h diff --git a/src/ripple/basics/tagged_integer.h b/include/xrpl/basics/tagged_integer.h similarity index 100% rename from src/ripple/basics/tagged_integer.h rename to include/xrpl/basics/tagged_integer.h diff --git a/src/ripple/beast/asio/io_latency_probe.h b/include/xrpl/beast/asio/io_latency_probe.h similarity index 100% rename from src/ripple/beast/asio/io_latency_probe.h rename to include/xrpl/beast/asio/io_latency_probe.h diff --git a/src/ripple/beast/clock/abstract_clock.h b/include/xrpl/beast/clock/abstract_clock.h similarity index 100% rename from src/ripple/beast/clock/abstract_clock.h rename to include/xrpl/beast/clock/abstract_clock.h diff --git a/src/ripple/beast/clock/basic_seconds_clock.h b/include/xrpl/beast/clock/basic_seconds_clock.h similarity index 100% rename from src/ripple/beast/clock/basic_seconds_clock.h rename to include/xrpl/beast/clock/basic_seconds_clock.h diff --git a/src/ripple/beast/clock/manual_clock.h b/include/xrpl/beast/clock/manual_clock.h similarity index 100% rename from src/ripple/beast/clock/manual_clock.h rename to include/xrpl/beast/clock/manual_clock.h diff --git a/src/ripple/beast/container/aged_container.h b/include/xrpl/beast/container/aged_container.h similarity index 100% rename from src/ripple/beast/container/aged_container.h rename to include/xrpl/beast/container/aged_container.h diff --git a/src/ripple/beast/container/aged_container_utility.h b/include/xrpl/beast/container/aged_container_utility.h similarity index 100% rename from src/ripple/beast/container/aged_container_utility.h rename to include/xrpl/beast/container/aged_container_utility.h diff --git a/src/ripple/beast/container/aged_map.h b/include/xrpl/beast/container/aged_map.h similarity index 100% rename from src/ripple/beast/container/aged_map.h rename to include/xrpl/beast/container/aged_map.h diff --git a/src/ripple/beast/container/aged_multimap.h b/include/xrpl/beast/container/aged_multimap.h similarity index 100% rename from src/ripple/beast/container/aged_multimap.h rename to include/xrpl/beast/container/aged_multimap.h diff --git a/src/ripple/beast/container/aged_multiset.h b/include/xrpl/beast/container/aged_multiset.h similarity index 100% rename from src/ripple/beast/container/aged_multiset.h rename to include/xrpl/beast/container/aged_multiset.h diff --git a/src/ripple/beast/container/aged_set.h b/include/xrpl/beast/container/aged_set.h similarity index 100% rename from src/ripple/beast/container/aged_set.h rename to include/xrpl/beast/container/aged_set.h diff --git a/src/ripple/beast/container/aged_unordered_map.h b/include/xrpl/beast/container/aged_unordered_map.h similarity index 100% rename from src/ripple/beast/container/aged_unordered_map.h rename to include/xrpl/beast/container/aged_unordered_map.h diff --git a/src/ripple/beast/container/aged_unordered_multimap.h b/include/xrpl/beast/container/aged_unordered_multimap.h similarity index 100% rename from src/ripple/beast/container/aged_unordered_multimap.h rename to include/xrpl/beast/container/aged_unordered_multimap.h diff --git a/src/ripple/beast/container/aged_unordered_multiset.h b/include/xrpl/beast/container/aged_unordered_multiset.h similarity index 100% rename from src/ripple/beast/container/aged_unordered_multiset.h rename to include/xrpl/beast/container/aged_unordered_multiset.h diff --git a/src/ripple/beast/container/aged_unordered_set.h b/include/xrpl/beast/container/aged_unordered_set.h similarity index 100% rename from src/ripple/beast/container/aged_unordered_set.h rename to include/xrpl/beast/container/aged_unordered_set.h diff --git a/src/ripple/beast/container/detail/aged_associative_container.h b/include/xrpl/beast/container/detail/aged_associative_container.h similarity index 100% rename from src/ripple/beast/container/detail/aged_associative_container.h rename to include/xrpl/beast/container/detail/aged_associative_container.h diff --git a/src/ripple/beast/container/detail/aged_container_iterator.h b/include/xrpl/beast/container/detail/aged_container_iterator.h similarity index 100% rename from src/ripple/beast/container/detail/aged_container_iterator.h rename to include/xrpl/beast/container/detail/aged_container_iterator.h diff --git a/src/ripple/beast/container/detail/aged_ordered_container.h b/include/xrpl/beast/container/detail/aged_ordered_container.h similarity index 100% rename from src/ripple/beast/container/detail/aged_ordered_container.h rename to include/xrpl/beast/container/detail/aged_ordered_container.h diff --git a/src/ripple/beast/container/detail/aged_unordered_container.h b/include/xrpl/beast/container/detail/aged_unordered_container.h similarity index 100% rename from src/ripple/beast/container/detail/aged_unordered_container.h rename to include/xrpl/beast/container/detail/aged_unordered_container.h diff --git a/src/ripple/beast/container/detail/empty_base_optimization.h b/include/xrpl/beast/container/detail/empty_base_optimization.h similarity index 100% rename from src/ripple/beast/container/detail/empty_base_optimization.h rename to include/xrpl/beast/container/detail/empty_base_optimization.h diff --git a/src/ripple/beast/core/CurrentThreadName.h b/include/xrpl/beast/core/CurrentThreadName.h similarity index 100% rename from src/ripple/beast/core/CurrentThreadName.h rename to include/xrpl/beast/core/CurrentThreadName.h diff --git a/src/ripple/beast/core/LexicalCast.h b/include/xrpl/beast/core/LexicalCast.h similarity index 100% rename from src/ripple/beast/core/LexicalCast.h rename to include/xrpl/beast/core/LexicalCast.h diff --git a/src/ripple/beast/core/List.h b/include/xrpl/beast/core/List.h similarity index 100% rename from src/ripple/beast/core/List.h rename to include/xrpl/beast/core/List.h diff --git a/src/ripple/beast/core/LockFreeStack.h b/include/xrpl/beast/core/LockFreeStack.h similarity index 100% rename from src/ripple/beast/core/LockFreeStack.h rename to include/xrpl/beast/core/LockFreeStack.h diff --git a/src/ripple/beast/core/SemanticVersion.h b/include/xrpl/beast/core/SemanticVersion.h similarity index 100% rename from src/ripple/beast/core/SemanticVersion.h rename to include/xrpl/beast/core/SemanticVersion.h diff --git a/src/ripple/beast/hash/hash_append.h b/include/xrpl/beast/hash/hash_append.h similarity index 100% rename from src/ripple/beast/hash/hash_append.h rename to include/xrpl/beast/hash/hash_append.h diff --git a/src/ripple/beast/hash/uhash.h b/include/xrpl/beast/hash/uhash.h similarity index 100% rename from src/ripple/beast/hash/uhash.h rename to include/xrpl/beast/hash/uhash.h diff --git a/src/ripple/beast/hash/xxhasher.h b/include/xrpl/beast/hash/xxhasher.h similarity index 100% rename from src/ripple/beast/hash/xxhasher.h rename to include/xrpl/beast/hash/xxhasher.h diff --git a/src/ripple/beast/insight/Collector.h b/include/xrpl/beast/insight/Collector.h similarity index 100% rename from src/ripple/beast/insight/Collector.h rename to include/xrpl/beast/insight/Collector.h diff --git a/src/ripple/beast/insight/Counter.h b/include/xrpl/beast/insight/Counter.h similarity index 100% rename from src/ripple/beast/insight/Counter.h rename to include/xrpl/beast/insight/Counter.h diff --git a/src/ripple/beast/insight/CounterImpl.h b/include/xrpl/beast/insight/CounterImpl.h similarity index 100% rename from src/ripple/beast/insight/CounterImpl.h rename to include/xrpl/beast/insight/CounterImpl.h diff --git a/src/ripple/beast/insight/Event.h b/include/xrpl/beast/insight/Event.h similarity index 100% rename from src/ripple/beast/insight/Event.h rename to include/xrpl/beast/insight/Event.h diff --git a/src/ripple/beast/insight/EventImpl.h b/include/xrpl/beast/insight/EventImpl.h similarity index 100% rename from src/ripple/beast/insight/EventImpl.h rename to include/xrpl/beast/insight/EventImpl.h diff --git a/src/ripple/beast/insight/Gauge.h b/include/xrpl/beast/insight/Gauge.h similarity index 100% rename from src/ripple/beast/insight/Gauge.h rename to include/xrpl/beast/insight/Gauge.h diff --git a/src/ripple/beast/insight/GaugeImpl.h b/include/xrpl/beast/insight/GaugeImpl.h similarity index 100% rename from src/ripple/beast/insight/GaugeImpl.h rename to include/xrpl/beast/insight/GaugeImpl.h diff --git a/src/ripple/beast/insight/Group.h b/include/xrpl/beast/insight/Group.h similarity index 100% rename from src/ripple/beast/insight/Group.h rename to include/xrpl/beast/insight/Group.h diff --git a/src/ripple/beast/insight/Groups.h b/include/xrpl/beast/insight/Groups.h similarity index 100% rename from src/ripple/beast/insight/Groups.h rename to include/xrpl/beast/insight/Groups.h diff --git a/src/ripple/beast/insight/Hook.h b/include/xrpl/beast/insight/Hook.h similarity index 100% rename from src/ripple/beast/insight/Hook.h rename to include/xrpl/beast/insight/Hook.h diff --git a/src/ripple/beast/insight/HookImpl.h b/include/xrpl/beast/insight/HookImpl.h similarity index 100% rename from src/ripple/beast/insight/HookImpl.h rename to include/xrpl/beast/insight/HookImpl.h diff --git a/src/ripple/beast/insight/Insight.h b/include/xrpl/beast/insight/Insight.h similarity index 100% rename from src/ripple/beast/insight/Insight.h rename to include/xrpl/beast/insight/Insight.h diff --git a/src/ripple/beast/insight/Meter.h b/include/xrpl/beast/insight/Meter.h similarity index 100% rename from src/ripple/beast/insight/Meter.h rename to include/xrpl/beast/insight/Meter.h diff --git a/src/ripple/beast/insight/MeterImpl.h b/include/xrpl/beast/insight/MeterImpl.h similarity index 100% rename from src/ripple/beast/insight/MeterImpl.h rename to include/xrpl/beast/insight/MeterImpl.h diff --git a/src/ripple/beast/insight/NullCollector.h b/include/xrpl/beast/insight/NullCollector.h similarity index 100% rename from src/ripple/beast/insight/NullCollector.h rename to include/xrpl/beast/insight/NullCollector.h diff --git a/src/ripple/beast/insight/StatsDCollector.h b/include/xrpl/beast/insight/StatsDCollector.h similarity index 100% rename from src/ripple/beast/insight/StatsDCollector.h rename to include/xrpl/beast/insight/StatsDCollector.h diff --git a/src/ripple/beast/net/IPAddress.h b/include/xrpl/beast/net/IPAddress.h similarity index 100% rename from src/ripple/beast/net/IPAddress.h rename to include/xrpl/beast/net/IPAddress.h diff --git a/src/ripple/beast/net/IPAddressConversion.h b/include/xrpl/beast/net/IPAddressConversion.h similarity index 100% rename from src/ripple/beast/net/IPAddressConversion.h rename to include/xrpl/beast/net/IPAddressConversion.h diff --git a/src/ripple/beast/net/IPAddressV4.h b/include/xrpl/beast/net/IPAddressV4.h similarity index 100% rename from src/ripple/beast/net/IPAddressV4.h rename to include/xrpl/beast/net/IPAddressV4.h diff --git a/src/ripple/beast/net/IPAddressV6.h b/include/xrpl/beast/net/IPAddressV6.h similarity index 100% rename from src/ripple/beast/net/IPAddressV6.h rename to include/xrpl/beast/net/IPAddressV6.h diff --git a/src/ripple/beast/net/IPEndpoint.h b/include/xrpl/beast/net/IPEndpoint.h similarity index 100% rename from src/ripple/beast/net/IPEndpoint.h rename to include/xrpl/beast/net/IPEndpoint.h diff --git a/src/ripple/beast/rfc2616.h b/include/xrpl/beast/rfc2616.h similarity index 100% rename from src/ripple/beast/rfc2616.h rename to include/xrpl/beast/rfc2616.h diff --git a/src/ripple/beast/test/fail_counter.h b/include/xrpl/beast/test/fail_counter.h similarity index 100% rename from src/ripple/beast/test/fail_counter.h rename to include/xrpl/beast/test/fail_counter.h diff --git a/src/ripple/beast/test/fail_stream.h b/include/xrpl/beast/test/fail_stream.h similarity index 100% rename from src/ripple/beast/test/fail_stream.h rename to include/xrpl/beast/test/fail_stream.h diff --git a/src/ripple/beast/test/pipe_stream.h b/include/xrpl/beast/test/pipe_stream.h similarity index 100% rename from src/ripple/beast/test/pipe_stream.h rename to include/xrpl/beast/test/pipe_stream.h diff --git a/src/ripple/beast/test/sig_wait.h b/include/xrpl/beast/test/sig_wait.h similarity index 100% rename from src/ripple/beast/test/sig_wait.h rename to include/xrpl/beast/test/sig_wait.h diff --git a/src/ripple/beast/test/string_iostream.h b/include/xrpl/beast/test/string_iostream.h similarity index 100% rename from src/ripple/beast/test/string_iostream.h rename to include/xrpl/beast/test/string_iostream.h diff --git a/src/ripple/beast/test/string_istream.h b/include/xrpl/beast/test/string_istream.h similarity index 100% rename from src/ripple/beast/test/string_istream.h rename to include/xrpl/beast/test/string_istream.h diff --git a/src/ripple/beast/test/string_ostream.h b/include/xrpl/beast/test/string_ostream.h similarity index 100% rename from src/ripple/beast/test/string_ostream.h rename to include/xrpl/beast/test/string_ostream.h diff --git a/src/ripple/beast/test/test_allocator.h b/include/xrpl/beast/test/test_allocator.h similarity index 100% rename from src/ripple/beast/test/test_allocator.h rename to include/xrpl/beast/test/test_allocator.h diff --git a/src/ripple/beast/test/yield_to.h b/include/xrpl/beast/test/yield_to.h similarity index 100% rename from src/ripple/beast/test/yield_to.h rename to include/xrpl/beast/test/yield_to.h diff --git a/src/ripple/beast/type_name.h b/include/xrpl/beast/type_name.h similarity index 100% rename from src/ripple/beast/type_name.h rename to include/xrpl/beast/type_name.h diff --git a/src/ripple/beast/unit_test.h b/include/xrpl/beast/unit_test.h similarity index 100% rename from src/ripple/beast/unit_test.h rename to include/xrpl/beast/unit_test.h diff --git a/src/ripple/beast/unit_test/amount.h b/include/xrpl/beast/unit_test/amount.h similarity index 100% rename from src/ripple/beast/unit_test/amount.h rename to include/xrpl/beast/unit_test/amount.h diff --git a/src/ripple/beast/unit_test/detail/const_container.h b/include/xrpl/beast/unit_test/detail/const_container.h similarity index 100% rename from src/ripple/beast/unit_test/detail/const_container.h rename to include/xrpl/beast/unit_test/detail/const_container.h diff --git a/src/ripple/beast/unit_test/dstream.h b/include/xrpl/beast/unit_test/dstream.h similarity index 100% rename from src/ripple/beast/unit_test/dstream.h rename to include/xrpl/beast/unit_test/dstream.h diff --git a/src/ripple/beast/unit_test/global_suites.h b/include/xrpl/beast/unit_test/global_suites.h similarity index 100% rename from src/ripple/beast/unit_test/global_suites.h rename to include/xrpl/beast/unit_test/global_suites.h diff --git a/src/ripple/beast/unit_test/match.h b/include/xrpl/beast/unit_test/match.h similarity index 100% rename from src/ripple/beast/unit_test/match.h rename to include/xrpl/beast/unit_test/match.h diff --git a/src/ripple/beast/unit_test/recorder.h b/include/xrpl/beast/unit_test/recorder.h similarity index 100% rename from src/ripple/beast/unit_test/recorder.h rename to include/xrpl/beast/unit_test/recorder.h diff --git a/src/ripple/beast/unit_test/reporter.h b/include/xrpl/beast/unit_test/reporter.h similarity index 100% rename from src/ripple/beast/unit_test/reporter.h rename to include/xrpl/beast/unit_test/reporter.h diff --git a/src/ripple/beast/unit_test/results.h b/include/xrpl/beast/unit_test/results.h similarity index 100% rename from src/ripple/beast/unit_test/results.h rename to include/xrpl/beast/unit_test/results.h diff --git a/src/ripple/beast/unit_test/runner.h b/include/xrpl/beast/unit_test/runner.h similarity index 100% rename from src/ripple/beast/unit_test/runner.h rename to include/xrpl/beast/unit_test/runner.h diff --git a/src/ripple/beast/unit_test/suite.h b/include/xrpl/beast/unit_test/suite.h similarity index 100% rename from src/ripple/beast/unit_test/suite.h rename to include/xrpl/beast/unit_test/suite.h diff --git a/src/ripple/beast/unit_test/suite_info.h b/include/xrpl/beast/unit_test/suite_info.h similarity index 100% rename from src/ripple/beast/unit_test/suite_info.h rename to include/xrpl/beast/unit_test/suite_info.h diff --git a/src/ripple/beast/unit_test/suite_list.h b/include/xrpl/beast/unit_test/suite_list.h similarity index 100% rename from src/ripple/beast/unit_test/suite_list.h rename to include/xrpl/beast/unit_test/suite_list.h diff --git a/src/ripple/beast/unit_test/thread.h b/include/xrpl/beast/unit_test/thread.h similarity index 100% rename from src/ripple/beast/unit_test/thread.h rename to include/xrpl/beast/unit_test/thread.h diff --git a/src/ripple/beast/utility/Journal.h b/include/xrpl/beast/utility/Journal.h similarity index 100% rename from src/ripple/beast/utility/Journal.h rename to include/xrpl/beast/utility/Journal.h diff --git a/src/ripple/beast/utility/PropertyStream.h b/include/xrpl/beast/utility/PropertyStream.h similarity index 100% rename from src/ripple/beast/utility/PropertyStream.h rename to include/xrpl/beast/utility/PropertyStream.h diff --git a/src/ripple/beast/utility/WrappedSink.h b/include/xrpl/beast/utility/WrappedSink.h similarity index 100% rename from src/ripple/beast/utility/WrappedSink.h rename to include/xrpl/beast/utility/WrappedSink.h diff --git a/src/ripple/beast/utility/Zero.h b/include/xrpl/beast/utility/Zero.h similarity index 100% rename from src/ripple/beast/utility/Zero.h rename to include/xrpl/beast/utility/Zero.h diff --git a/src/ripple/beast/utility/hash_pair.h b/include/xrpl/beast/utility/hash_pair.h similarity index 100% rename from src/ripple/beast/utility/hash_pair.h rename to include/xrpl/beast/utility/hash_pair.h diff --git a/src/ripple/beast/utility/maybe_const.h b/include/xrpl/beast/utility/maybe_const.h similarity index 100% rename from src/ripple/beast/utility/maybe_const.h rename to include/xrpl/beast/utility/maybe_const.h diff --git a/src/ripple/beast/utility/rngfill.h b/include/xrpl/beast/utility/rngfill.h similarity index 100% rename from src/ripple/beast/utility/rngfill.h rename to include/xrpl/beast/utility/rngfill.h diff --git a/src/ripple/beast/utility/temp_dir.h b/include/xrpl/beast/utility/temp_dir.h similarity index 100% rename from src/ripple/beast/utility/temp_dir.h rename to include/xrpl/beast/utility/temp_dir.h diff --git a/src/ripple/beast/xor_shift_engine.h b/include/xrpl/beast/xor_shift_engine.h similarity index 100% rename from src/ripple/beast/xor_shift_engine.h rename to include/xrpl/beast/xor_shift_engine.h diff --git a/src/ripple/crypto/README.md b/include/xrpl/crypto/README.md similarity index 100% rename from src/ripple/crypto/README.md rename to include/xrpl/crypto/README.md diff --git a/src/ripple/crypto/RFC1751.h b/include/xrpl/crypto/RFC1751.h similarity index 100% rename from src/ripple/crypto/RFC1751.h rename to include/xrpl/crypto/RFC1751.h diff --git a/src/ripple/crypto/csprng.h b/include/xrpl/crypto/csprng.h similarity index 100% rename from src/ripple/crypto/csprng.h rename to include/xrpl/crypto/csprng.h diff --git a/src/ripple/crypto/secure_erase.h b/include/xrpl/crypto/secure_erase.h similarity index 100% rename from src/ripple/crypto/secure_erase.h rename to include/xrpl/crypto/secure_erase.h diff --git a/src/ripple/json/JsonPropertyStream.h b/include/xrpl/json/JsonPropertyStream.h similarity index 100% rename from src/ripple/json/JsonPropertyStream.h rename to include/xrpl/json/JsonPropertyStream.h diff --git a/src/ripple/json/Object.h b/include/xrpl/json/Object.h similarity index 100% rename from src/ripple/json/Object.h rename to include/xrpl/json/Object.h diff --git a/src/ripple/json/Output.h b/include/xrpl/json/Output.h similarity index 100% rename from src/ripple/json/Output.h rename to include/xrpl/json/Output.h diff --git a/src/ripple/json/README.md b/include/xrpl/json/README.md similarity index 100% rename from src/ripple/json/README.md rename to include/xrpl/json/README.md diff --git a/src/ripple/json/Writer.h b/include/xrpl/json/Writer.h similarity index 100% rename from src/ripple/json/Writer.h rename to include/xrpl/json/Writer.h diff --git a/src/ripple/json/impl/json_assert.h b/include/xrpl/json/detail/json_assert.h similarity index 100% rename from src/ripple/json/impl/json_assert.h rename to include/xrpl/json/detail/json_assert.h diff --git a/src/ripple/json/json_errors.h b/include/xrpl/json/json_errors.h similarity index 100% rename from src/ripple/json/json_errors.h rename to include/xrpl/json/json_errors.h diff --git a/src/ripple/json/json_forwards.h b/include/xrpl/json/json_forwards.h similarity index 100% rename from src/ripple/json/json_forwards.h rename to include/xrpl/json/json_forwards.h diff --git a/src/ripple/json/json_reader.h b/include/xrpl/json/json_reader.h similarity index 100% rename from src/ripple/json/json_reader.h rename to include/xrpl/json/json_reader.h diff --git a/src/ripple/json/json_value.h b/include/xrpl/json/json_value.h similarity index 100% rename from src/ripple/json/json_value.h rename to include/xrpl/json/json_value.h diff --git a/src/ripple/json/json_writer.h b/include/xrpl/json/json_writer.h similarity index 100% rename from src/ripple/json/json_writer.h rename to include/xrpl/json/json_writer.h diff --git a/src/ripple/json/to_string.h b/include/xrpl/json/to_string.h similarity index 100% rename from src/ripple/json/to_string.h rename to include/xrpl/json/to_string.h diff --git a/src/ripple/proto/README.md b/include/xrpl/proto/README.md similarity index 100% rename from src/ripple/proto/README.md rename to include/xrpl/proto/README.md diff --git a/src/ripple/proto/org/xrpl/rpc/v1/README.md b/include/xrpl/proto/org/xrpl/rpc/v1/README.md similarity index 100% rename from src/ripple/proto/org/xrpl/rpc/v1/README.md rename to include/xrpl/proto/org/xrpl/rpc/v1/README.md diff --git a/src/ripple/proto/org/xrpl/rpc/v1/get_ledger.proto b/include/xrpl/proto/org/xrpl/rpc/v1/get_ledger.proto similarity index 100% rename from src/ripple/proto/org/xrpl/rpc/v1/get_ledger.proto rename to include/xrpl/proto/org/xrpl/rpc/v1/get_ledger.proto diff --git a/src/ripple/proto/org/xrpl/rpc/v1/get_ledger_data.proto b/include/xrpl/proto/org/xrpl/rpc/v1/get_ledger_data.proto similarity index 100% rename from src/ripple/proto/org/xrpl/rpc/v1/get_ledger_data.proto rename to include/xrpl/proto/org/xrpl/rpc/v1/get_ledger_data.proto diff --git a/src/ripple/proto/org/xrpl/rpc/v1/get_ledger_diff.proto b/include/xrpl/proto/org/xrpl/rpc/v1/get_ledger_diff.proto similarity index 100% rename from src/ripple/proto/org/xrpl/rpc/v1/get_ledger_diff.proto rename to include/xrpl/proto/org/xrpl/rpc/v1/get_ledger_diff.proto diff --git a/src/ripple/proto/org/xrpl/rpc/v1/get_ledger_entry.proto b/include/xrpl/proto/org/xrpl/rpc/v1/get_ledger_entry.proto similarity index 100% rename from src/ripple/proto/org/xrpl/rpc/v1/get_ledger_entry.proto rename to include/xrpl/proto/org/xrpl/rpc/v1/get_ledger_entry.proto diff --git a/src/ripple/proto/org/xrpl/rpc/v1/ledger.proto b/include/xrpl/proto/org/xrpl/rpc/v1/ledger.proto similarity index 100% rename from src/ripple/proto/org/xrpl/rpc/v1/ledger.proto rename to include/xrpl/proto/org/xrpl/rpc/v1/ledger.proto diff --git a/src/ripple/proto/org/xrpl/rpc/v1/xrp_ledger.proto b/include/xrpl/proto/org/xrpl/rpc/v1/xrp_ledger.proto similarity index 100% rename from src/ripple/proto/org/xrpl/rpc/v1/xrp_ledger.proto rename to include/xrpl/proto/org/xrpl/rpc/v1/xrp_ledger.proto diff --git a/src/ripple/proto/ripple.proto b/include/xrpl/proto/ripple.proto similarity index 100% rename from src/ripple/proto/ripple.proto rename to include/xrpl/proto/ripple.proto diff --git a/src/ripple/protocol/AMMCore.h b/include/xrpl/protocol/AMMCore.h similarity index 100% rename from src/ripple/protocol/AMMCore.h rename to include/xrpl/protocol/AMMCore.h diff --git a/src/ripple/protocol/AccountID.h b/include/xrpl/protocol/AccountID.h similarity index 100% rename from src/ripple/protocol/AccountID.h rename to include/xrpl/protocol/AccountID.h diff --git a/src/ripple/protocol/AmountConversions.h b/include/xrpl/protocol/AmountConversions.h similarity index 100% rename from src/ripple/protocol/AmountConversions.h rename to include/xrpl/protocol/AmountConversions.h diff --git a/src/ripple/protocol/ApiVersion.h b/include/xrpl/protocol/ApiVersion.h similarity index 100% rename from src/ripple/protocol/ApiVersion.h rename to include/xrpl/protocol/ApiVersion.h diff --git a/src/ripple/protocol/Book.h b/include/xrpl/protocol/Book.h similarity index 100% rename from src/ripple/protocol/Book.h rename to include/xrpl/protocol/Book.h diff --git a/src/ripple/protocol/BuildInfo.h b/include/xrpl/protocol/BuildInfo.h similarity index 100% rename from src/ripple/protocol/BuildInfo.h rename to include/xrpl/protocol/BuildInfo.h diff --git a/src/ripple/protocol/ErrorCodes.h b/include/xrpl/protocol/ErrorCodes.h similarity index 100% rename from src/ripple/protocol/ErrorCodes.h rename to include/xrpl/protocol/ErrorCodes.h diff --git a/src/ripple/protocol/Feature.h b/include/xrpl/protocol/Feature.h similarity index 100% rename from src/ripple/protocol/Feature.h rename to include/xrpl/protocol/Feature.h diff --git a/src/ripple/protocol/Fees.h b/include/xrpl/protocol/Fees.h similarity index 100% rename from src/ripple/protocol/Fees.h rename to include/xrpl/protocol/Fees.h diff --git a/src/ripple/protocol/HashPrefix.h b/include/xrpl/protocol/HashPrefix.h similarity index 100% rename from src/ripple/protocol/HashPrefix.h rename to include/xrpl/protocol/HashPrefix.h diff --git a/src/ripple/protocol/Indexes.h b/include/xrpl/protocol/Indexes.h similarity index 100% rename from src/ripple/protocol/Indexes.h rename to include/xrpl/protocol/Indexes.h diff --git a/src/ripple/protocol/InnerObjectFormats.h b/include/xrpl/protocol/InnerObjectFormats.h similarity index 100% rename from src/ripple/protocol/InnerObjectFormats.h rename to include/xrpl/protocol/InnerObjectFormats.h diff --git a/src/ripple/protocol/Issue.h b/include/xrpl/protocol/Issue.h similarity index 100% rename from src/ripple/protocol/Issue.h rename to include/xrpl/protocol/Issue.h diff --git a/src/ripple/protocol/KeyType.h b/include/xrpl/protocol/KeyType.h similarity index 100% rename from src/ripple/protocol/KeyType.h rename to include/xrpl/protocol/KeyType.h diff --git a/src/ripple/protocol/Keylet.h b/include/xrpl/protocol/Keylet.h similarity index 100% rename from src/ripple/protocol/Keylet.h rename to include/xrpl/protocol/Keylet.h diff --git a/src/ripple/protocol/KnownFormats.h b/include/xrpl/protocol/KnownFormats.h similarity index 100% rename from src/ripple/protocol/KnownFormats.h rename to include/xrpl/protocol/KnownFormats.h diff --git a/src/ripple/protocol/LedgerFormats.h b/include/xrpl/protocol/LedgerFormats.h similarity index 100% rename from src/ripple/protocol/LedgerFormats.h rename to include/xrpl/protocol/LedgerFormats.h diff --git a/src/ripple/protocol/LedgerHeader.h b/include/xrpl/protocol/LedgerHeader.h similarity index 100% rename from src/ripple/protocol/LedgerHeader.h rename to include/xrpl/protocol/LedgerHeader.h diff --git a/src/ripple/protocol/MultiApiJson.h b/include/xrpl/protocol/MultiApiJson.h similarity index 100% rename from src/ripple/protocol/MultiApiJson.h rename to include/xrpl/protocol/MultiApiJson.h diff --git a/src/ripple/protocol/NFTSyntheticSerializer.h b/include/xrpl/protocol/NFTSyntheticSerializer.h similarity index 100% rename from src/ripple/protocol/NFTSyntheticSerializer.h rename to include/xrpl/protocol/NFTSyntheticSerializer.h diff --git a/src/ripple/protocol/NFTokenID.h b/include/xrpl/protocol/NFTokenID.h similarity index 100% rename from src/ripple/protocol/NFTokenID.h rename to include/xrpl/protocol/NFTokenID.h diff --git a/src/ripple/protocol/NFTokenOfferID.h b/include/xrpl/protocol/NFTokenOfferID.h similarity index 100% rename from src/ripple/protocol/NFTokenOfferID.h rename to include/xrpl/protocol/NFTokenOfferID.h diff --git a/src/ripple/protocol/PayChan.h b/include/xrpl/protocol/PayChan.h similarity index 100% rename from src/ripple/protocol/PayChan.h rename to include/xrpl/protocol/PayChan.h diff --git a/src/ripple/protocol/Protocol.h b/include/xrpl/protocol/Protocol.h similarity index 100% rename from src/ripple/protocol/Protocol.h rename to include/xrpl/protocol/Protocol.h diff --git a/src/ripple/protocol/PublicKey.h b/include/xrpl/protocol/PublicKey.h similarity index 100% rename from src/ripple/protocol/PublicKey.h rename to include/xrpl/protocol/PublicKey.h diff --git a/src/ripple/protocol/Quality.h b/include/xrpl/protocol/Quality.h similarity index 100% rename from src/ripple/protocol/Quality.h rename to include/xrpl/protocol/Quality.h diff --git a/src/ripple/protocol/QualityFunction.h b/include/xrpl/protocol/QualityFunction.h similarity index 100% rename from src/ripple/protocol/QualityFunction.h rename to include/xrpl/protocol/QualityFunction.h diff --git a/src/ripple/protocol/README.md b/include/xrpl/protocol/README.md similarity index 100% rename from src/ripple/protocol/README.md rename to include/xrpl/protocol/README.md diff --git a/src/ripple/protocol/RPCErr.h b/include/xrpl/protocol/RPCErr.h similarity index 100% rename from src/ripple/protocol/RPCErr.h rename to include/xrpl/protocol/RPCErr.h diff --git a/src/ripple/protocol/Rate.h b/include/xrpl/protocol/Rate.h similarity index 100% rename from src/ripple/protocol/Rate.h rename to include/xrpl/protocol/Rate.h diff --git a/src/ripple/protocol/RippleLedgerHash.h b/include/xrpl/protocol/RippleLedgerHash.h similarity index 100% rename from src/ripple/protocol/RippleLedgerHash.h rename to include/xrpl/protocol/RippleLedgerHash.h diff --git a/src/ripple/protocol/Rules.h b/include/xrpl/protocol/Rules.h similarity index 100% rename from src/ripple/protocol/Rules.h rename to include/xrpl/protocol/Rules.h diff --git a/src/ripple/protocol/SField.h b/include/xrpl/protocol/SField.h similarity index 100% rename from src/ripple/protocol/SField.h rename to include/xrpl/protocol/SField.h diff --git a/src/ripple/protocol/SOTemplate.h b/include/xrpl/protocol/SOTemplate.h similarity index 100% rename from src/ripple/protocol/SOTemplate.h rename to include/xrpl/protocol/SOTemplate.h diff --git a/src/ripple/protocol/STAccount.h b/include/xrpl/protocol/STAccount.h similarity index 100% rename from src/ripple/protocol/STAccount.h rename to include/xrpl/protocol/STAccount.h diff --git a/src/ripple/protocol/STAmount.h b/include/xrpl/protocol/STAmount.h similarity index 100% rename from src/ripple/protocol/STAmount.h rename to include/xrpl/protocol/STAmount.h diff --git a/src/ripple/protocol/STArray.h b/include/xrpl/protocol/STArray.h similarity index 100% rename from src/ripple/protocol/STArray.h rename to include/xrpl/protocol/STArray.h diff --git a/src/ripple/protocol/STBase.h b/include/xrpl/protocol/STBase.h similarity index 100% rename from src/ripple/protocol/STBase.h rename to include/xrpl/protocol/STBase.h diff --git a/src/ripple/protocol/STBitString.h b/include/xrpl/protocol/STBitString.h similarity index 100% rename from src/ripple/protocol/STBitString.h rename to include/xrpl/protocol/STBitString.h diff --git a/src/ripple/protocol/STBlob.h b/include/xrpl/protocol/STBlob.h similarity index 100% rename from src/ripple/protocol/STBlob.h rename to include/xrpl/protocol/STBlob.h diff --git a/src/ripple/protocol/STCurrency.h b/include/xrpl/protocol/STCurrency.h similarity index 100% rename from src/ripple/protocol/STCurrency.h rename to include/xrpl/protocol/STCurrency.h diff --git a/src/ripple/protocol/STExchange.h b/include/xrpl/protocol/STExchange.h similarity index 100% rename from src/ripple/protocol/STExchange.h rename to include/xrpl/protocol/STExchange.h diff --git a/src/ripple/protocol/STInteger.h b/include/xrpl/protocol/STInteger.h similarity index 100% rename from src/ripple/protocol/STInteger.h rename to include/xrpl/protocol/STInteger.h diff --git a/src/ripple/protocol/STIssue.h b/include/xrpl/protocol/STIssue.h similarity index 100% rename from src/ripple/protocol/STIssue.h rename to include/xrpl/protocol/STIssue.h diff --git a/src/ripple/protocol/STLedgerEntry.h b/include/xrpl/protocol/STLedgerEntry.h similarity index 100% rename from src/ripple/protocol/STLedgerEntry.h rename to include/xrpl/protocol/STLedgerEntry.h diff --git a/src/ripple/protocol/STObject.h b/include/xrpl/protocol/STObject.h similarity index 100% rename from src/ripple/protocol/STObject.h rename to include/xrpl/protocol/STObject.h diff --git a/src/ripple/protocol/STParsedJSON.h b/include/xrpl/protocol/STParsedJSON.h similarity index 100% rename from src/ripple/protocol/STParsedJSON.h rename to include/xrpl/protocol/STParsedJSON.h diff --git a/src/ripple/protocol/STPathSet.h b/include/xrpl/protocol/STPathSet.h similarity index 100% rename from src/ripple/protocol/STPathSet.h rename to include/xrpl/protocol/STPathSet.h diff --git a/src/ripple/protocol/STTx.h b/include/xrpl/protocol/STTx.h similarity index 100% rename from src/ripple/protocol/STTx.h rename to include/xrpl/protocol/STTx.h diff --git a/src/ripple/protocol/STValidation.h b/include/xrpl/protocol/STValidation.h similarity index 100% rename from src/ripple/protocol/STValidation.h rename to include/xrpl/protocol/STValidation.h diff --git a/src/ripple/protocol/STVector256.h b/include/xrpl/protocol/STVector256.h similarity index 100% rename from src/ripple/protocol/STVector256.h rename to include/xrpl/protocol/STVector256.h diff --git a/src/ripple/protocol/STXChainBridge.h b/include/xrpl/protocol/STXChainBridge.h similarity index 100% rename from src/ripple/protocol/STXChainBridge.h rename to include/xrpl/protocol/STXChainBridge.h diff --git a/src/ripple/protocol/SecretKey.h b/include/xrpl/protocol/SecretKey.h similarity index 100% rename from src/ripple/protocol/SecretKey.h rename to include/xrpl/protocol/SecretKey.h diff --git a/src/ripple/protocol/Seed.h b/include/xrpl/protocol/Seed.h similarity index 100% rename from src/ripple/protocol/Seed.h rename to include/xrpl/protocol/Seed.h diff --git a/src/ripple/protocol/SeqProxy.h b/include/xrpl/protocol/SeqProxy.h similarity index 100% rename from src/ripple/protocol/SeqProxy.h rename to include/xrpl/protocol/SeqProxy.h diff --git a/src/ripple/protocol/Serializer.h b/include/xrpl/protocol/Serializer.h similarity index 100% rename from src/ripple/protocol/Serializer.h rename to include/xrpl/protocol/Serializer.h diff --git a/src/ripple/protocol/Sign.h b/include/xrpl/protocol/Sign.h similarity index 100% rename from src/ripple/protocol/Sign.h rename to include/xrpl/protocol/Sign.h diff --git a/src/ripple/protocol/SystemParameters.h b/include/xrpl/protocol/SystemParameters.h similarity index 100% rename from src/ripple/protocol/SystemParameters.h rename to include/xrpl/protocol/SystemParameters.h diff --git a/src/ripple/protocol/TER.h b/include/xrpl/protocol/TER.h similarity index 100% rename from src/ripple/protocol/TER.h rename to include/xrpl/protocol/TER.h diff --git a/src/ripple/protocol/TxFlags.h b/include/xrpl/protocol/TxFlags.h similarity index 100% rename from src/ripple/protocol/TxFlags.h rename to include/xrpl/protocol/TxFlags.h diff --git a/src/ripple/protocol/TxFormats.h b/include/xrpl/protocol/TxFormats.h similarity index 100% rename from src/ripple/protocol/TxFormats.h rename to include/xrpl/protocol/TxFormats.h diff --git a/src/ripple/protocol/TxMeta.h b/include/xrpl/protocol/TxMeta.h similarity index 100% rename from src/ripple/protocol/TxMeta.h rename to include/xrpl/protocol/TxMeta.h diff --git a/src/ripple/protocol/UintTypes.h b/include/xrpl/protocol/UintTypes.h similarity index 100% rename from src/ripple/protocol/UintTypes.h rename to include/xrpl/protocol/UintTypes.h diff --git a/src/ripple/protocol/XChainAttestations.h b/include/xrpl/protocol/XChainAttestations.h similarity index 100% rename from src/ripple/protocol/XChainAttestations.h rename to include/xrpl/protocol/XChainAttestations.h diff --git a/src/ripple/protocol/impl/STVar.h b/include/xrpl/protocol/detail/STVar.h similarity index 100% rename from src/ripple/protocol/impl/STVar.h rename to include/xrpl/protocol/detail/STVar.h diff --git a/src/ripple/protocol/impl/b58_utils.h b/include/xrpl/protocol/detail/b58_utils.h similarity index 100% rename from src/ripple/protocol/impl/b58_utils.h rename to include/xrpl/protocol/detail/b58_utils.h diff --git a/src/ripple/protocol/impl/secp256k1.h b/include/xrpl/protocol/detail/secp256k1.h similarity index 100% rename from src/ripple/protocol/impl/secp256k1.h rename to include/xrpl/protocol/detail/secp256k1.h diff --git a/src/ripple/protocol/impl/token_errors.h b/include/xrpl/protocol/detail/token_errors.h similarity index 100% rename from src/ripple/protocol/impl/token_errors.h rename to include/xrpl/protocol/detail/token_errors.h diff --git a/src/ripple/protocol/digest.h b/include/xrpl/protocol/digest.h similarity index 100% rename from src/ripple/protocol/digest.h rename to include/xrpl/protocol/digest.h diff --git a/src/ripple/protocol/json_get_or_throw.h b/include/xrpl/protocol/json_get_or_throw.h similarity index 100% rename from src/ripple/protocol/json_get_or_throw.h rename to include/xrpl/protocol/json_get_or_throw.h diff --git a/src/ripple/protocol/jss.h b/include/xrpl/protocol/jss.h similarity index 100% rename from src/ripple/protocol/jss.h rename to include/xrpl/protocol/jss.h diff --git a/src/ripple/protocol/messages.h b/include/xrpl/protocol/messages.h similarity index 100% rename from src/ripple/protocol/messages.h rename to include/xrpl/protocol/messages.h diff --git a/src/ripple/protocol/nft.h b/include/xrpl/protocol/nft.h similarity index 100% rename from src/ripple/protocol/nft.h rename to include/xrpl/protocol/nft.h diff --git a/src/ripple/protocol/nftPageMask.h b/include/xrpl/protocol/nftPageMask.h similarity index 100% rename from src/ripple/protocol/nftPageMask.h rename to include/xrpl/protocol/nftPageMask.h diff --git a/src/ripple/protocol/serialize.h b/include/xrpl/protocol/serialize.h similarity index 100% rename from src/ripple/protocol/serialize.h rename to include/xrpl/protocol/serialize.h diff --git a/src/ripple/protocol/st.h b/include/xrpl/protocol/st.h similarity index 100% rename from src/ripple/protocol/st.h rename to include/xrpl/protocol/st.h diff --git a/src/ripple/protocol/tokens.h b/include/xrpl/protocol/tokens.h similarity index 100% rename from src/ripple/protocol/tokens.h rename to include/xrpl/protocol/tokens.h diff --git a/src/ripple/resource/Charge.h b/include/xrpl/resource/Charge.h similarity index 100% rename from src/ripple/resource/Charge.h rename to include/xrpl/resource/Charge.h diff --git a/src/ripple/resource/Consumer.h b/include/xrpl/resource/Consumer.h similarity index 100% rename from src/ripple/resource/Consumer.h rename to include/xrpl/resource/Consumer.h diff --git a/src/ripple/resource/Disposition.h b/include/xrpl/resource/Disposition.h similarity index 100% rename from src/ripple/resource/Disposition.h rename to include/xrpl/resource/Disposition.h diff --git a/src/ripple/resource/Fees.h b/include/xrpl/resource/Fees.h similarity index 100% rename from src/ripple/resource/Fees.h rename to include/xrpl/resource/Fees.h diff --git a/src/ripple/resource/Gossip.h b/include/xrpl/resource/Gossip.h similarity index 100% rename from src/ripple/resource/Gossip.h rename to include/xrpl/resource/Gossip.h diff --git a/src/ripple/resource/README.md b/include/xrpl/resource/README.md similarity index 100% rename from src/ripple/resource/README.md rename to include/xrpl/resource/README.md diff --git a/src/ripple/resource/ResourceManager.h b/include/xrpl/resource/ResourceManager.h similarity index 100% rename from src/ripple/resource/ResourceManager.h rename to include/xrpl/resource/ResourceManager.h diff --git a/src/ripple/resource/Types.h b/include/xrpl/resource/Types.h similarity index 100% rename from src/ripple/resource/Types.h rename to include/xrpl/resource/Types.h diff --git a/src/ripple/resource/impl/Entry.h b/include/xrpl/resource/detail/Entry.h similarity index 100% rename from src/ripple/resource/impl/Entry.h rename to include/xrpl/resource/detail/Entry.h diff --git a/src/ripple/resource/impl/Import.h b/include/xrpl/resource/detail/Import.h similarity index 100% rename from src/ripple/resource/impl/Import.h rename to include/xrpl/resource/detail/Import.h diff --git a/src/ripple/resource/impl/Key.h b/include/xrpl/resource/detail/Key.h similarity index 100% rename from src/ripple/resource/impl/Key.h rename to include/xrpl/resource/detail/Key.h diff --git a/src/ripple/resource/impl/Kind.h b/include/xrpl/resource/detail/Kind.h similarity index 100% rename from src/ripple/resource/impl/Kind.h rename to include/xrpl/resource/detail/Kind.h diff --git a/src/ripple/resource/impl/Logic.h b/include/xrpl/resource/detail/Logic.h similarity index 100% rename from src/ripple/resource/impl/Logic.h rename to include/xrpl/resource/detail/Logic.h diff --git a/src/ripple/resource/impl/Tuning.h b/include/xrpl/resource/detail/Tuning.h similarity index 100% rename from src/ripple/resource/impl/Tuning.h rename to include/xrpl/resource/detail/Tuning.h diff --git a/src/ripple/server/Handoff.h b/include/xrpl/server/Handoff.h similarity index 100% rename from src/ripple/server/Handoff.h rename to include/xrpl/server/Handoff.h diff --git a/src/ripple/server/Port.h b/include/xrpl/server/Port.h similarity index 100% rename from src/ripple/server/Port.h rename to include/xrpl/server/Port.h diff --git a/src/ripple/server/Server.h b/include/xrpl/server/Server.h similarity index 100% rename from src/ripple/server/Server.h rename to include/xrpl/server/Server.h diff --git a/src/ripple/server/Session.h b/include/xrpl/server/Session.h similarity index 100% rename from src/ripple/server/Session.h rename to include/xrpl/server/Session.h diff --git a/src/ripple/server/SimpleWriter.h b/include/xrpl/server/SimpleWriter.h similarity index 100% rename from src/ripple/server/SimpleWriter.h rename to include/xrpl/server/SimpleWriter.h diff --git a/src/ripple/server/WSSession.h b/include/xrpl/server/WSSession.h similarity index 100% rename from src/ripple/server/WSSession.h rename to include/xrpl/server/WSSession.h diff --git a/src/ripple/server/Writer.h b/include/xrpl/server/Writer.h similarity index 100% rename from src/ripple/server/Writer.h rename to include/xrpl/server/Writer.h diff --git a/src/ripple/server/impl/BaseHTTPPeer.h b/include/xrpl/server/detail/BaseHTTPPeer.h similarity index 100% rename from src/ripple/server/impl/BaseHTTPPeer.h rename to include/xrpl/server/detail/BaseHTTPPeer.h diff --git a/src/ripple/server/impl/BasePeer.h b/include/xrpl/server/detail/BasePeer.h similarity index 100% rename from src/ripple/server/impl/BasePeer.h rename to include/xrpl/server/detail/BasePeer.h diff --git a/src/ripple/server/impl/BaseWSPeer.h b/include/xrpl/server/detail/BaseWSPeer.h similarity index 100% rename from src/ripple/server/impl/BaseWSPeer.h rename to include/xrpl/server/detail/BaseWSPeer.h diff --git a/src/ripple/server/impl/Door.h b/include/xrpl/server/detail/Door.h similarity index 100% rename from src/ripple/server/impl/Door.h rename to include/xrpl/server/detail/Door.h diff --git a/src/ripple/server/impl/JSONRPCUtil.h b/include/xrpl/server/detail/JSONRPCUtil.h similarity index 100% rename from src/ripple/server/impl/JSONRPCUtil.h rename to include/xrpl/server/detail/JSONRPCUtil.h diff --git a/src/ripple/server/impl/LowestLayer.h b/include/xrpl/server/detail/LowestLayer.h similarity index 100% rename from src/ripple/server/impl/LowestLayer.h rename to include/xrpl/server/detail/LowestLayer.h diff --git a/src/ripple/server/impl/PlainHTTPPeer.h b/include/xrpl/server/detail/PlainHTTPPeer.h similarity index 100% rename from src/ripple/server/impl/PlainHTTPPeer.h rename to include/xrpl/server/detail/PlainHTTPPeer.h diff --git a/src/ripple/server/impl/PlainWSPeer.h b/include/xrpl/server/detail/PlainWSPeer.h similarity index 100% rename from src/ripple/server/impl/PlainWSPeer.h rename to include/xrpl/server/detail/PlainWSPeer.h diff --git a/src/ripple/server/impl/SSLHTTPPeer.h b/include/xrpl/server/detail/SSLHTTPPeer.h similarity index 100% rename from src/ripple/server/impl/SSLHTTPPeer.h rename to include/xrpl/server/detail/SSLHTTPPeer.h diff --git a/src/ripple/server/impl/SSLWSPeer.h b/include/xrpl/server/detail/SSLWSPeer.h similarity index 100% rename from src/ripple/server/impl/SSLWSPeer.h rename to include/xrpl/server/detail/SSLWSPeer.h diff --git a/src/ripple/server/impl/ServerImpl.h b/include/xrpl/server/detail/ServerImpl.h similarity index 100% rename from src/ripple/server/impl/ServerImpl.h rename to include/xrpl/server/detail/ServerImpl.h diff --git a/src/ripple/server/impl/io_list.h b/include/xrpl/server/detail/io_list.h similarity index 100% rename from src/ripple/server/impl/io_list.h rename to include/xrpl/server/detail/io_list.h diff --git a/src/ripple/basics/impl/Archive.cpp b/src/libxrpl/basics/Archive.cpp similarity index 100% rename from src/ripple/basics/impl/Archive.cpp rename to src/libxrpl/basics/Archive.cpp diff --git a/src/ripple/basics/impl/BasicConfig.cpp b/src/libxrpl/basics/BasicConfig.cpp similarity index 100% rename from src/ripple/basics/impl/BasicConfig.cpp rename to src/libxrpl/basics/BasicConfig.cpp diff --git a/src/ripple/basics/impl/CountedObject.cpp b/src/libxrpl/basics/CountedObject.cpp similarity index 100% rename from src/ripple/basics/impl/CountedObject.cpp rename to src/libxrpl/basics/CountedObject.cpp diff --git a/src/ripple/basics/impl/FileUtilities.cpp b/src/libxrpl/basics/FileUtilities.cpp similarity index 100% rename from src/ripple/basics/impl/FileUtilities.cpp rename to src/libxrpl/basics/FileUtilities.cpp diff --git a/src/ripple/basics/impl/IOUAmount.cpp b/src/libxrpl/basics/IOUAmount.cpp similarity index 100% rename from src/ripple/basics/impl/IOUAmount.cpp rename to src/libxrpl/basics/IOUAmount.cpp diff --git a/src/ripple/basics/impl/Log.cpp b/src/libxrpl/basics/Log.cpp similarity index 100% rename from src/ripple/basics/impl/Log.cpp rename to src/libxrpl/basics/Log.cpp diff --git a/src/ripple/basics/impl/Number.cpp b/src/libxrpl/basics/Number.cpp similarity index 100% rename from src/ripple/basics/impl/Number.cpp rename to src/libxrpl/basics/Number.cpp diff --git a/src/ripple/basics/impl/ResolverAsio.cpp b/src/libxrpl/basics/ResolverAsio.cpp similarity index 100% rename from src/ripple/basics/impl/ResolverAsio.cpp rename to src/libxrpl/basics/ResolverAsio.cpp diff --git a/src/ripple/basics/impl/StringUtilities.cpp b/src/libxrpl/basics/StringUtilities.cpp similarity index 100% rename from src/ripple/basics/impl/StringUtilities.cpp rename to src/libxrpl/basics/StringUtilities.cpp diff --git a/src/ripple/basics/impl/UptimeClock.cpp b/src/libxrpl/basics/UptimeClock.cpp similarity index 100% rename from src/ripple/basics/impl/UptimeClock.cpp rename to src/libxrpl/basics/UptimeClock.cpp diff --git a/src/ripple/basics/impl/base64.cpp b/src/libxrpl/basics/base64.cpp similarity index 100% rename from src/ripple/basics/impl/base64.cpp rename to src/libxrpl/basics/base64.cpp diff --git a/src/ripple/basics/impl/contract.cpp b/src/libxrpl/basics/contract.cpp similarity index 100% rename from src/ripple/basics/impl/contract.cpp rename to src/libxrpl/basics/contract.cpp diff --git a/src/ripple/basics/impl/make_SSLContext.cpp b/src/libxrpl/basics/make_SSLContext.cpp similarity index 100% rename from src/ripple/basics/impl/make_SSLContext.cpp rename to src/libxrpl/basics/make_SSLContext.cpp diff --git a/src/ripple/basics/impl/mulDiv.cpp b/src/libxrpl/basics/mulDiv.cpp similarity index 100% rename from src/ripple/basics/impl/mulDiv.cpp rename to src/libxrpl/basics/mulDiv.cpp diff --git a/src/ripple/basics/impl/partitioned_unordered_map.cpp b/src/libxrpl/basics/partitioned_unordered_map.cpp similarity index 100% rename from src/ripple/basics/impl/partitioned_unordered_map.cpp rename to src/libxrpl/basics/partitioned_unordered_map.cpp diff --git a/src/ripple/beast/clock/basic_seconds_clock.cpp b/src/libxrpl/beast/clock/basic_seconds_clock.cpp similarity index 100% rename from src/ripple/beast/clock/basic_seconds_clock.cpp rename to src/libxrpl/beast/clock/basic_seconds_clock.cpp diff --git a/src/ripple/beast/core/CurrentThreadName.cpp b/src/libxrpl/beast/core/CurrentThreadName.cpp similarity index 100% rename from src/ripple/beast/core/CurrentThreadName.cpp rename to src/libxrpl/beast/core/CurrentThreadName.cpp diff --git a/src/ripple/beast/core/SemanticVersion.cpp b/src/libxrpl/beast/core/SemanticVersion.cpp similarity index 100% rename from src/ripple/beast/core/SemanticVersion.cpp rename to src/libxrpl/beast/core/SemanticVersion.cpp diff --git a/src/ripple/beast/insight/impl/Collector.cpp b/src/libxrpl/beast/insight/Collector.cpp similarity index 100% rename from src/ripple/beast/insight/impl/Collector.cpp rename to src/libxrpl/beast/insight/Collector.cpp diff --git a/src/ripple/beast/insight/impl/Groups.cpp b/src/libxrpl/beast/insight/Groups.cpp similarity index 100% rename from src/ripple/beast/insight/impl/Groups.cpp rename to src/libxrpl/beast/insight/Groups.cpp diff --git a/src/ripple/beast/insight/impl/Hook.cpp b/src/libxrpl/beast/insight/Hook.cpp similarity index 100% rename from src/ripple/beast/insight/impl/Hook.cpp rename to src/libxrpl/beast/insight/Hook.cpp diff --git a/src/ripple/beast/insight/impl/Metric.cpp b/src/libxrpl/beast/insight/Metric.cpp similarity index 100% rename from src/ripple/beast/insight/impl/Metric.cpp rename to src/libxrpl/beast/insight/Metric.cpp diff --git a/src/ripple/beast/insight/impl/NullCollector.cpp b/src/libxrpl/beast/insight/NullCollector.cpp similarity index 100% rename from src/ripple/beast/insight/impl/NullCollector.cpp rename to src/libxrpl/beast/insight/NullCollector.cpp diff --git a/src/ripple/beast/insight/impl/StatsDCollector.cpp b/src/libxrpl/beast/insight/StatsDCollector.cpp similarity index 100% rename from src/ripple/beast/insight/impl/StatsDCollector.cpp rename to src/libxrpl/beast/insight/StatsDCollector.cpp diff --git a/src/ripple/beast/net/impl/IPAddressConversion.cpp b/src/libxrpl/beast/net/IPAddressConversion.cpp similarity index 100% rename from src/ripple/beast/net/impl/IPAddressConversion.cpp rename to src/libxrpl/beast/net/IPAddressConversion.cpp diff --git a/src/ripple/beast/net/impl/IPAddressV4.cpp b/src/libxrpl/beast/net/IPAddressV4.cpp similarity index 100% rename from src/ripple/beast/net/impl/IPAddressV4.cpp rename to src/libxrpl/beast/net/IPAddressV4.cpp diff --git a/src/ripple/beast/net/impl/IPAddressV6.cpp b/src/libxrpl/beast/net/IPAddressV6.cpp similarity index 100% rename from src/ripple/beast/net/impl/IPAddressV6.cpp rename to src/libxrpl/beast/net/IPAddressV6.cpp diff --git a/src/ripple/beast/net/impl/IPEndpoint.cpp b/src/libxrpl/beast/net/IPEndpoint.cpp similarity index 100% rename from src/ripple/beast/net/impl/IPEndpoint.cpp rename to src/libxrpl/beast/net/IPEndpoint.cpp diff --git a/src/ripple/beast/utility/src/beast_Journal.cpp b/src/libxrpl/beast/utility/src/beast_Journal.cpp similarity index 100% rename from src/ripple/beast/utility/src/beast_Journal.cpp rename to src/libxrpl/beast/utility/src/beast_Journal.cpp diff --git a/src/ripple/beast/utility/src/beast_PropertyStream.cpp b/src/libxrpl/beast/utility/src/beast_PropertyStream.cpp similarity index 100% rename from src/ripple/beast/utility/src/beast_PropertyStream.cpp rename to src/libxrpl/beast/utility/src/beast_PropertyStream.cpp diff --git a/src/ripple/crypto/impl/RFC1751.cpp b/src/libxrpl/crypto/RFC1751.cpp similarity index 100% rename from src/ripple/crypto/impl/RFC1751.cpp rename to src/libxrpl/crypto/RFC1751.cpp diff --git a/src/ripple/crypto/impl/csprng.cpp b/src/libxrpl/crypto/csprng.cpp similarity index 100% rename from src/ripple/crypto/impl/csprng.cpp rename to src/libxrpl/crypto/csprng.cpp diff --git a/src/ripple/crypto/impl/secure_erase.cpp b/src/libxrpl/crypto/secure_erase.cpp similarity index 100% rename from src/ripple/crypto/impl/secure_erase.cpp rename to src/libxrpl/crypto/secure_erase.cpp diff --git a/src/ripple/json/impl/JsonPropertyStream.cpp b/src/libxrpl/json/JsonPropertyStream.cpp similarity index 100% rename from src/ripple/json/impl/JsonPropertyStream.cpp rename to src/libxrpl/json/JsonPropertyStream.cpp diff --git a/src/ripple/json/impl/Object.cpp b/src/libxrpl/json/Object.cpp similarity index 100% rename from src/ripple/json/impl/Object.cpp rename to src/libxrpl/json/Object.cpp diff --git a/src/ripple/json/impl/Output.cpp b/src/libxrpl/json/Output.cpp similarity index 100% rename from src/ripple/json/impl/Output.cpp rename to src/libxrpl/json/Output.cpp diff --git a/src/ripple/json/impl/Writer.cpp b/src/libxrpl/json/Writer.cpp similarity index 100% rename from src/ripple/json/impl/Writer.cpp rename to src/libxrpl/json/Writer.cpp diff --git a/src/ripple/json/impl/json_reader.cpp b/src/libxrpl/json/json_reader.cpp similarity index 100% rename from src/ripple/json/impl/json_reader.cpp rename to src/libxrpl/json/json_reader.cpp diff --git a/src/ripple/json/impl/json_value.cpp b/src/libxrpl/json/json_value.cpp similarity index 100% rename from src/ripple/json/impl/json_value.cpp rename to src/libxrpl/json/json_value.cpp diff --git a/src/ripple/json/impl/json_valueiterator.cpp b/src/libxrpl/json/json_valueiterator.cpp similarity index 100% rename from src/ripple/json/impl/json_valueiterator.cpp rename to src/libxrpl/json/json_valueiterator.cpp diff --git a/src/ripple/json/impl/json_writer.cpp b/src/libxrpl/json/json_writer.cpp similarity index 100% rename from src/ripple/json/impl/json_writer.cpp rename to src/libxrpl/json/json_writer.cpp diff --git a/src/ripple/json/impl/to_string.cpp b/src/libxrpl/json/to_string.cpp similarity index 100% rename from src/ripple/json/impl/to_string.cpp rename to src/libxrpl/json/to_string.cpp diff --git a/src/ripple/protocol/impl/AMMCore.cpp b/src/libxrpl/protocol/AMMCore.cpp similarity index 100% rename from src/ripple/protocol/impl/AMMCore.cpp rename to src/libxrpl/protocol/AMMCore.cpp diff --git a/src/ripple/protocol/impl/AccountID.cpp b/src/libxrpl/protocol/AccountID.cpp similarity index 100% rename from src/ripple/protocol/impl/AccountID.cpp rename to src/libxrpl/protocol/AccountID.cpp diff --git a/src/ripple/protocol/impl/Book.cpp b/src/libxrpl/protocol/Book.cpp similarity index 100% rename from src/ripple/protocol/impl/Book.cpp rename to src/libxrpl/protocol/Book.cpp diff --git a/src/ripple/protocol/impl/BuildInfo.cpp b/src/libxrpl/protocol/BuildInfo.cpp similarity index 100% rename from src/ripple/protocol/impl/BuildInfo.cpp rename to src/libxrpl/protocol/BuildInfo.cpp diff --git a/src/ripple/protocol/impl/ErrorCodes.cpp b/src/libxrpl/protocol/ErrorCodes.cpp similarity index 100% rename from src/ripple/protocol/impl/ErrorCodes.cpp rename to src/libxrpl/protocol/ErrorCodes.cpp diff --git a/src/ripple/protocol/impl/Feature.cpp b/src/libxrpl/protocol/Feature.cpp similarity index 100% rename from src/ripple/protocol/impl/Feature.cpp rename to src/libxrpl/protocol/Feature.cpp diff --git a/src/ripple/protocol/impl/Indexes.cpp b/src/libxrpl/protocol/Indexes.cpp similarity index 100% rename from src/ripple/protocol/impl/Indexes.cpp rename to src/libxrpl/protocol/Indexes.cpp diff --git a/src/ripple/protocol/impl/InnerObjectFormats.cpp b/src/libxrpl/protocol/InnerObjectFormats.cpp similarity index 100% rename from src/ripple/protocol/impl/InnerObjectFormats.cpp rename to src/libxrpl/protocol/InnerObjectFormats.cpp diff --git a/src/ripple/protocol/impl/Issue.cpp b/src/libxrpl/protocol/Issue.cpp similarity index 100% rename from src/ripple/protocol/impl/Issue.cpp rename to src/libxrpl/protocol/Issue.cpp diff --git a/src/ripple/protocol/impl/Keylet.cpp b/src/libxrpl/protocol/Keylet.cpp similarity index 100% rename from src/ripple/protocol/impl/Keylet.cpp rename to src/libxrpl/protocol/Keylet.cpp diff --git a/src/ripple/protocol/impl/LedgerFormats.cpp b/src/libxrpl/protocol/LedgerFormats.cpp similarity index 100% rename from src/ripple/protocol/impl/LedgerFormats.cpp rename to src/libxrpl/protocol/LedgerFormats.cpp diff --git a/src/ripple/protocol/impl/LedgerHeader.cpp b/src/libxrpl/protocol/LedgerHeader.cpp similarity index 100% rename from src/ripple/protocol/impl/LedgerHeader.cpp rename to src/libxrpl/protocol/LedgerHeader.cpp diff --git a/src/ripple/protocol/impl/NFTSyntheticSerializer.cpp b/src/libxrpl/protocol/NFTSyntheticSerializer.cpp similarity index 100% rename from src/ripple/protocol/impl/NFTSyntheticSerializer.cpp rename to src/libxrpl/protocol/NFTSyntheticSerializer.cpp diff --git a/src/ripple/protocol/impl/NFTokenID.cpp b/src/libxrpl/protocol/NFTokenID.cpp similarity index 100% rename from src/ripple/protocol/impl/NFTokenID.cpp rename to src/libxrpl/protocol/NFTokenID.cpp diff --git a/src/ripple/protocol/impl/NFTokenOfferID.cpp b/src/libxrpl/protocol/NFTokenOfferID.cpp similarity index 100% rename from src/ripple/protocol/impl/NFTokenOfferID.cpp rename to src/libxrpl/protocol/NFTokenOfferID.cpp diff --git a/src/ripple/protocol/impl/PublicKey.cpp b/src/libxrpl/protocol/PublicKey.cpp similarity index 100% rename from src/ripple/protocol/impl/PublicKey.cpp rename to src/libxrpl/protocol/PublicKey.cpp diff --git a/src/ripple/protocol/impl/Quality.cpp b/src/libxrpl/protocol/Quality.cpp similarity index 100% rename from src/ripple/protocol/impl/Quality.cpp rename to src/libxrpl/protocol/Quality.cpp diff --git a/src/ripple/protocol/impl/QualityFunction.cpp b/src/libxrpl/protocol/QualityFunction.cpp similarity index 100% rename from src/ripple/protocol/impl/QualityFunction.cpp rename to src/libxrpl/protocol/QualityFunction.cpp diff --git a/src/ripple/protocol/impl/RPCErr.cpp b/src/libxrpl/protocol/RPCErr.cpp similarity index 100% rename from src/ripple/protocol/impl/RPCErr.cpp rename to src/libxrpl/protocol/RPCErr.cpp diff --git a/src/ripple/protocol/impl/Rate2.cpp b/src/libxrpl/protocol/Rate2.cpp similarity index 100% rename from src/ripple/protocol/impl/Rate2.cpp rename to src/libxrpl/protocol/Rate2.cpp diff --git a/src/ripple/protocol/impl/Rules.cpp b/src/libxrpl/protocol/Rules.cpp similarity index 100% rename from src/ripple/protocol/impl/Rules.cpp rename to src/libxrpl/protocol/Rules.cpp diff --git a/src/ripple/protocol/impl/SField.cpp b/src/libxrpl/protocol/SField.cpp similarity index 100% rename from src/ripple/protocol/impl/SField.cpp rename to src/libxrpl/protocol/SField.cpp diff --git a/src/ripple/protocol/impl/SOTemplate.cpp b/src/libxrpl/protocol/SOTemplate.cpp similarity index 100% rename from src/ripple/protocol/impl/SOTemplate.cpp rename to src/libxrpl/protocol/SOTemplate.cpp diff --git a/src/ripple/protocol/impl/STAccount.cpp b/src/libxrpl/protocol/STAccount.cpp similarity index 100% rename from src/ripple/protocol/impl/STAccount.cpp rename to src/libxrpl/protocol/STAccount.cpp diff --git a/src/ripple/protocol/impl/STAmount.cpp b/src/libxrpl/protocol/STAmount.cpp similarity index 100% rename from src/ripple/protocol/impl/STAmount.cpp rename to src/libxrpl/protocol/STAmount.cpp diff --git a/src/ripple/protocol/impl/STArray.cpp b/src/libxrpl/protocol/STArray.cpp similarity index 100% rename from src/ripple/protocol/impl/STArray.cpp rename to src/libxrpl/protocol/STArray.cpp diff --git a/src/ripple/protocol/impl/STBase.cpp b/src/libxrpl/protocol/STBase.cpp similarity index 100% rename from src/ripple/protocol/impl/STBase.cpp rename to src/libxrpl/protocol/STBase.cpp diff --git a/src/ripple/protocol/impl/STBlob.cpp b/src/libxrpl/protocol/STBlob.cpp similarity index 100% rename from src/ripple/protocol/impl/STBlob.cpp rename to src/libxrpl/protocol/STBlob.cpp diff --git a/src/ripple/protocol/impl/STCurrency.cpp b/src/libxrpl/protocol/STCurrency.cpp similarity index 100% rename from src/ripple/protocol/impl/STCurrency.cpp rename to src/libxrpl/protocol/STCurrency.cpp diff --git a/src/ripple/protocol/impl/STInteger.cpp b/src/libxrpl/protocol/STInteger.cpp similarity index 100% rename from src/ripple/protocol/impl/STInteger.cpp rename to src/libxrpl/protocol/STInteger.cpp diff --git a/src/ripple/protocol/impl/STIssue.cpp b/src/libxrpl/protocol/STIssue.cpp similarity index 100% rename from src/ripple/protocol/impl/STIssue.cpp rename to src/libxrpl/protocol/STIssue.cpp diff --git a/src/ripple/protocol/impl/STLedgerEntry.cpp b/src/libxrpl/protocol/STLedgerEntry.cpp similarity index 100% rename from src/ripple/protocol/impl/STLedgerEntry.cpp rename to src/libxrpl/protocol/STLedgerEntry.cpp diff --git a/src/ripple/protocol/impl/STObject.cpp b/src/libxrpl/protocol/STObject.cpp similarity index 100% rename from src/ripple/protocol/impl/STObject.cpp rename to src/libxrpl/protocol/STObject.cpp diff --git a/src/ripple/protocol/impl/STParsedJSON.cpp b/src/libxrpl/protocol/STParsedJSON.cpp similarity index 100% rename from src/ripple/protocol/impl/STParsedJSON.cpp rename to src/libxrpl/protocol/STParsedJSON.cpp diff --git a/src/ripple/protocol/impl/STPathSet.cpp b/src/libxrpl/protocol/STPathSet.cpp similarity index 100% rename from src/ripple/protocol/impl/STPathSet.cpp rename to src/libxrpl/protocol/STPathSet.cpp diff --git a/src/ripple/protocol/impl/STTx.cpp b/src/libxrpl/protocol/STTx.cpp similarity index 100% rename from src/ripple/protocol/impl/STTx.cpp rename to src/libxrpl/protocol/STTx.cpp diff --git a/src/ripple/protocol/impl/STValidation.cpp b/src/libxrpl/protocol/STValidation.cpp similarity index 100% rename from src/ripple/protocol/impl/STValidation.cpp rename to src/libxrpl/protocol/STValidation.cpp diff --git a/src/ripple/protocol/impl/STVar.cpp b/src/libxrpl/protocol/STVar.cpp similarity index 100% rename from src/ripple/protocol/impl/STVar.cpp rename to src/libxrpl/protocol/STVar.cpp diff --git a/src/ripple/protocol/impl/STVector256.cpp b/src/libxrpl/protocol/STVector256.cpp similarity index 100% rename from src/ripple/protocol/impl/STVector256.cpp rename to src/libxrpl/protocol/STVector256.cpp diff --git a/src/ripple/protocol/impl/STXChainBridge.cpp b/src/libxrpl/protocol/STXChainBridge.cpp similarity index 100% rename from src/ripple/protocol/impl/STXChainBridge.cpp rename to src/libxrpl/protocol/STXChainBridge.cpp diff --git a/src/ripple/protocol/impl/SecretKey.cpp b/src/libxrpl/protocol/SecretKey.cpp similarity index 100% rename from src/ripple/protocol/impl/SecretKey.cpp rename to src/libxrpl/protocol/SecretKey.cpp diff --git a/src/ripple/protocol/impl/Seed.cpp b/src/libxrpl/protocol/Seed.cpp similarity index 100% rename from src/ripple/protocol/impl/Seed.cpp rename to src/libxrpl/protocol/Seed.cpp diff --git a/src/ripple/protocol/impl/Serializer.cpp b/src/libxrpl/protocol/Serializer.cpp similarity index 100% rename from src/ripple/protocol/impl/Serializer.cpp rename to src/libxrpl/protocol/Serializer.cpp diff --git a/src/ripple/protocol/impl/Sign.cpp b/src/libxrpl/protocol/Sign.cpp similarity index 100% rename from src/ripple/protocol/impl/Sign.cpp rename to src/libxrpl/protocol/Sign.cpp diff --git a/src/ripple/protocol/impl/TER.cpp b/src/libxrpl/protocol/TER.cpp similarity index 100% rename from src/ripple/protocol/impl/TER.cpp rename to src/libxrpl/protocol/TER.cpp diff --git a/src/ripple/protocol/impl/TxFormats.cpp b/src/libxrpl/protocol/TxFormats.cpp similarity index 100% rename from src/ripple/protocol/impl/TxFormats.cpp rename to src/libxrpl/protocol/TxFormats.cpp diff --git a/src/ripple/protocol/impl/TxMeta.cpp b/src/libxrpl/protocol/TxMeta.cpp similarity index 100% rename from src/ripple/protocol/impl/TxMeta.cpp rename to src/libxrpl/protocol/TxMeta.cpp diff --git a/src/ripple/protocol/impl/UintTypes.cpp b/src/libxrpl/protocol/UintTypes.cpp similarity index 100% rename from src/ripple/protocol/impl/UintTypes.cpp rename to src/libxrpl/protocol/UintTypes.cpp diff --git a/src/ripple/protocol/impl/XChainAttestations.cpp b/src/libxrpl/protocol/XChainAttestations.cpp similarity index 100% rename from src/ripple/protocol/impl/XChainAttestations.cpp rename to src/libxrpl/protocol/XChainAttestations.cpp diff --git a/src/ripple/protocol/impl/digest.cpp b/src/libxrpl/protocol/digest.cpp similarity index 100% rename from src/ripple/protocol/impl/digest.cpp rename to src/libxrpl/protocol/digest.cpp diff --git a/src/ripple/protocol/impl/tokens.cpp b/src/libxrpl/protocol/tokens.cpp similarity index 100% rename from src/ripple/protocol/impl/tokens.cpp rename to src/libxrpl/protocol/tokens.cpp diff --git a/src/ripple/resource/impl/Charge.cpp b/src/libxrpl/resource/Charge.cpp similarity index 100% rename from src/ripple/resource/impl/Charge.cpp rename to src/libxrpl/resource/Charge.cpp diff --git a/src/ripple/resource/impl/Consumer.cpp b/src/libxrpl/resource/Consumer.cpp similarity index 100% rename from src/ripple/resource/impl/Consumer.cpp rename to src/libxrpl/resource/Consumer.cpp diff --git a/src/ripple/resource/impl/Fees.cpp b/src/libxrpl/resource/Fees.cpp similarity index 100% rename from src/ripple/resource/impl/Fees.cpp rename to src/libxrpl/resource/Fees.cpp diff --git a/src/ripple/resource/impl/ResourceManager.cpp b/src/libxrpl/resource/ResourceManager.cpp similarity index 100% rename from src/ripple/resource/impl/ResourceManager.cpp rename to src/libxrpl/resource/ResourceManager.cpp diff --git a/src/ripple/server/impl/JSONRPCUtil.cpp b/src/libxrpl/server/JSONRPCUtil.cpp similarity index 100% rename from src/ripple/server/impl/JSONRPCUtil.cpp rename to src/libxrpl/server/JSONRPCUtil.cpp diff --git a/src/ripple/server/impl/Port.cpp b/src/libxrpl/server/Port.cpp similarity index 100% rename from src/ripple/server/impl/Port.cpp rename to src/libxrpl/server/Port.cpp diff --git a/src/ripple/README.md b/src/xrpld/README.md similarity index 100% rename from src/ripple/README.md rename to src/xrpld/README.md diff --git a/src/ripple/app/consensus/RCLCensorshipDetector.h b/src/xrpld/app/consensus/RCLCensorshipDetector.h similarity index 100% rename from src/ripple/app/consensus/RCLCensorshipDetector.h rename to src/xrpld/app/consensus/RCLCensorshipDetector.h diff --git a/src/ripple/app/consensus/RCLConsensus.cpp b/src/xrpld/app/consensus/RCLConsensus.cpp similarity index 100% rename from src/ripple/app/consensus/RCLConsensus.cpp rename to src/xrpld/app/consensus/RCLConsensus.cpp diff --git a/src/ripple/app/consensus/RCLConsensus.h b/src/xrpld/app/consensus/RCLConsensus.h similarity index 100% rename from src/ripple/app/consensus/RCLConsensus.h rename to src/xrpld/app/consensus/RCLConsensus.h diff --git a/src/ripple/app/consensus/RCLCxLedger.h b/src/xrpld/app/consensus/RCLCxLedger.h similarity index 100% rename from src/ripple/app/consensus/RCLCxLedger.h rename to src/xrpld/app/consensus/RCLCxLedger.h diff --git a/src/ripple/app/consensus/RCLCxPeerPos.cpp b/src/xrpld/app/consensus/RCLCxPeerPos.cpp similarity index 100% rename from src/ripple/app/consensus/RCLCxPeerPos.cpp rename to src/xrpld/app/consensus/RCLCxPeerPos.cpp diff --git a/src/ripple/app/consensus/RCLCxPeerPos.h b/src/xrpld/app/consensus/RCLCxPeerPos.h similarity index 100% rename from src/ripple/app/consensus/RCLCxPeerPos.h rename to src/xrpld/app/consensus/RCLCxPeerPos.h diff --git a/src/ripple/app/consensus/RCLCxTx.h b/src/xrpld/app/consensus/RCLCxTx.h similarity index 100% rename from src/ripple/app/consensus/RCLCxTx.h rename to src/xrpld/app/consensus/RCLCxTx.h diff --git a/src/ripple/app/consensus/RCLValidations.cpp b/src/xrpld/app/consensus/RCLValidations.cpp similarity index 100% rename from src/ripple/app/consensus/RCLValidations.cpp rename to src/xrpld/app/consensus/RCLValidations.cpp diff --git a/src/ripple/app/consensus/RCLValidations.h b/src/xrpld/app/consensus/RCLValidations.h similarity index 100% rename from src/ripple/app/consensus/RCLValidations.h rename to src/xrpld/app/consensus/RCLValidations.h diff --git a/src/ripple/app/consensus/README.md b/src/xrpld/app/consensus/README.md similarity index 100% rename from src/ripple/app/consensus/README.md rename to src/xrpld/app/consensus/README.md diff --git a/src/ripple/app/ledger/AbstractFetchPackContainer.h b/src/xrpld/app/ledger/AbstractFetchPackContainer.h similarity index 100% rename from src/ripple/app/ledger/AbstractFetchPackContainer.h rename to src/xrpld/app/ledger/AbstractFetchPackContainer.h diff --git a/src/ripple/app/ledger/AcceptedLedger.cpp b/src/xrpld/app/ledger/AcceptedLedger.cpp similarity index 100% rename from src/ripple/app/ledger/AcceptedLedger.cpp rename to src/xrpld/app/ledger/AcceptedLedger.cpp diff --git a/src/ripple/app/ledger/AcceptedLedger.h b/src/xrpld/app/ledger/AcceptedLedger.h similarity index 100% rename from src/ripple/app/ledger/AcceptedLedger.h rename to src/xrpld/app/ledger/AcceptedLedger.h diff --git a/src/ripple/app/ledger/AcceptedLedgerTx.cpp b/src/xrpld/app/ledger/AcceptedLedgerTx.cpp similarity index 100% rename from src/ripple/app/ledger/AcceptedLedgerTx.cpp rename to src/xrpld/app/ledger/AcceptedLedgerTx.cpp diff --git a/src/ripple/app/ledger/AcceptedLedgerTx.h b/src/xrpld/app/ledger/AcceptedLedgerTx.h similarity index 100% rename from src/ripple/app/ledger/AcceptedLedgerTx.h rename to src/xrpld/app/ledger/AcceptedLedgerTx.h diff --git a/src/ripple/app/ledger/AccountStateSF.cpp b/src/xrpld/app/ledger/AccountStateSF.cpp similarity index 100% rename from src/ripple/app/ledger/AccountStateSF.cpp rename to src/xrpld/app/ledger/AccountStateSF.cpp diff --git a/src/ripple/app/ledger/AccountStateSF.h b/src/xrpld/app/ledger/AccountStateSF.h similarity index 100% rename from src/ripple/app/ledger/AccountStateSF.h rename to src/xrpld/app/ledger/AccountStateSF.h diff --git a/src/ripple/app/ledger/BookListeners.cpp b/src/xrpld/app/ledger/BookListeners.cpp similarity index 100% rename from src/ripple/app/ledger/BookListeners.cpp rename to src/xrpld/app/ledger/BookListeners.cpp diff --git a/src/ripple/app/ledger/BookListeners.h b/src/xrpld/app/ledger/BookListeners.h similarity index 100% rename from src/ripple/app/ledger/BookListeners.h rename to src/xrpld/app/ledger/BookListeners.h diff --git a/src/ripple/app/ledger/BuildLedger.h b/src/xrpld/app/ledger/BuildLedger.h similarity index 100% rename from src/ripple/app/ledger/BuildLedger.h rename to src/xrpld/app/ledger/BuildLedger.h diff --git a/src/ripple/app/ledger/ConsensusTransSetSF.cpp b/src/xrpld/app/ledger/ConsensusTransSetSF.cpp similarity index 100% rename from src/ripple/app/ledger/ConsensusTransSetSF.cpp rename to src/xrpld/app/ledger/ConsensusTransSetSF.cpp diff --git a/src/ripple/app/ledger/ConsensusTransSetSF.h b/src/xrpld/app/ledger/ConsensusTransSetSF.h similarity index 100% rename from src/ripple/app/ledger/ConsensusTransSetSF.h rename to src/xrpld/app/ledger/ConsensusTransSetSF.h diff --git a/src/ripple/app/ledger/InboundLedger.h b/src/xrpld/app/ledger/InboundLedger.h similarity index 100% rename from src/ripple/app/ledger/InboundLedger.h rename to src/xrpld/app/ledger/InboundLedger.h diff --git a/src/ripple/app/ledger/InboundLedgers.h b/src/xrpld/app/ledger/InboundLedgers.h similarity index 100% rename from src/ripple/app/ledger/InboundLedgers.h rename to src/xrpld/app/ledger/InboundLedgers.h diff --git a/src/ripple/app/ledger/InboundTransactions.h b/src/xrpld/app/ledger/InboundTransactions.h similarity index 100% rename from src/ripple/app/ledger/InboundTransactions.h rename to src/xrpld/app/ledger/InboundTransactions.h diff --git a/src/ripple/app/ledger/InboundTransactions.uml b/src/xrpld/app/ledger/InboundTransactions.uml similarity index 100% rename from src/ripple/app/ledger/InboundTransactions.uml rename to src/xrpld/app/ledger/InboundTransactions.uml diff --git a/src/ripple/app/ledger/Ledger.cpp b/src/xrpld/app/ledger/Ledger.cpp similarity index 100% rename from src/ripple/app/ledger/Ledger.cpp rename to src/xrpld/app/ledger/Ledger.cpp diff --git a/src/ripple/app/ledger/Ledger.h b/src/xrpld/app/ledger/Ledger.h similarity index 100% rename from src/ripple/app/ledger/Ledger.h rename to src/xrpld/app/ledger/Ledger.h diff --git a/src/ripple/app/ledger/LedgerCleaner.h b/src/xrpld/app/ledger/LedgerCleaner.h similarity index 100% rename from src/ripple/app/ledger/LedgerCleaner.h rename to src/xrpld/app/ledger/LedgerCleaner.h diff --git a/src/ripple/app/ledger/LedgerHistory.cpp b/src/xrpld/app/ledger/LedgerHistory.cpp similarity index 100% rename from src/ripple/app/ledger/LedgerHistory.cpp rename to src/xrpld/app/ledger/LedgerHistory.cpp diff --git a/src/ripple/app/ledger/LedgerHistory.h b/src/xrpld/app/ledger/LedgerHistory.h similarity index 100% rename from src/ripple/app/ledger/LedgerHistory.h rename to src/xrpld/app/ledger/LedgerHistory.h diff --git a/src/ripple/app/ledger/LedgerHolder.h b/src/xrpld/app/ledger/LedgerHolder.h similarity index 100% rename from src/ripple/app/ledger/LedgerHolder.h rename to src/xrpld/app/ledger/LedgerHolder.h diff --git a/src/ripple/app/ledger/LedgerMaster.h b/src/xrpld/app/ledger/LedgerMaster.h similarity index 100% rename from src/ripple/app/ledger/LedgerMaster.h rename to src/xrpld/app/ledger/LedgerMaster.h diff --git a/src/ripple/app/ledger/LedgerReplay.h b/src/xrpld/app/ledger/LedgerReplay.h similarity index 100% rename from src/ripple/app/ledger/LedgerReplay.h rename to src/xrpld/app/ledger/LedgerReplay.h diff --git a/src/ripple/app/ledger/LedgerReplayTask.h b/src/xrpld/app/ledger/LedgerReplayTask.h similarity index 100% rename from src/ripple/app/ledger/LedgerReplayTask.h rename to src/xrpld/app/ledger/LedgerReplayTask.h diff --git a/src/ripple/app/ledger/LedgerReplayer.h b/src/xrpld/app/ledger/LedgerReplayer.h similarity index 100% rename from src/ripple/app/ledger/LedgerReplayer.h rename to src/xrpld/app/ledger/LedgerReplayer.h diff --git a/src/ripple/app/ledger/LedgerToJson.h b/src/xrpld/app/ledger/LedgerToJson.h similarity index 100% rename from src/ripple/app/ledger/LedgerToJson.h rename to src/xrpld/app/ledger/LedgerToJson.h diff --git a/src/ripple/app/ledger/LocalTxs.h b/src/xrpld/app/ledger/LocalTxs.h similarity index 100% rename from src/ripple/app/ledger/LocalTxs.h rename to src/xrpld/app/ledger/LocalTxs.h diff --git a/src/ripple/app/ledger/OpenLedger.h b/src/xrpld/app/ledger/OpenLedger.h similarity index 100% rename from src/ripple/app/ledger/OpenLedger.h rename to src/xrpld/app/ledger/OpenLedger.h diff --git a/src/ripple/app/ledger/OrderBookDB.cpp b/src/xrpld/app/ledger/OrderBookDB.cpp similarity index 100% rename from src/ripple/app/ledger/OrderBookDB.cpp rename to src/xrpld/app/ledger/OrderBookDB.cpp diff --git a/src/ripple/app/ledger/OrderBookDB.h b/src/xrpld/app/ledger/OrderBookDB.h similarity index 100% rename from src/ripple/app/ledger/OrderBookDB.h rename to src/xrpld/app/ledger/OrderBookDB.h diff --git a/src/ripple/app/ledger/PendingSaves.h b/src/xrpld/app/ledger/PendingSaves.h similarity index 100% rename from src/ripple/app/ledger/PendingSaves.h rename to src/xrpld/app/ledger/PendingSaves.h diff --git a/src/ripple/app/ledger/README.md b/src/xrpld/app/ledger/README.md similarity index 100% rename from src/ripple/app/ledger/README.md rename to src/xrpld/app/ledger/README.md diff --git a/src/ripple/app/ledger/TransactionMaster.h b/src/xrpld/app/ledger/TransactionMaster.h similarity index 100% rename from src/ripple/app/ledger/TransactionMaster.h rename to src/xrpld/app/ledger/TransactionMaster.h diff --git a/src/ripple/app/ledger/TransactionStateSF.cpp b/src/xrpld/app/ledger/TransactionStateSF.cpp similarity index 100% rename from src/ripple/app/ledger/TransactionStateSF.cpp rename to src/xrpld/app/ledger/TransactionStateSF.cpp diff --git a/src/ripple/app/ledger/TransactionStateSF.h b/src/xrpld/app/ledger/TransactionStateSF.h similarity index 100% rename from src/ripple/app/ledger/TransactionStateSF.h rename to src/xrpld/app/ledger/TransactionStateSF.h diff --git a/src/ripple/app/ledger/impl/BuildLedger.cpp b/src/xrpld/app/ledger/detail/BuildLedger.cpp similarity index 100% rename from src/ripple/app/ledger/impl/BuildLedger.cpp rename to src/xrpld/app/ledger/detail/BuildLedger.cpp diff --git a/src/ripple/app/ledger/impl/InboundLedger.cpp b/src/xrpld/app/ledger/detail/InboundLedger.cpp similarity index 100% rename from src/ripple/app/ledger/impl/InboundLedger.cpp rename to src/xrpld/app/ledger/detail/InboundLedger.cpp diff --git a/src/ripple/app/ledger/impl/InboundLedgers.cpp b/src/xrpld/app/ledger/detail/InboundLedgers.cpp similarity index 100% rename from src/ripple/app/ledger/impl/InboundLedgers.cpp rename to src/xrpld/app/ledger/detail/InboundLedgers.cpp diff --git a/src/ripple/app/ledger/impl/InboundTransactions.cpp b/src/xrpld/app/ledger/detail/InboundTransactions.cpp similarity index 100% rename from src/ripple/app/ledger/impl/InboundTransactions.cpp rename to src/xrpld/app/ledger/detail/InboundTransactions.cpp diff --git a/src/ripple/app/ledger/impl/LedgerCleaner.cpp b/src/xrpld/app/ledger/detail/LedgerCleaner.cpp similarity index 100% rename from src/ripple/app/ledger/impl/LedgerCleaner.cpp rename to src/xrpld/app/ledger/detail/LedgerCleaner.cpp diff --git a/src/ripple/app/ledger/impl/LedgerDeltaAcquire.cpp b/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp similarity index 100% rename from src/ripple/app/ledger/impl/LedgerDeltaAcquire.cpp rename to src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp diff --git a/src/ripple/app/ledger/impl/LedgerDeltaAcquire.h b/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.h similarity index 100% rename from src/ripple/app/ledger/impl/LedgerDeltaAcquire.h rename to src/xrpld/app/ledger/detail/LedgerDeltaAcquire.h diff --git a/src/ripple/app/ledger/impl/LedgerMaster.cpp b/src/xrpld/app/ledger/detail/LedgerMaster.cpp similarity index 100% rename from src/ripple/app/ledger/impl/LedgerMaster.cpp rename to src/xrpld/app/ledger/detail/LedgerMaster.cpp diff --git a/src/ripple/app/ledger/impl/LedgerReplay.cpp b/src/xrpld/app/ledger/detail/LedgerReplay.cpp similarity index 100% rename from src/ripple/app/ledger/impl/LedgerReplay.cpp rename to src/xrpld/app/ledger/detail/LedgerReplay.cpp diff --git a/src/ripple/app/ledger/impl/LedgerReplayMsgHandler.cpp b/src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.cpp similarity index 100% rename from src/ripple/app/ledger/impl/LedgerReplayMsgHandler.cpp rename to src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.cpp diff --git a/src/ripple/app/ledger/impl/LedgerReplayMsgHandler.h b/src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.h similarity index 100% rename from src/ripple/app/ledger/impl/LedgerReplayMsgHandler.h rename to src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.h diff --git a/src/ripple/app/ledger/impl/LedgerReplayTask.cpp b/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp similarity index 100% rename from src/ripple/app/ledger/impl/LedgerReplayTask.cpp rename to src/xrpld/app/ledger/detail/LedgerReplayTask.cpp diff --git a/src/ripple/app/ledger/impl/LedgerReplayer.cpp b/src/xrpld/app/ledger/detail/LedgerReplayer.cpp similarity index 100% rename from src/ripple/app/ledger/impl/LedgerReplayer.cpp rename to src/xrpld/app/ledger/detail/LedgerReplayer.cpp diff --git a/src/ripple/app/ledger/impl/LedgerToJson.cpp b/src/xrpld/app/ledger/detail/LedgerToJson.cpp similarity index 100% rename from src/ripple/app/ledger/impl/LedgerToJson.cpp rename to src/xrpld/app/ledger/detail/LedgerToJson.cpp diff --git a/src/ripple/app/ledger/impl/LocalTxs.cpp b/src/xrpld/app/ledger/detail/LocalTxs.cpp similarity index 100% rename from src/ripple/app/ledger/impl/LocalTxs.cpp rename to src/xrpld/app/ledger/detail/LocalTxs.cpp diff --git a/src/ripple/app/ledger/impl/OpenLedger.cpp b/src/xrpld/app/ledger/detail/OpenLedger.cpp similarity index 100% rename from src/ripple/app/ledger/impl/OpenLedger.cpp rename to src/xrpld/app/ledger/detail/OpenLedger.cpp diff --git a/src/ripple/app/ledger/impl/SkipListAcquire.cpp b/src/xrpld/app/ledger/detail/SkipListAcquire.cpp similarity index 100% rename from src/ripple/app/ledger/impl/SkipListAcquire.cpp rename to src/xrpld/app/ledger/detail/SkipListAcquire.cpp diff --git a/src/ripple/app/ledger/impl/SkipListAcquire.h b/src/xrpld/app/ledger/detail/SkipListAcquire.h similarity index 100% rename from src/ripple/app/ledger/impl/SkipListAcquire.h rename to src/xrpld/app/ledger/detail/SkipListAcquire.h diff --git a/src/ripple/app/ledger/impl/TimeoutCounter.cpp b/src/xrpld/app/ledger/detail/TimeoutCounter.cpp similarity index 100% rename from src/ripple/app/ledger/impl/TimeoutCounter.cpp rename to src/xrpld/app/ledger/detail/TimeoutCounter.cpp diff --git a/src/ripple/app/ledger/impl/TimeoutCounter.h b/src/xrpld/app/ledger/detail/TimeoutCounter.h similarity index 100% rename from src/ripple/app/ledger/impl/TimeoutCounter.h rename to src/xrpld/app/ledger/detail/TimeoutCounter.h diff --git a/src/ripple/app/ledger/impl/TransactionAcquire.cpp b/src/xrpld/app/ledger/detail/TransactionAcquire.cpp similarity index 100% rename from src/ripple/app/ledger/impl/TransactionAcquire.cpp rename to src/xrpld/app/ledger/detail/TransactionAcquire.cpp diff --git a/src/ripple/app/ledger/impl/TransactionAcquire.h b/src/xrpld/app/ledger/detail/TransactionAcquire.h similarity index 100% rename from src/ripple/app/ledger/impl/TransactionAcquire.h rename to src/xrpld/app/ledger/detail/TransactionAcquire.h diff --git a/src/ripple/app/ledger/impl/TransactionMaster.cpp b/src/xrpld/app/ledger/detail/TransactionMaster.cpp similarity index 100% rename from src/ripple/app/ledger/impl/TransactionMaster.cpp rename to src/xrpld/app/ledger/detail/TransactionMaster.cpp diff --git a/src/ripple/app/main/Application.cpp b/src/xrpld/app/main/Application.cpp similarity index 100% rename from src/ripple/app/main/Application.cpp rename to src/xrpld/app/main/Application.cpp diff --git a/src/ripple/app/main/Application.h b/src/xrpld/app/main/Application.h similarity index 100% rename from src/ripple/app/main/Application.h rename to src/xrpld/app/main/Application.h diff --git a/src/ripple/app/main/BasicApp.cpp b/src/xrpld/app/main/BasicApp.cpp similarity index 100% rename from src/ripple/app/main/BasicApp.cpp rename to src/xrpld/app/main/BasicApp.cpp diff --git a/src/ripple/app/main/BasicApp.h b/src/xrpld/app/main/BasicApp.h similarity index 100% rename from src/ripple/app/main/BasicApp.h rename to src/xrpld/app/main/BasicApp.h diff --git a/src/ripple/app/main/CollectorManager.cpp b/src/xrpld/app/main/CollectorManager.cpp similarity index 100% rename from src/ripple/app/main/CollectorManager.cpp rename to src/xrpld/app/main/CollectorManager.cpp diff --git a/src/ripple/app/main/CollectorManager.h b/src/xrpld/app/main/CollectorManager.h similarity index 100% rename from src/ripple/app/main/CollectorManager.h rename to src/xrpld/app/main/CollectorManager.h diff --git a/src/ripple/app/main/DBInit.h b/src/xrpld/app/main/DBInit.h similarity index 100% rename from src/ripple/app/main/DBInit.h rename to src/xrpld/app/main/DBInit.h diff --git a/src/ripple/app/main/GRPCServer.cpp b/src/xrpld/app/main/GRPCServer.cpp similarity index 100% rename from src/ripple/app/main/GRPCServer.cpp rename to src/xrpld/app/main/GRPCServer.cpp diff --git a/src/ripple/app/main/GRPCServer.h b/src/xrpld/app/main/GRPCServer.h similarity index 100% rename from src/ripple/app/main/GRPCServer.h rename to src/xrpld/app/main/GRPCServer.h diff --git a/src/ripple/app/main/LoadManager.cpp b/src/xrpld/app/main/LoadManager.cpp similarity index 100% rename from src/ripple/app/main/LoadManager.cpp rename to src/xrpld/app/main/LoadManager.cpp diff --git a/src/ripple/app/main/LoadManager.h b/src/xrpld/app/main/LoadManager.h similarity index 100% rename from src/ripple/app/main/LoadManager.h rename to src/xrpld/app/main/LoadManager.h diff --git a/src/ripple/app/main/Main.cpp b/src/xrpld/app/main/Main.cpp similarity index 100% rename from src/ripple/app/main/Main.cpp rename to src/xrpld/app/main/Main.cpp diff --git a/src/ripple/app/main/NodeIdentity.cpp b/src/xrpld/app/main/NodeIdentity.cpp similarity index 100% rename from src/ripple/app/main/NodeIdentity.cpp rename to src/xrpld/app/main/NodeIdentity.cpp diff --git a/src/ripple/app/main/NodeIdentity.h b/src/xrpld/app/main/NodeIdentity.h similarity index 100% rename from src/ripple/app/main/NodeIdentity.h rename to src/xrpld/app/main/NodeIdentity.h diff --git a/src/ripple/app/main/NodeStoreScheduler.cpp b/src/xrpld/app/main/NodeStoreScheduler.cpp similarity index 100% rename from src/ripple/app/main/NodeStoreScheduler.cpp rename to src/xrpld/app/main/NodeStoreScheduler.cpp diff --git a/src/ripple/app/main/NodeStoreScheduler.h b/src/xrpld/app/main/NodeStoreScheduler.h similarity index 100% rename from src/ripple/app/main/NodeStoreScheduler.h rename to src/xrpld/app/main/NodeStoreScheduler.h diff --git a/src/ripple/app/main/Tuning.h b/src/xrpld/app/main/Tuning.h similarity index 100% rename from src/ripple/app/main/Tuning.h rename to src/xrpld/app/main/Tuning.h diff --git a/src/ripple/app/misc/AMMHelpers.h b/src/xrpld/app/misc/AMMHelpers.h similarity index 100% rename from src/ripple/app/misc/AMMHelpers.h rename to src/xrpld/app/misc/AMMHelpers.h diff --git a/src/ripple/app/misc/AMMUtils.h b/src/xrpld/app/misc/AMMUtils.h similarity index 100% rename from src/ripple/app/misc/AMMUtils.h rename to src/xrpld/app/misc/AMMUtils.h diff --git a/src/ripple/app/misc/AmendmentTable.h b/src/xrpld/app/misc/AmendmentTable.h similarity index 100% rename from src/ripple/app/misc/AmendmentTable.h rename to src/xrpld/app/misc/AmendmentTable.h diff --git a/src/ripple/app/misc/CanonicalTXSet.cpp b/src/xrpld/app/misc/CanonicalTXSet.cpp similarity index 100% rename from src/ripple/app/misc/CanonicalTXSet.cpp rename to src/xrpld/app/misc/CanonicalTXSet.cpp diff --git a/src/ripple/app/misc/CanonicalTXSet.h b/src/xrpld/app/misc/CanonicalTXSet.h similarity index 100% rename from src/ripple/app/misc/CanonicalTXSet.h rename to src/xrpld/app/misc/CanonicalTXSet.h diff --git a/src/ripple/app/misc/DeliverMax.h b/src/xrpld/app/misc/DeliverMax.h similarity index 100% rename from src/ripple/app/misc/DeliverMax.h rename to src/xrpld/app/misc/DeliverMax.h diff --git a/src/ripple/app/misc/FeeEscalation.md b/src/xrpld/app/misc/FeeEscalation.md similarity index 100% rename from src/ripple/app/misc/FeeEscalation.md rename to src/xrpld/app/misc/FeeEscalation.md diff --git a/src/ripple/app/misc/FeeVote.h b/src/xrpld/app/misc/FeeVote.h similarity index 100% rename from src/ripple/app/misc/FeeVote.h rename to src/xrpld/app/misc/FeeVote.h diff --git a/src/ripple/app/misc/FeeVoteImpl.cpp b/src/xrpld/app/misc/FeeVoteImpl.cpp similarity index 100% rename from src/ripple/app/misc/FeeVoteImpl.cpp rename to src/xrpld/app/misc/FeeVoteImpl.cpp diff --git a/src/ripple/app/misc/HashRouter.cpp b/src/xrpld/app/misc/HashRouter.cpp similarity index 100% rename from src/ripple/app/misc/HashRouter.cpp rename to src/xrpld/app/misc/HashRouter.cpp diff --git a/src/ripple/app/misc/HashRouter.h b/src/xrpld/app/misc/HashRouter.h similarity index 100% rename from src/ripple/app/misc/HashRouter.h rename to src/xrpld/app/misc/HashRouter.h diff --git a/src/ripple/app/misc/LoadFeeTrack.h b/src/xrpld/app/misc/LoadFeeTrack.h similarity index 100% rename from src/ripple/app/misc/LoadFeeTrack.h rename to src/xrpld/app/misc/LoadFeeTrack.h diff --git a/src/ripple/app/misc/Manifest.h b/src/xrpld/app/misc/Manifest.h similarity index 100% rename from src/ripple/app/misc/Manifest.h rename to src/xrpld/app/misc/Manifest.h diff --git a/src/ripple/app/misc/NegativeUNLVote.cpp b/src/xrpld/app/misc/NegativeUNLVote.cpp similarity index 100% rename from src/ripple/app/misc/NegativeUNLVote.cpp rename to src/xrpld/app/misc/NegativeUNLVote.cpp diff --git a/src/ripple/app/misc/NegativeUNLVote.h b/src/xrpld/app/misc/NegativeUNLVote.h similarity index 100% rename from src/ripple/app/misc/NegativeUNLVote.h rename to src/xrpld/app/misc/NegativeUNLVote.h diff --git a/src/ripple/app/misc/NetworkOPs.cpp b/src/xrpld/app/misc/NetworkOPs.cpp similarity index 100% rename from src/ripple/app/misc/NetworkOPs.cpp rename to src/xrpld/app/misc/NetworkOPs.cpp diff --git a/src/ripple/app/misc/NetworkOPs.h b/src/xrpld/app/misc/NetworkOPs.h similarity index 100% rename from src/ripple/app/misc/NetworkOPs.h rename to src/xrpld/app/misc/NetworkOPs.h diff --git a/src/ripple/app/misc/README.md b/src/xrpld/app/misc/README.md similarity index 100% rename from src/ripple/app/misc/README.md rename to src/xrpld/app/misc/README.md diff --git a/src/ripple/app/misc/SHAMapStore.h b/src/xrpld/app/misc/SHAMapStore.h similarity index 100% rename from src/ripple/app/misc/SHAMapStore.h rename to src/xrpld/app/misc/SHAMapStore.h diff --git a/src/ripple/app/misc/SHAMapStoreImp.cpp b/src/xrpld/app/misc/SHAMapStoreImp.cpp similarity index 100% rename from src/ripple/app/misc/SHAMapStoreImp.cpp rename to src/xrpld/app/misc/SHAMapStoreImp.cpp diff --git a/src/ripple/app/misc/SHAMapStoreImp.h b/src/xrpld/app/misc/SHAMapStoreImp.h similarity index 100% rename from src/ripple/app/misc/SHAMapStoreImp.h rename to src/xrpld/app/misc/SHAMapStoreImp.h diff --git a/src/ripple/app/misc/Transaction.h b/src/xrpld/app/misc/Transaction.h similarity index 100% rename from src/ripple/app/misc/Transaction.h rename to src/xrpld/app/misc/Transaction.h diff --git a/src/ripple/app/misc/TxQ.h b/src/xrpld/app/misc/TxQ.h similarity index 100% rename from src/ripple/app/misc/TxQ.h rename to src/xrpld/app/misc/TxQ.h diff --git a/src/ripple/app/misc/ValidatorKeys.h b/src/xrpld/app/misc/ValidatorKeys.h similarity index 100% rename from src/ripple/app/misc/ValidatorKeys.h rename to src/xrpld/app/misc/ValidatorKeys.h diff --git a/src/ripple/app/misc/ValidatorList.h b/src/xrpld/app/misc/ValidatorList.h similarity index 100% rename from src/ripple/app/misc/ValidatorList.h rename to src/xrpld/app/misc/ValidatorList.h diff --git a/src/ripple/app/misc/ValidatorSite.h b/src/xrpld/app/misc/ValidatorSite.h similarity index 100% rename from src/ripple/app/misc/ValidatorSite.h rename to src/xrpld/app/misc/ValidatorSite.h diff --git a/src/ripple/app/misc/impl/AMMHelpers.cpp b/src/xrpld/app/misc/detail/AMMHelpers.cpp similarity index 100% rename from src/ripple/app/misc/impl/AMMHelpers.cpp rename to src/xrpld/app/misc/detail/AMMHelpers.cpp diff --git a/src/ripple/app/misc/impl/AMMUtils.cpp b/src/xrpld/app/misc/detail/AMMUtils.cpp similarity index 100% rename from src/ripple/app/misc/impl/AMMUtils.cpp rename to src/xrpld/app/misc/detail/AMMUtils.cpp diff --git a/src/ripple/app/misc/impl/AccountTxPaging.cpp b/src/xrpld/app/misc/detail/AccountTxPaging.cpp similarity index 100% rename from src/ripple/app/misc/impl/AccountTxPaging.cpp rename to src/xrpld/app/misc/detail/AccountTxPaging.cpp diff --git a/src/ripple/app/misc/impl/AccountTxPaging.h b/src/xrpld/app/misc/detail/AccountTxPaging.h similarity index 100% rename from src/ripple/app/misc/impl/AccountTxPaging.h rename to src/xrpld/app/misc/detail/AccountTxPaging.h diff --git a/src/ripple/app/misc/impl/AmendmentTable.cpp b/src/xrpld/app/misc/detail/AmendmentTable.cpp similarity index 100% rename from src/ripple/app/misc/impl/AmendmentTable.cpp rename to src/xrpld/app/misc/detail/AmendmentTable.cpp diff --git a/src/ripple/app/misc/impl/DeliverMax.cpp b/src/xrpld/app/misc/detail/DeliverMax.cpp similarity index 100% rename from src/ripple/app/misc/impl/DeliverMax.cpp rename to src/xrpld/app/misc/detail/DeliverMax.cpp diff --git a/src/ripple/app/misc/impl/LoadFeeTrack.cpp b/src/xrpld/app/misc/detail/LoadFeeTrack.cpp similarity index 100% rename from src/ripple/app/misc/impl/LoadFeeTrack.cpp rename to src/xrpld/app/misc/detail/LoadFeeTrack.cpp diff --git a/src/ripple/app/misc/impl/Manifest.cpp b/src/xrpld/app/misc/detail/Manifest.cpp similarity index 100% rename from src/ripple/app/misc/impl/Manifest.cpp rename to src/xrpld/app/misc/detail/Manifest.cpp diff --git a/src/ripple/app/misc/impl/Transaction.cpp b/src/xrpld/app/misc/detail/Transaction.cpp similarity index 100% rename from src/ripple/app/misc/impl/Transaction.cpp rename to src/xrpld/app/misc/detail/Transaction.cpp diff --git a/src/ripple/app/misc/impl/TxQ.cpp b/src/xrpld/app/misc/detail/TxQ.cpp similarity index 100% rename from src/ripple/app/misc/impl/TxQ.cpp rename to src/xrpld/app/misc/detail/TxQ.cpp diff --git a/src/ripple/app/misc/impl/ValidatorKeys.cpp b/src/xrpld/app/misc/detail/ValidatorKeys.cpp similarity index 100% rename from src/ripple/app/misc/impl/ValidatorKeys.cpp rename to src/xrpld/app/misc/detail/ValidatorKeys.cpp diff --git a/src/ripple/app/misc/impl/ValidatorList.cpp b/src/xrpld/app/misc/detail/ValidatorList.cpp similarity index 100% rename from src/ripple/app/misc/impl/ValidatorList.cpp rename to src/xrpld/app/misc/detail/ValidatorList.cpp diff --git a/src/ripple/app/misc/impl/ValidatorSite.cpp b/src/xrpld/app/misc/detail/ValidatorSite.cpp similarity index 100% rename from src/ripple/app/misc/impl/ValidatorSite.cpp rename to src/xrpld/app/misc/detail/ValidatorSite.cpp diff --git a/src/ripple/app/misc/detail/Work.h b/src/xrpld/app/misc/detail/Work.h similarity index 100% rename from src/ripple/app/misc/detail/Work.h rename to src/xrpld/app/misc/detail/Work.h diff --git a/src/ripple/app/misc/detail/WorkBase.h b/src/xrpld/app/misc/detail/WorkBase.h similarity index 100% rename from src/ripple/app/misc/detail/WorkBase.h rename to src/xrpld/app/misc/detail/WorkBase.h diff --git a/src/ripple/app/misc/detail/WorkFile.h b/src/xrpld/app/misc/detail/WorkFile.h similarity index 100% rename from src/ripple/app/misc/detail/WorkFile.h rename to src/xrpld/app/misc/detail/WorkFile.h diff --git a/src/ripple/app/misc/detail/WorkPlain.h b/src/xrpld/app/misc/detail/WorkPlain.h similarity index 100% rename from src/ripple/app/misc/detail/WorkPlain.h rename to src/xrpld/app/misc/detail/WorkPlain.h diff --git a/src/ripple/app/misc/detail/WorkSSL.h b/src/xrpld/app/misc/detail/WorkSSL.h similarity index 100% rename from src/ripple/app/misc/detail/WorkSSL.h rename to src/xrpld/app/misc/detail/WorkSSL.h diff --git a/src/ripple/app/misc/detail/impl/WorkSSL.cpp b/src/xrpld/app/misc/detail/detail/WorkSSL.cpp similarity index 100% rename from src/ripple/app/misc/detail/impl/WorkSSL.cpp rename to src/xrpld/app/misc/detail/detail/WorkSSL.cpp diff --git a/src/ripple/app/paths/AMMContext.h b/src/xrpld/app/paths/AMMContext.h similarity index 100% rename from src/ripple/app/paths/AMMContext.h rename to src/xrpld/app/paths/AMMContext.h diff --git a/src/ripple/app/paths/AMMLiquidity.h b/src/xrpld/app/paths/AMMLiquidity.h similarity index 100% rename from src/ripple/app/paths/AMMLiquidity.h rename to src/xrpld/app/paths/AMMLiquidity.h diff --git a/src/ripple/app/paths/AMMOffer.h b/src/xrpld/app/paths/AMMOffer.h similarity index 100% rename from src/ripple/app/paths/AMMOffer.h rename to src/xrpld/app/paths/AMMOffer.h diff --git a/src/ripple/app/paths/AccountCurrencies.cpp b/src/xrpld/app/paths/AccountCurrencies.cpp similarity index 100% rename from src/ripple/app/paths/AccountCurrencies.cpp rename to src/xrpld/app/paths/AccountCurrencies.cpp diff --git a/src/ripple/app/paths/AccountCurrencies.h b/src/xrpld/app/paths/AccountCurrencies.h similarity index 100% rename from src/ripple/app/paths/AccountCurrencies.h rename to src/xrpld/app/paths/AccountCurrencies.h diff --git a/src/ripple/app/paths/Credit.cpp b/src/xrpld/app/paths/Credit.cpp similarity index 100% rename from src/ripple/app/paths/Credit.cpp rename to src/xrpld/app/paths/Credit.cpp diff --git a/src/ripple/app/paths/Credit.h b/src/xrpld/app/paths/Credit.h similarity index 100% rename from src/ripple/app/paths/Credit.h rename to src/xrpld/app/paths/Credit.h diff --git a/src/ripple/app/paths/Flow.cpp b/src/xrpld/app/paths/Flow.cpp similarity index 100% rename from src/ripple/app/paths/Flow.cpp rename to src/xrpld/app/paths/Flow.cpp diff --git a/src/ripple/app/paths/Flow.h b/src/xrpld/app/paths/Flow.h similarity index 100% rename from src/ripple/app/paths/Flow.h rename to src/xrpld/app/paths/Flow.h diff --git a/src/ripple/app/paths/PathRequest.cpp b/src/xrpld/app/paths/PathRequest.cpp similarity index 100% rename from src/ripple/app/paths/PathRequest.cpp rename to src/xrpld/app/paths/PathRequest.cpp diff --git a/src/ripple/app/paths/PathRequest.h b/src/xrpld/app/paths/PathRequest.h similarity index 100% rename from src/ripple/app/paths/PathRequest.h rename to src/xrpld/app/paths/PathRequest.h diff --git a/src/ripple/app/paths/PathRequests.cpp b/src/xrpld/app/paths/PathRequests.cpp similarity index 100% rename from src/ripple/app/paths/PathRequests.cpp rename to src/xrpld/app/paths/PathRequests.cpp diff --git a/src/ripple/app/paths/PathRequests.h b/src/xrpld/app/paths/PathRequests.h similarity index 100% rename from src/ripple/app/paths/PathRequests.h rename to src/xrpld/app/paths/PathRequests.h diff --git a/src/ripple/app/paths/Pathfinder.cpp b/src/xrpld/app/paths/Pathfinder.cpp similarity index 100% rename from src/ripple/app/paths/Pathfinder.cpp rename to src/xrpld/app/paths/Pathfinder.cpp diff --git a/src/ripple/app/paths/Pathfinder.h b/src/xrpld/app/paths/Pathfinder.h similarity index 100% rename from src/ripple/app/paths/Pathfinder.h rename to src/xrpld/app/paths/Pathfinder.h diff --git a/src/ripple/app/paths/RippleCalc.cpp b/src/xrpld/app/paths/RippleCalc.cpp similarity index 100% rename from src/ripple/app/paths/RippleCalc.cpp rename to src/xrpld/app/paths/RippleCalc.cpp diff --git a/src/ripple/app/paths/RippleCalc.h b/src/xrpld/app/paths/RippleCalc.h similarity index 100% rename from src/ripple/app/paths/RippleCalc.h rename to src/xrpld/app/paths/RippleCalc.h diff --git a/src/ripple/app/paths/RippleLineCache.cpp b/src/xrpld/app/paths/RippleLineCache.cpp similarity index 100% rename from src/ripple/app/paths/RippleLineCache.cpp rename to src/xrpld/app/paths/RippleLineCache.cpp diff --git a/src/ripple/app/paths/RippleLineCache.h b/src/xrpld/app/paths/RippleLineCache.h similarity index 100% rename from src/ripple/app/paths/RippleLineCache.h rename to src/xrpld/app/paths/RippleLineCache.h diff --git a/src/ripple/app/paths/TrustLine.cpp b/src/xrpld/app/paths/TrustLine.cpp similarity index 100% rename from src/ripple/app/paths/TrustLine.cpp rename to src/xrpld/app/paths/TrustLine.cpp diff --git a/src/ripple/app/paths/TrustLine.h b/src/xrpld/app/paths/TrustLine.h similarity index 100% rename from src/ripple/app/paths/TrustLine.h rename to src/xrpld/app/paths/TrustLine.h diff --git a/src/ripple/app/paths/impl/AMMLiquidity.cpp b/src/xrpld/app/paths/detail/AMMLiquidity.cpp similarity index 100% rename from src/ripple/app/paths/impl/AMMLiquidity.cpp rename to src/xrpld/app/paths/detail/AMMLiquidity.cpp diff --git a/src/ripple/app/paths/impl/AMMOffer.cpp b/src/xrpld/app/paths/detail/AMMOffer.cpp similarity index 100% rename from src/ripple/app/paths/impl/AMMOffer.cpp rename to src/xrpld/app/paths/detail/AMMOffer.cpp diff --git a/src/ripple/app/paths/impl/AmountSpec.h b/src/xrpld/app/paths/detail/AmountSpec.h similarity index 100% rename from src/ripple/app/paths/impl/AmountSpec.h rename to src/xrpld/app/paths/detail/AmountSpec.h diff --git a/src/ripple/app/paths/impl/BookStep.cpp b/src/xrpld/app/paths/detail/BookStep.cpp similarity index 100% rename from src/ripple/app/paths/impl/BookStep.cpp rename to src/xrpld/app/paths/detail/BookStep.cpp diff --git a/src/ripple/app/paths/impl/DirectStep.cpp b/src/xrpld/app/paths/detail/DirectStep.cpp similarity index 100% rename from src/ripple/app/paths/impl/DirectStep.cpp rename to src/xrpld/app/paths/detail/DirectStep.cpp diff --git a/src/ripple/app/paths/impl/FlatSets.h b/src/xrpld/app/paths/detail/FlatSets.h similarity index 100% rename from src/ripple/app/paths/impl/FlatSets.h rename to src/xrpld/app/paths/detail/FlatSets.h diff --git a/src/ripple/app/paths/impl/FlowDebugInfo.h b/src/xrpld/app/paths/detail/FlowDebugInfo.h similarity index 100% rename from src/ripple/app/paths/impl/FlowDebugInfo.h rename to src/xrpld/app/paths/detail/FlowDebugInfo.h diff --git a/src/ripple/app/paths/impl/PathfinderUtils.h b/src/xrpld/app/paths/detail/PathfinderUtils.h similarity index 100% rename from src/ripple/app/paths/impl/PathfinderUtils.h rename to src/xrpld/app/paths/detail/PathfinderUtils.h diff --git a/src/ripple/app/paths/impl/PaySteps.cpp b/src/xrpld/app/paths/detail/PaySteps.cpp similarity index 100% rename from src/ripple/app/paths/impl/PaySteps.cpp rename to src/xrpld/app/paths/detail/PaySteps.cpp diff --git a/src/ripple/app/paths/impl/StepChecks.h b/src/xrpld/app/paths/detail/StepChecks.h similarity index 100% rename from src/ripple/app/paths/impl/StepChecks.h rename to src/xrpld/app/paths/detail/StepChecks.h diff --git a/src/ripple/app/paths/impl/Steps.h b/src/xrpld/app/paths/detail/Steps.h similarity index 100% rename from src/ripple/app/paths/impl/Steps.h rename to src/xrpld/app/paths/detail/Steps.h diff --git a/src/ripple/app/paths/impl/StrandFlow.h b/src/xrpld/app/paths/detail/StrandFlow.h similarity index 100% rename from src/ripple/app/paths/impl/StrandFlow.h rename to src/xrpld/app/paths/detail/StrandFlow.h diff --git a/src/ripple/app/paths/impl/XRPEndpointStep.cpp b/src/xrpld/app/paths/detail/XRPEndpointStep.cpp similarity index 100% rename from src/ripple/app/paths/impl/XRPEndpointStep.cpp rename to src/xrpld/app/paths/detail/XRPEndpointStep.cpp diff --git a/src/ripple/app/rdb/Download.h b/src/xrpld/app/rdb/Download.h similarity index 100% rename from src/ripple/app/rdb/Download.h rename to src/xrpld/app/rdb/Download.h diff --git a/src/ripple/app/rdb/PeerFinder.h b/src/xrpld/app/rdb/PeerFinder.h similarity index 100% rename from src/ripple/app/rdb/PeerFinder.h rename to src/xrpld/app/rdb/PeerFinder.h diff --git a/src/ripple/app/rdb/README.md b/src/xrpld/app/rdb/README.md similarity index 100% rename from src/ripple/app/rdb/README.md rename to src/xrpld/app/rdb/README.md diff --git a/src/ripple/app/rdb/RelationalDatabase.h b/src/xrpld/app/rdb/RelationalDatabase.h similarity index 100% rename from src/ripple/app/rdb/RelationalDatabase.h rename to src/xrpld/app/rdb/RelationalDatabase.h diff --git a/src/ripple/app/rdb/ShardArchive.h b/src/xrpld/app/rdb/ShardArchive.h similarity index 100% rename from src/ripple/app/rdb/ShardArchive.h rename to src/xrpld/app/rdb/ShardArchive.h diff --git a/src/ripple/app/rdb/State.h b/src/xrpld/app/rdb/State.h similarity index 100% rename from src/ripple/app/rdb/State.h rename to src/xrpld/app/rdb/State.h diff --git a/src/ripple/app/rdb/UnitaryShard.h b/src/xrpld/app/rdb/UnitaryShard.h similarity index 100% rename from src/ripple/app/rdb/UnitaryShard.h rename to src/xrpld/app/rdb/UnitaryShard.h diff --git a/src/ripple/app/rdb/Vacuum.h b/src/xrpld/app/rdb/Vacuum.h similarity index 100% rename from src/ripple/app/rdb/Vacuum.h rename to src/xrpld/app/rdb/Vacuum.h diff --git a/src/ripple/app/rdb/Wallet.h b/src/xrpld/app/rdb/Wallet.h similarity index 100% rename from src/ripple/app/rdb/Wallet.h rename to src/xrpld/app/rdb/Wallet.h diff --git a/src/ripple/app/rdb/backend/PostgresDatabase.h b/src/xrpld/app/rdb/backend/PostgresDatabase.h similarity index 100% rename from src/ripple/app/rdb/backend/PostgresDatabase.h rename to src/xrpld/app/rdb/backend/PostgresDatabase.h diff --git a/src/ripple/app/rdb/backend/SQLiteDatabase.h b/src/xrpld/app/rdb/backend/SQLiteDatabase.h similarity index 100% rename from src/ripple/app/rdb/backend/SQLiteDatabase.h rename to src/xrpld/app/rdb/backend/SQLiteDatabase.h diff --git a/src/ripple/app/rdb/backend/detail/Node.h b/src/xrpld/app/rdb/backend/detail/Node.h similarity index 100% rename from src/ripple/app/rdb/backend/detail/Node.h rename to src/xrpld/app/rdb/backend/detail/Node.h diff --git a/src/ripple/app/rdb/backend/impl/PostgresDatabase.cpp b/src/xrpld/app/rdb/backend/detail/PostgresDatabase.cpp similarity index 100% rename from src/ripple/app/rdb/backend/impl/PostgresDatabase.cpp rename to src/xrpld/app/rdb/backend/detail/PostgresDatabase.cpp diff --git a/src/ripple/app/rdb/backend/impl/SQLiteDatabase.cpp b/src/xrpld/app/rdb/backend/detail/SQLiteDatabase.cpp similarity index 100% rename from src/ripple/app/rdb/backend/impl/SQLiteDatabase.cpp rename to src/xrpld/app/rdb/backend/detail/SQLiteDatabase.cpp diff --git a/src/ripple/app/rdb/backend/detail/Shard.h b/src/xrpld/app/rdb/backend/detail/Shard.h similarity index 100% rename from src/ripple/app/rdb/backend/detail/Shard.h rename to src/xrpld/app/rdb/backend/detail/Shard.h diff --git a/src/ripple/app/rdb/backend/detail/impl/Node.cpp b/src/xrpld/app/rdb/backend/detail/detail/Node.cpp similarity index 100% rename from src/ripple/app/rdb/backend/detail/impl/Node.cpp rename to src/xrpld/app/rdb/backend/detail/detail/Node.cpp diff --git a/src/ripple/app/rdb/backend/detail/impl/Shard.cpp b/src/xrpld/app/rdb/backend/detail/detail/Shard.cpp similarity index 100% rename from src/ripple/app/rdb/backend/detail/impl/Shard.cpp rename to src/xrpld/app/rdb/backend/detail/detail/Shard.cpp diff --git a/src/ripple/app/rdb/impl/Download.cpp b/src/xrpld/app/rdb/detail/Download.cpp similarity index 100% rename from src/ripple/app/rdb/impl/Download.cpp rename to src/xrpld/app/rdb/detail/Download.cpp diff --git a/src/ripple/app/rdb/impl/PeerFinder.cpp b/src/xrpld/app/rdb/detail/PeerFinder.cpp similarity index 100% rename from src/ripple/app/rdb/impl/PeerFinder.cpp rename to src/xrpld/app/rdb/detail/PeerFinder.cpp diff --git a/src/ripple/app/rdb/impl/RelationalDatabase.cpp b/src/xrpld/app/rdb/detail/RelationalDatabase.cpp similarity index 100% rename from src/ripple/app/rdb/impl/RelationalDatabase.cpp rename to src/xrpld/app/rdb/detail/RelationalDatabase.cpp diff --git a/src/ripple/app/rdb/impl/ShardArchive.cpp b/src/xrpld/app/rdb/detail/ShardArchive.cpp similarity index 100% rename from src/ripple/app/rdb/impl/ShardArchive.cpp rename to src/xrpld/app/rdb/detail/ShardArchive.cpp diff --git a/src/ripple/app/rdb/impl/State.cpp b/src/xrpld/app/rdb/detail/State.cpp similarity index 100% rename from src/ripple/app/rdb/impl/State.cpp rename to src/xrpld/app/rdb/detail/State.cpp diff --git a/src/ripple/app/rdb/impl/UnitaryShard.cpp b/src/xrpld/app/rdb/detail/UnitaryShard.cpp similarity index 100% rename from src/ripple/app/rdb/impl/UnitaryShard.cpp rename to src/xrpld/app/rdb/detail/UnitaryShard.cpp diff --git a/src/ripple/app/rdb/impl/Vacuum.cpp b/src/xrpld/app/rdb/detail/Vacuum.cpp similarity index 100% rename from src/ripple/app/rdb/impl/Vacuum.cpp rename to src/xrpld/app/rdb/detail/Vacuum.cpp diff --git a/src/ripple/app/rdb/impl/Wallet.cpp b/src/xrpld/app/rdb/detail/Wallet.cpp similarity index 100% rename from src/ripple/app/rdb/impl/Wallet.cpp rename to src/xrpld/app/rdb/detail/Wallet.cpp diff --git a/src/ripple/app/reporting/ETLHelpers.h b/src/xrpld/app/reporting/ETLHelpers.h similarity index 100% rename from src/ripple/app/reporting/ETLHelpers.h rename to src/xrpld/app/reporting/ETLHelpers.h diff --git a/src/ripple/app/reporting/ETLSource.cpp b/src/xrpld/app/reporting/ETLSource.cpp similarity index 100% rename from src/ripple/app/reporting/ETLSource.cpp rename to src/xrpld/app/reporting/ETLSource.cpp diff --git a/src/ripple/app/reporting/ETLSource.h b/src/xrpld/app/reporting/ETLSource.h similarity index 100% rename from src/ripple/app/reporting/ETLSource.h rename to src/xrpld/app/reporting/ETLSource.h diff --git a/src/ripple/app/reporting/P2pProxy.cpp b/src/xrpld/app/reporting/P2pProxy.cpp similarity index 100% rename from src/ripple/app/reporting/P2pProxy.cpp rename to src/xrpld/app/reporting/P2pProxy.cpp diff --git a/src/ripple/app/reporting/P2pProxy.h b/src/xrpld/app/reporting/P2pProxy.h similarity index 100% rename from src/ripple/app/reporting/P2pProxy.h rename to src/xrpld/app/reporting/P2pProxy.h diff --git a/src/ripple/app/reporting/README.md b/src/xrpld/app/reporting/README.md similarity index 100% rename from src/ripple/app/reporting/README.md rename to src/xrpld/app/reporting/README.md diff --git a/src/ripple/app/reporting/ReportingETL.cpp b/src/xrpld/app/reporting/ReportingETL.cpp similarity index 100% rename from src/ripple/app/reporting/ReportingETL.cpp rename to src/xrpld/app/reporting/ReportingETL.cpp diff --git a/src/ripple/app/reporting/ReportingETL.h b/src/xrpld/app/reporting/ReportingETL.h similarity index 100% rename from src/ripple/app/reporting/ReportingETL.h rename to src/xrpld/app/reporting/ReportingETL.h diff --git a/src/ripple/app/tx/apply.h b/src/xrpld/app/tx/apply.h similarity index 100% rename from src/ripple/app/tx/apply.h rename to src/xrpld/app/tx/apply.h diff --git a/src/ripple/app/tx/applySteps.h b/src/xrpld/app/tx/applySteps.h similarity index 100% rename from src/ripple/app/tx/applySteps.h rename to src/xrpld/app/tx/applySteps.h diff --git a/src/ripple/app/tx/impl/AMMBid.cpp b/src/xrpld/app/tx/detail/AMMBid.cpp similarity index 100% rename from src/ripple/app/tx/impl/AMMBid.cpp rename to src/xrpld/app/tx/detail/AMMBid.cpp diff --git a/src/ripple/app/tx/impl/AMMBid.h b/src/xrpld/app/tx/detail/AMMBid.h similarity index 100% rename from src/ripple/app/tx/impl/AMMBid.h rename to src/xrpld/app/tx/detail/AMMBid.h diff --git a/src/ripple/app/tx/impl/AMMCreate.cpp b/src/xrpld/app/tx/detail/AMMCreate.cpp similarity index 100% rename from src/ripple/app/tx/impl/AMMCreate.cpp rename to src/xrpld/app/tx/detail/AMMCreate.cpp diff --git a/src/ripple/app/tx/impl/AMMCreate.h b/src/xrpld/app/tx/detail/AMMCreate.h similarity index 100% rename from src/ripple/app/tx/impl/AMMCreate.h rename to src/xrpld/app/tx/detail/AMMCreate.h diff --git a/src/ripple/app/tx/impl/AMMDelete.cpp b/src/xrpld/app/tx/detail/AMMDelete.cpp similarity index 100% rename from src/ripple/app/tx/impl/AMMDelete.cpp rename to src/xrpld/app/tx/detail/AMMDelete.cpp diff --git a/src/ripple/app/tx/impl/AMMDelete.h b/src/xrpld/app/tx/detail/AMMDelete.h similarity index 100% rename from src/ripple/app/tx/impl/AMMDelete.h rename to src/xrpld/app/tx/detail/AMMDelete.h diff --git a/src/ripple/app/tx/impl/AMMDeposit.cpp b/src/xrpld/app/tx/detail/AMMDeposit.cpp similarity index 100% rename from src/ripple/app/tx/impl/AMMDeposit.cpp rename to src/xrpld/app/tx/detail/AMMDeposit.cpp diff --git a/src/ripple/app/tx/impl/AMMDeposit.h b/src/xrpld/app/tx/detail/AMMDeposit.h similarity index 100% rename from src/ripple/app/tx/impl/AMMDeposit.h rename to src/xrpld/app/tx/detail/AMMDeposit.h diff --git a/src/ripple/app/tx/impl/AMMVote.cpp b/src/xrpld/app/tx/detail/AMMVote.cpp similarity index 100% rename from src/ripple/app/tx/impl/AMMVote.cpp rename to src/xrpld/app/tx/detail/AMMVote.cpp diff --git a/src/ripple/app/tx/impl/AMMVote.h b/src/xrpld/app/tx/detail/AMMVote.h similarity index 100% rename from src/ripple/app/tx/impl/AMMVote.h rename to src/xrpld/app/tx/detail/AMMVote.h diff --git a/src/ripple/app/tx/impl/AMMWithdraw.cpp b/src/xrpld/app/tx/detail/AMMWithdraw.cpp similarity index 100% rename from src/ripple/app/tx/impl/AMMWithdraw.cpp rename to src/xrpld/app/tx/detail/AMMWithdraw.cpp diff --git a/src/ripple/app/tx/impl/AMMWithdraw.h b/src/xrpld/app/tx/detail/AMMWithdraw.h similarity index 100% rename from src/ripple/app/tx/impl/AMMWithdraw.h rename to src/xrpld/app/tx/detail/AMMWithdraw.h diff --git a/src/ripple/app/tx/impl/ApplyContext.cpp b/src/xrpld/app/tx/detail/ApplyContext.cpp similarity index 100% rename from src/ripple/app/tx/impl/ApplyContext.cpp rename to src/xrpld/app/tx/detail/ApplyContext.cpp diff --git a/src/ripple/app/tx/impl/ApplyContext.h b/src/xrpld/app/tx/detail/ApplyContext.h similarity index 100% rename from src/ripple/app/tx/impl/ApplyContext.h rename to src/xrpld/app/tx/detail/ApplyContext.h diff --git a/src/ripple/app/tx/impl/BookTip.cpp b/src/xrpld/app/tx/detail/BookTip.cpp similarity index 100% rename from src/ripple/app/tx/impl/BookTip.cpp rename to src/xrpld/app/tx/detail/BookTip.cpp diff --git a/src/ripple/app/tx/impl/BookTip.h b/src/xrpld/app/tx/detail/BookTip.h similarity index 100% rename from src/ripple/app/tx/impl/BookTip.h rename to src/xrpld/app/tx/detail/BookTip.h diff --git a/src/ripple/app/tx/impl/CancelCheck.cpp b/src/xrpld/app/tx/detail/CancelCheck.cpp similarity index 100% rename from src/ripple/app/tx/impl/CancelCheck.cpp rename to src/xrpld/app/tx/detail/CancelCheck.cpp diff --git a/src/ripple/app/tx/impl/CancelCheck.h b/src/xrpld/app/tx/detail/CancelCheck.h similarity index 100% rename from src/ripple/app/tx/impl/CancelCheck.h rename to src/xrpld/app/tx/detail/CancelCheck.h diff --git a/src/ripple/app/tx/impl/CancelOffer.cpp b/src/xrpld/app/tx/detail/CancelOffer.cpp similarity index 100% rename from src/ripple/app/tx/impl/CancelOffer.cpp rename to src/xrpld/app/tx/detail/CancelOffer.cpp diff --git a/src/ripple/app/tx/impl/CancelOffer.h b/src/xrpld/app/tx/detail/CancelOffer.h similarity index 100% rename from src/ripple/app/tx/impl/CancelOffer.h rename to src/xrpld/app/tx/detail/CancelOffer.h diff --git a/src/ripple/app/tx/impl/CashCheck.cpp b/src/xrpld/app/tx/detail/CashCheck.cpp similarity index 100% rename from src/ripple/app/tx/impl/CashCheck.cpp rename to src/xrpld/app/tx/detail/CashCheck.cpp diff --git a/src/ripple/app/tx/impl/CashCheck.h b/src/xrpld/app/tx/detail/CashCheck.h similarity index 100% rename from src/ripple/app/tx/impl/CashCheck.h rename to src/xrpld/app/tx/detail/CashCheck.h diff --git a/src/ripple/app/tx/impl/Change.cpp b/src/xrpld/app/tx/detail/Change.cpp similarity index 100% rename from src/ripple/app/tx/impl/Change.cpp rename to src/xrpld/app/tx/detail/Change.cpp diff --git a/src/ripple/app/tx/impl/Change.h b/src/xrpld/app/tx/detail/Change.h similarity index 100% rename from src/ripple/app/tx/impl/Change.h rename to src/xrpld/app/tx/detail/Change.h diff --git a/src/ripple/app/tx/impl/Clawback.cpp b/src/xrpld/app/tx/detail/Clawback.cpp similarity index 100% rename from src/ripple/app/tx/impl/Clawback.cpp rename to src/xrpld/app/tx/detail/Clawback.cpp diff --git a/src/ripple/app/tx/impl/Clawback.h b/src/xrpld/app/tx/detail/Clawback.h similarity index 100% rename from src/ripple/app/tx/impl/Clawback.h rename to src/xrpld/app/tx/detail/Clawback.h diff --git a/src/ripple/app/tx/impl/CreateCheck.cpp b/src/xrpld/app/tx/detail/CreateCheck.cpp similarity index 100% rename from src/ripple/app/tx/impl/CreateCheck.cpp rename to src/xrpld/app/tx/detail/CreateCheck.cpp diff --git a/src/ripple/app/tx/impl/CreateCheck.h b/src/xrpld/app/tx/detail/CreateCheck.h similarity index 100% rename from src/ripple/app/tx/impl/CreateCheck.h rename to src/xrpld/app/tx/detail/CreateCheck.h diff --git a/src/ripple/app/tx/impl/CreateOffer.cpp b/src/xrpld/app/tx/detail/CreateOffer.cpp similarity index 100% rename from src/ripple/app/tx/impl/CreateOffer.cpp rename to src/xrpld/app/tx/detail/CreateOffer.cpp diff --git a/src/ripple/app/tx/impl/CreateOffer.h b/src/xrpld/app/tx/detail/CreateOffer.h similarity index 100% rename from src/ripple/app/tx/impl/CreateOffer.h rename to src/xrpld/app/tx/detail/CreateOffer.h diff --git a/src/ripple/app/tx/impl/CreateTicket.cpp b/src/xrpld/app/tx/detail/CreateTicket.cpp similarity index 100% rename from src/ripple/app/tx/impl/CreateTicket.cpp rename to src/xrpld/app/tx/detail/CreateTicket.cpp diff --git a/src/ripple/app/tx/impl/CreateTicket.h b/src/xrpld/app/tx/detail/CreateTicket.h similarity index 100% rename from src/ripple/app/tx/impl/CreateTicket.h rename to src/xrpld/app/tx/detail/CreateTicket.h diff --git a/src/ripple/app/tx/impl/DID.cpp b/src/xrpld/app/tx/detail/DID.cpp similarity index 100% rename from src/ripple/app/tx/impl/DID.cpp rename to src/xrpld/app/tx/detail/DID.cpp diff --git a/src/ripple/app/tx/impl/DID.h b/src/xrpld/app/tx/detail/DID.h similarity index 100% rename from src/ripple/app/tx/impl/DID.h rename to src/xrpld/app/tx/detail/DID.h diff --git a/src/ripple/app/tx/impl/DeleteAccount.cpp b/src/xrpld/app/tx/detail/DeleteAccount.cpp similarity index 100% rename from src/ripple/app/tx/impl/DeleteAccount.cpp rename to src/xrpld/app/tx/detail/DeleteAccount.cpp diff --git a/src/ripple/app/tx/impl/DeleteAccount.h b/src/xrpld/app/tx/detail/DeleteAccount.h similarity index 100% rename from src/ripple/app/tx/impl/DeleteAccount.h rename to src/xrpld/app/tx/detail/DeleteAccount.h diff --git a/src/ripple/app/tx/impl/DeleteOracle.cpp b/src/xrpld/app/tx/detail/DeleteOracle.cpp similarity index 100% rename from src/ripple/app/tx/impl/DeleteOracle.cpp rename to src/xrpld/app/tx/detail/DeleteOracle.cpp diff --git a/src/ripple/app/tx/impl/DeleteOracle.h b/src/xrpld/app/tx/detail/DeleteOracle.h similarity index 100% rename from src/ripple/app/tx/impl/DeleteOracle.h rename to src/xrpld/app/tx/detail/DeleteOracle.h diff --git a/src/ripple/app/tx/impl/DepositPreauth.cpp b/src/xrpld/app/tx/detail/DepositPreauth.cpp similarity index 100% rename from src/ripple/app/tx/impl/DepositPreauth.cpp rename to src/xrpld/app/tx/detail/DepositPreauth.cpp diff --git a/src/ripple/app/tx/impl/DepositPreauth.h b/src/xrpld/app/tx/detail/DepositPreauth.h similarity index 100% rename from src/ripple/app/tx/impl/DepositPreauth.h rename to src/xrpld/app/tx/detail/DepositPreauth.h diff --git a/src/ripple/app/tx/impl/Escrow.cpp b/src/xrpld/app/tx/detail/Escrow.cpp similarity index 100% rename from src/ripple/app/tx/impl/Escrow.cpp rename to src/xrpld/app/tx/detail/Escrow.cpp diff --git a/src/ripple/app/tx/impl/Escrow.h b/src/xrpld/app/tx/detail/Escrow.h similarity index 100% rename from src/ripple/app/tx/impl/Escrow.h rename to src/xrpld/app/tx/detail/Escrow.h diff --git a/src/ripple/app/tx/impl/InvariantCheck.cpp b/src/xrpld/app/tx/detail/InvariantCheck.cpp similarity index 100% rename from src/ripple/app/tx/impl/InvariantCheck.cpp rename to src/xrpld/app/tx/detail/InvariantCheck.cpp diff --git a/src/ripple/app/tx/impl/InvariantCheck.h b/src/xrpld/app/tx/detail/InvariantCheck.h similarity index 100% rename from src/ripple/app/tx/impl/InvariantCheck.h rename to src/xrpld/app/tx/detail/InvariantCheck.h diff --git a/src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp b/src/xrpld/app/tx/detail/NFTokenAcceptOffer.cpp similarity index 100% rename from src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp rename to src/xrpld/app/tx/detail/NFTokenAcceptOffer.cpp diff --git a/src/ripple/app/tx/impl/NFTokenAcceptOffer.h b/src/xrpld/app/tx/detail/NFTokenAcceptOffer.h similarity index 100% rename from src/ripple/app/tx/impl/NFTokenAcceptOffer.h rename to src/xrpld/app/tx/detail/NFTokenAcceptOffer.h diff --git a/src/ripple/app/tx/impl/NFTokenBurn.cpp b/src/xrpld/app/tx/detail/NFTokenBurn.cpp similarity index 100% rename from src/ripple/app/tx/impl/NFTokenBurn.cpp rename to src/xrpld/app/tx/detail/NFTokenBurn.cpp diff --git a/src/ripple/app/tx/impl/NFTokenBurn.h b/src/xrpld/app/tx/detail/NFTokenBurn.h similarity index 100% rename from src/ripple/app/tx/impl/NFTokenBurn.h rename to src/xrpld/app/tx/detail/NFTokenBurn.h diff --git a/src/ripple/app/tx/impl/NFTokenCancelOffer.cpp b/src/xrpld/app/tx/detail/NFTokenCancelOffer.cpp similarity index 100% rename from src/ripple/app/tx/impl/NFTokenCancelOffer.cpp rename to src/xrpld/app/tx/detail/NFTokenCancelOffer.cpp diff --git a/src/ripple/app/tx/impl/NFTokenCancelOffer.h b/src/xrpld/app/tx/detail/NFTokenCancelOffer.h similarity index 100% rename from src/ripple/app/tx/impl/NFTokenCancelOffer.h rename to src/xrpld/app/tx/detail/NFTokenCancelOffer.h diff --git a/src/ripple/app/tx/impl/NFTokenCreateOffer.cpp b/src/xrpld/app/tx/detail/NFTokenCreateOffer.cpp similarity index 100% rename from src/ripple/app/tx/impl/NFTokenCreateOffer.cpp rename to src/xrpld/app/tx/detail/NFTokenCreateOffer.cpp diff --git a/src/ripple/app/tx/impl/NFTokenCreateOffer.h b/src/xrpld/app/tx/detail/NFTokenCreateOffer.h similarity index 100% rename from src/ripple/app/tx/impl/NFTokenCreateOffer.h rename to src/xrpld/app/tx/detail/NFTokenCreateOffer.h diff --git a/src/ripple/app/tx/impl/NFTokenMint.cpp b/src/xrpld/app/tx/detail/NFTokenMint.cpp similarity index 100% rename from src/ripple/app/tx/impl/NFTokenMint.cpp rename to src/xrpld/app/tx/detail/NFTokenMint.cpp diff --git a/src/ripple/app/tx/impl/NFTokenMint.h b/src/xrpld/app/tx/detail/NFTokenMint.h similarity index 100% rename from src/ripple/app/tx/impl/NFTokenMint.h rename to src/xrpld/app/tx/detail/NFTokenMint.h diff --git a/src/ripple/app/tx/impl/details/NFTokenUtils.cpp b/src/xrpld/app/tx/detail/NFTokenUtils.cpp similarity index 100% rename from src/ripple/app/tx/impl/details/NFTokenUtils.cpp rename to src/xrpld/app/tx/detail/NFTokenUtils.cpp diff --git a/src/ripple/app/tx/impl/details/NFTokenUtils.h b/src/xrpld/app/tx/detail/NFTokenUtils.h similarity index 100% rename from src/ripple/app/tx/impl/details/NFTokenUtils.h rename to src/xrpld/app/tx/detail/NFTokenUtils.h diff --git a/src/ripple/app/tx/impl/Offer.h b/src/xrpld/app/tx/detail/Offer.h similarity index 100% rename from src/ripple/app/tx/impl/Offer.h rename to src/xrpld/app/tx/detail/Offer.h diff --git a/src/ripple/app/tx/impl/OfferStream.cpp b/src/xrpld/app/tx/detail/OfferStream.cpp similarity index 100% rename from src/ripple/app/tx/impl/OfferStream.cpp rename to src/xrpld/app/tx/detail/OfferStream.cpp diff --git a/src/ripple/app/tx/impl/OfferStream.h b/src/xrpld/app/tx/detail/OfferStream.h similarity index 100% rename from src/ripple/app/tx/impl/OfferStream.h rename to src/xrpld/app/tx/detail/OfferStream.h diff --git a/src/ripple/app/tx/impl/PayChan.cpp b/src/xrpld/app/tx/detail/PayChan.cpp similarity index 100% rename from src/ripple/app/tx/impl/PayChan.cpp rename to src/xrpld/app/tx/detail/PayChan.cpp diff --git a/src/ripple/app/tx/impl/PayChan.h b/src/xrpld/app/tx/detail/PayChan.h similarity index 100% rename from src/ripple/app/tx/impl/PayChan.h rename to src/xrpld/app/tx/detail/PayChan.h diff --git a/src/ripple/app/tx/impl/Payment.cpp b/src/xrpld/app/tx/detail/Payment.cpp similarity index 100% rename from src/ripple/app/tx/impl/Payment.cpp rename to src/xrpld/app/tx/detail/Payment.cpp diff --git a/src/ripple/app/tx/impl/Payment.h b/src/xrpld/app/tx/detail/Payment.h similarity index 100% rename from src/ripple/app/tx/impl/Payment.h rename to src/xrpld/app/tx/detail/Payment.h diff --git a/src/ripple/app/tx/impl/SetAccount.cpp b/src/xrpld/app/tx/detail/SetAccount.cpp similarity index 100% rename from src/ripple/app/tx/impl/SetAccount.cpp rename to src/xrpld/app/tx/detail/SetAccount.cpp diff --git a/src/ripple/app/tx/impl/SetAccount.h b/src/xrpld/app/tx/detail/SetAccount.h similarity index 100% rename from src/ripple/app/tx/impl/SetAccount.h rename to src/xrpld/app/tx/detail/SetAccount.h diff --git a/src/ripple/app/tx/impl/SetOracle.cpp b/src/xrpld/app/tx/detail/SetOracle.cpp similarity index 100% rename from src/ripple/app/tx/impl/SetOracle.cpp rename to src/xrpld/app/tx/detail/SetOracle.cpp diff --git a/src/ripple/app/tx/impl/SetOracle.h b/src/xrpld/app/tx/detail/SetOracle.h similarity index 100% rename from src/ripple/app/tx/impl/SetOracle.h rename to src/xrpld/app/tx/detail/SetOracle.h diff --git a/src/ripple/app/tx/impl/SetRegularKey.cpp b/src/xrpld/app/tx/detail/SetRegularKey.cpp similarity index 100% rename from src/ripple/app/tx/impl/SetRegularKey.cpp rename to src/xrpld/app/tx/detail/SetRegularKey.cpp diff --git a/src/ripple/app/tx/impl/SetRegularKey.h b/src/xrpld/app/tx/detail/SetRegularKey.h similarity index 100% rename from src/ripple/app/tx/impl/SetRegularKey.h rename to src/xrpld/app/tx/detail/SetRegularKey.h diff --git a/src/ripple/app/tx/impl/SetSignerList.cpp b/src/xrpld/app/tx/detail/SetSignerList.cpp similarity index 100% rename from src/ripple/app/tx/impl/SetSignerList.cpp rename to src/xrpld/app/tx/detail/SetSignerList.cpp diff --git a/src/ripple/app/tx/impl/SetSignerList.h b/src/xrpld/app/tx/detail/SetSignerList.h similarity index 100% rename from src/ripple/app/tx/impl/SetSignerList.h rename to src/xrpld/app/tx/detail/SetSignerList.h diff --git a/src/ripple/app/tx/impl/SetTrust.cpp b/src/xrpld/app/tx/detail/SetTrust.cpp similarity index 100% rename from src/ripple/app/tx/impl/SetTrust.cpp rename to src/xrpld/app/tx/detail/SetTrust.cpp diff --git a/src/ripple/app/tx/impl/SetTrust.h b/src/xrpld/app/tx/detail/SetTrust.h similarity index 100% rename from src/ripple/app/tx/impl/SetTrust.h rename to src/xrpld/app/tx/detail/SetTrust.h diff --git a/src/ripple/app/tx/impl/SignerEntries.cpp b/src/xrpld/app/tx/detail/SignerEntries.cpp similarity index 100% rename from src/ripple/app/tx/impl/SignerEntries.cpp rename to src/xrpld/app/tx/detail/SignerEntries.cpp diff --git a/src/ripple/app/tx/impl/SignerEntries.h b/src/xrpld/app/tx/detail/SignerEntries.h similarity index 100% rename from src/ripple/app/tx/impl/SignerEntries.h rename to src/xrpld/app/tx/detail/SignerEntries.h diff --git a/src/ripple/app/tx/impl/Taker.cpp b/src/xrpld/app/tx/detail/Taker.cpp similarity index 100% rename from src/ripple/app/tx/impl/Taker.cpp rename to src/xrpld/app/tx/detail/Taker.cpp diff --git a/src/ripple/app/tx/impl/Taker.h b/src/xrpld/app/tx/detail/Taker.h similarity index 100% rename from src/ripple/app/tx/impl/Taker.h rename to src/xrpld/app/tx/detail/Taker.h diff --git a/src/ripple/app/tx/impl/Transactor.cpp b/src/xrpld/app/tx/detail/Transactor.cpp similarity index 100% rename from src/ripple/app/tx/impl/Transactor.cpp rename to src/xrpld/app/tx/detail/Transactor.cpp diff --git a/src/ripple/app/tx/impl/Transactor.h b/src/xrpld/app/tx/detail/Transactor.h similarity index 100% rename from src/ripple/app/tx/impl/Transactor.h rename to src/xrpld/app/tx/detail/Transactor.h diff --git a/src/ripple/app/tx/impl/XChainBridge.cpp b/src/xrpld/app/tx/detail/XChainBridge.cpp similarity index 100% rename from src/ripple/app/tx/impl/XChainBridge.cpp rename to src/xrpld/app/tx/detail/XChainBridge.cpp diff --git a/src/ripple/app/tx/impl/XChainBridge.h b/src/xrpld/app/tx/detail/XChainBridge.h similarity index 100% rename from src/ripple/app/tx/impl/XChainBridge.h rename to src/xrpld/app/tx/detail/XChainBridge.h diff --git a/src/ripple/app/tx/impl/apply.cpp b/src/xrpld/app/tx/detail/apply.cpp similarity index 100% rename from src/ripple/app/tx/impl/apply.cpp rename to src/xrpld/app/tx/detail/apply.cpp diff --git a/src/ripple/app/tx/impl/applySteps.cpp b/src/xrpld/app/tx/detail/applySteps.cpp similarity index 100% rename from src/ripple/app/tx/impl/applySteps.cpp rename to src/xrpld/app/tx/detail/applySteps.cpp diff --git a/src/ripple/conditions/Condition.h b/src/xrpld/conditions/Condition.h similarity index 100% rename from src/ripple/conditions/Condition.h rename to src/xrpld/conditions/Condition.h diff --git a/src/ripple/conditions/Fulfillment.h b/src/xrpld/conditions/Fulfillment.h similarity index 100% rename from src/ripple/conditions/Fulfillment.h rename to src/xrpld/conditions/Fulfillment.h diff --git a/src/ripple/conditions/impl/Condition.cpp b/src/xrpld/conditions/detail/Condition.cpp similarity index 100% rename from src/ripple/conditions/impl/Condition.cpp rename to src/xrpld/conditions/detail/Condition.cpp diff --git a/src/ripple/conditions/impl/Fulfillment.cpp b/src/xrpld/conditions/detail/Fulfillment.cpp similarity index 100% rename from src/ripple/conditions/impl/Fulfillment.cpp rename to src/xrpld/conditions/detail/Fulfillment.cpp diff --git a/src/ripple/conditions/impl/PreimageSha256.h b/src/xrpld/conditions/detail/PreimageSha256.h similarity index 100% rename from src/ripple/conditions/impl/PreimageSha256.h rename to src/xrpld/conditions/detail/PreimageSha256.h diff --git a/src/ripple/conditions/impl/error.cpp b/src/xrpld/conditions/detail/error.cpp similarity index 100% rename from src/ripple/conditions/impl/error.cpp rename to src/xrpld/conditions/detail/error.cpp diff --git a/src/ripple/conditions/impl/error.h b/src/xrpld/conditions/detail/error.h similarity index 100% rename from src/ripple/conditions/impl/error.h rename to src/xrpld/conditions/detail/error.h diff --git a/src/ripple/conditions/impl/utils.h b/src/xrpld/conditions/detail/utils.h similarity index 100% rename from src/ripple/conditions/impl/utils.h rename to src/xrpld/conditions/detail/utils.h diff --git a/src/ripple/consensus/Consensus.cpp b/src/xrpld/consensus/Consensus.cpp similarity index 100% rename from src/ripple/consensus/Consensus.cpp rename to src/xrpld/consensus/Consensus.cpp diff --git a/src/ripple/consensus/Consensus.h b/src/xrpld/consensus/Consensus.h similarity index 100% rename from src/ripple/consensus/Consensus.h rename to src/xrpld/consensus/Consensus.h diff --git a/src/ripple/consensus/ConsensusParms.h b/src/xrpld/consensus/ConsensusParms.h similarity index 100% rename from src/ripple/consensus/ConsensusParms.h rename to src/xrpld/consensus/ConsensusParms.h diff --git a/src/ripple/consensus/ConsensusProposal.h b/src/xrpld/consensus/ConsensusProposal.h similarity index 100% rename from src/ripple/consensus/ConsensusProposal.h rename to src/xrpld/consensus/ConsensusProposal.h diff --git a/src/ripple/consensus/ConsensusTypes.h b/src/xrpld/consensus/ConsensusTypes.h similarity index 100% rename from src/ripple/consensus/ConsensusTypes.h rename to src/xrpld/consensus/ConsensusTypes.h diff --git a/src/ripple/consensus/DisputedTx.h b/src/xrpld/consensus/DisputedTx.h similarity index 100% rename from src/ripple/consensus/DisputedTx.h rename to src/xrpld/consensus/DisputedTx.h diff --git a/src/ripple/consensus/LedgerTiming.h b/src/xrpld/consensus/LedgerTiming.h similarity index 100% rename from src/ripple/consensus/LedgerTiming.h rename to src/xrpld/consensus/LedgerTiming.h diff --git a/src/ripple/consensus/LedgerTrie.h b/src/xrpld/consensus/LedgerTrie.h similarity index 100% rename from src/ripple/consensus/LedgerTrie.h rename to src/xrpld/consensus/LedgerTrie.h diff --git a/src/ripple/consensus/README.md b/src/xrpld/consensus/README.md similarity index 100% rename from src/ripple/consensus/README.md rename to src/xrpld/consensus/README.md diff --git a/src/ripple/consensus/Validations.h b/src/xrpld/consensus/Validations.h similarity index 100% rename from src/ripple/consensus/Validations.h rename to src/xrpld/consensus/Validations.h diff --git a/src/ripple/core/ClosureCounter.h b/src/xrpld/core/ClosureCounter.h similarity index 100% rename from src/ripple/core/ClosureCounter.h rename to src/xrpld/core/ClosureCounter.h diff --git a/src/ripple/core/Config.h b/src/xrpld/core/Config.h similarity index 100% rename from src/ripple/core/Config.h rename to src/xrpld/core/Config.h diff --git a/src/ripple/core/ConfigSections.h b/src/xrpld/core/ConfigSections.h similarity index 100% rename from src/ripple/core/ConfigSections.h rename to src/xrpld/core/ConfigSections.h diff --git a/src/ripple/core/Coro.ipp b/src/xrpld/core/Coro.ipp similarity index 100% rename from src/ripple/core/Coro.ipp rename to src/xrpld/core/Coro.ipp diff --git a/src/ripple/core/DatabaseCon.h b/src/xrpld/core/DatabaseCon.h similarity index 100% rename from src/ripple/core/DatabaseCon.h rename to src/xrpld/core/DatabaseCon.h diff --git a/src/ripple/core/Job.h b/src/xrpld/core/Job.h similarity index 100% rename from src/ripple/core/Job.h rename to src/xrpld/core/Job.h diff --git a/src/ripple/core/JobQueue.h b/src/xrpld/core/JobQueue.h similarity index 100% rename from src/ripple/core/JobQueue.h rename to src/xrpld/core/JobQueue.h diff --git a/src/ripple/core/JobTypeData.h b/src/xrpld/core/JobTypeData.h similarity index 100% rename from src/ripple/core/JobTypeData.h rename to src/xrpld/core/JobTypeData.h diff --git a/src/ripple/core/JobTypeInfo.h b/src/xrpld/core/JobTypeInfo.h similarity index 100% rename from src/ripple/core/JobTypeInfo.h rename to src/xrpld/core/JobTypeInfo.h diff --git a/src/ripple/core/JobTypes.h b/src/xrpld/core/JobTypes.h similarity index 100% rename from src/ripple/core/JobTypes.h rename to src/xrpld/core/JobTypes.h diff --git a/src/ripple/core/LoadEvent.h b/src/xrpld/core/LoadEvent.h similarity index 100% rename from src/ripple/core/LoadEvent.h rename to src/xrpld/core/LoadEvent.h diff --git a/src/ripple/core/LoadMonitor.h b/src/xrpld/core/LoadMonitor.h similarity index 100% rename from src/ripple/core/LoadMonitor.h rename to src/xrpld/core/LoadMonitor.h diff --git a/src/ripple/core/Pg.cpp b/src/xrpld/core/Pg.cpp similarity index 100% rename from src/ripple/core/Pg.cpp rename to src/xrpld/core/Pg.cpp diff --git a/src/ripple/core/Pg.h b/src/xrpld/core/Pg.h similarity index 100% rename from src/ripple/core/Pg.h rename to src/xrpld/core/Pg.h diff --git a/src/ripple/core/SociDB.h b/src/xrpld/core/SociDB.h similarity index 100% rename from src/ripple/core/SociDB.h rename to src/xrpld/core/SociDB.h diff --git a/src/ripple/core/TimeKeeper.h b/src/xrpld/core/TimeKeeper.h similarity index 100% rename from src/ripple/core/TimeKeeper.h rename to src/xrpld/core/TimeKeeper.h diff --git a/src/ripple/core/impl/Config.cpp b/src/xrpld/core/detail/Config.cpp similarity index 100% rename from src/ripple/core/impl/Config.cpp rename to src/xrpld/core/detail/Config.cpp diff --git a/src/ripple/core/impl/DatabaseCon.cpp b/src/xrpld/core/detail/DatabaseCon.cpp similarity index 100% rename from src/ripple/core/impl/DatabaseCon.cpp rename to src/xrpld/core/detail/DatabaseCon.cpp diff --git a/src/ripple/core/impl/Job.cpp b/src/xrpld/core/detail/Job.cpp similarity index 100% rename from src/ripple/core/impl/Job.cpp rename to src/xrpld/core/detail/Job.cpp diff --git a/src/ripple/core/impl/JobQueue.cpp b/src/xrpld/core/detail/JobQueue.cpp similarity index 100% rename from src/ripple/core/impl/JobQueue.cpp rename to src/xrpld/core/detail/JobQueue.cpp diff --git a/src/ripple/core/impl/LoadEvent.cpp b/src/xrpld/core/detail/LoadEvent.cpp similarity index 100% rename from src/ripple/core/impl/LoadEvent.cpp rename to src/xrpld/core/detail/LoadEvent.cpp diff --git a/src/ripple/core/impl/LoadMonitor.cpp b/src/xrpld/core/detail/LoadMonitor.cpp similarity index 100% rename from src/ripple/core/impl/LoadMonitor.cpp rename to src/xrpld/core/detail/LoadMonitor.cpp diff --git a/src/ripple/core/impl/SociDB.cpp b/src/xrpld/core/detail/SociDB.cpp similarity index 100% rename from src/ripple/core/impl/SociDB.cpp rename to src/xrpld/core/detail/SociDB.cpp diff --git a/src/ripple/core/impl/Workers.cpp b/src/xrpld/core/detail/Workers.cpp similarity index 100% rename from src/ripple/core/impl/Workers.cpp rename to src/xrpld/core/detail/Workers.cpp diff --git a/src/ripple/core/impl/Workers.h b/src/xrpld/core/detail/Workers.h similarity index 100% rename from src/ripple/core/impl/Workers.h rename to src/xrpld/core/detail/Workers.h diff --git a/src/ripple/core/impl/semaphore.h b/src/xrpld/core/detail/semaphore.h similarity index 100% rename from src/ripple/core/impl/semaphore.h rename to src/xrpld/core/detail/semaphore.h diff --git a/src/ripple/ledger/ApplyView.h b/src/xrpld/ledger/ApplyView.h similarity index 100% rename from src/ripple/ledger/ApplyView.h rename to src/xrpld/ledger/ApplyView.h diff --git a/src/ripple/ledger/ApplyViewImpl.h b/src/xrpld/ledger/ApplyViewImpl.h similarity index 100% rename from src/ripple/ledger/ApplyViewImpl.h rename to src/xrpld/ledger/ApplyViewImpl.h diff --git a/src/ripple/ledger/BookDirs.h b/src/xrpld/ledger/BookDirs.h similarity index 100% rename from src/ripple/ledger/BookDirs.h rename to src/xrpld/ledger/BookDirs.h diff --git a/src/ripple/ledger/CachedSLEs.h b/src/xrpld/ledger/CachedSLEs.h similarity index 100% rename from src/ripple/ledger/CachedSLEs.h rename to src/xrpld/ledger/CachedSLEs.h diff --git a/src/ripple/ledger/CachedView.h b/src/xrpld/ledger/CachedView.h similarity index 100% rename from src/ripple/ledger/CachedView.h rename to src/xrpld/ledger/CachedView.h diff --git a/src/ripple/ledger/Directory.h b/src/xrpld/ledger/Directory.h similarity index 100% rename from src/ripple/ledger/Directory.h rename to src/xrpld/ledger/Directory.h diff --git a/src/ripple/ledger/OpenView.h b/src/xrpld/ledger/OpenView.h similarity index 100% rename from src/ripple/ledger/OpenView.h rename to src/xrpld/ledger/OpenView.h diff --git a/src/ripple/ledger/PaymentSandbox.h b/src/xrpld/ledger/PaymentSandbox.h similarity index 100% rename from src/ripple/ledger/PaymentSandbox.h rename to src/xrpld/ledger/PaymentSandbox.h diff --git a/src/ripple/ledger/RawView.h b/src/xrpld/ledger/RawView.h similarity index 100% rename from src/ripple/ledger/RawView.h rename to src/xrpld/ledger/RawView.h diff --git a/src/ripple/ledger/ReadView.h b/src/xrpld/ledger/ReadView.h similarity index 100% rename from src/ripple/ledger/ReadView.h rename to src/xrpld/ledger/ReadView.h diff --git a/src/ripple/ledger/Sandbox.h b/src/xrpld/ledger/Sandbox.h similarity index 100% rename from src/ripple/ledger/Sandbox.h rename to src/xrpld/ledger/Sandbox.h diff --git a/src/ripple/ledger/View.h b/src/xrpld/ledger/View.h similarity index 100% rename from src/ripple/ledger/View.h rename to src/xrpld/ledger/View.h diff --git a/src/ripple/ledger/impl/ApplyStateTable.cpp b/src/xrpld/ledger/detail/ApplyStateTable.cpp similarity index 100% rename from src/ripple/ledger/impl/ApplyStateTable.cpp rename to src/xrpld/ledger/detail/ApplyStateTable.cpp diff --git a/src/ripple/ledger/detail/ApplyStateTable.h b/src/xrpld/ledger/detail/ApplyStateTable.h similarity index 100% rename from src/ripple/ledger/detail/ApplyStateTable.h rename to src/xrpld/ledger/detail/ApplyStateTable.h diff --git a/src/ripple/ledger/impl/ApplyView.cpp b/src/xrpld/ledger/detail/ApplyView.cpp similarity index 100% rename from src/ripple/ledger/impl/ApplyView.cpp rename to src/xrpld/ledger/detail/ApplyView.cpp diff --git a/src/ripple/ledger/impl/ApplyViewBase.cpp b/src/xrpld/ledger/detail/ApplyViewBase.cpp similarity index 100% rename from src/ripple/ledger/impl/ApplyViewBase.cpp rename to src/xrpld/ledger/detail/ApplyViewBase.cpp diff --git a/src/ripple/ledger/detail/ApplyViewBase.h b/src/xrpld/ledger/detail/ApplyViewBase.h similarity index 100% rename from src/ripple/ledger/detail/ApplyViewBase.h rename to src/xrpld/ledger/detail/ApplyViewBase.h diff --git a/src/ripple/ledger/impl/ApplyViewImpl.cpp b/src/xrpld/ledger/detail/ApplyViewImpl.cpp similarity index 100% rename from src/ripple/ledger/impl/ApplyViewImpl.cpp rename to src/xrpld/ledger/detail/ApplyViewImpl.cpp diff --git a/src/ripple/ledger/impl/BookDirs.cpp b/src/xrpld/ledger/detail/BookDirs.cpp similarity index 100% rename from src/ripple/ledger/impl/BookDirs.cpp rename to src/xrpld/ledger/detail/BookDirs.cpp diff --git a/src/ripple/ledger/impl/CachedView.cpp b/src/xrpld/ledger/detail/CachedView.cpp similarity index 100% rename from src/ripple/ledger/impl/CachedView.cpp rename to src/xrpld/ledger/detail/CachedView.cpp diff --git a/src/ripple/ledger/impl/Directory.cpp b/src/xrpld/ledger/detail/Directory.cpp similarity index 100% rename from src/ripple/ledger/impl/Directory.cpp rename to src/xrpld/ledger/detail/Directory.cpp diff --git a/src/ripple/ledger/impl/OpenView.cpp b/src/xrpld/ledger/detail/OpenView.cpp similarity index 100% rename from src/ripple/ledger/impl/OpenView.cpp rename to src/xrpld/ledger/detail/OpenView.cpp diff --git a/src/ripple/ledger/impl/PaymentSandbox.cpp b/src/xrpld/ledger/detail/PaymentSandbox.cpp similarity index 100% rename from src/ripple/ledger/impl/PaymentSandbox.cpp rename to src/xrpld/ledger/detail/PaymentSandbox.cpp diff --git a/src/ripple/ledger/impl/RawStateTable.cpp b/src/xrpld/ledger/detail/RawStateTable.cpp similarity index 100% rename from src/ripple/ledger/impl/RawStateTable.cpp rename to src/xrpld/ledger/detail/RawStateTable.cpp diff --git a/src/ripple/ledger/detail/RawStateTable.h b/src/xrpld/ledger/detail/RawStateTable.h similarity index 100% rename from src/ripple/ledger/detail/RawStateTable.h rename to src/xrpld/ledger/detail/RawStateTable.h diff --git a/src/ripple/ledger/impl/ReadView.cpp b/src/xrpld/ledger/detail/ReadView.cpp similarity index 100% rename from src/ripple/ledger/impl/ReadView.cpp rename to src/xrpld/ledger/detail/ReadView.cpp diff --git a/src/ripple/ledger/detail/ReadViewFwdRange.h b/src/xrpld/ledger/detail/ReadViewFwdRange.h similarity index 100% rename from src/ripple/ledger/detail/ReadViewFwdRange.h rename to src/xrpld/ledger/detail/ReadViewFwdRange.h diff --git a/src/ripple/ledger/detail/ReadViewFwdRange.ipp b/src/xrpld/ledger/detail/ReadViewFwdRange.ipp similarity index 100% rename from src/ripple/ledger/detail/ReadViewFwdRange.ipp rename to src/xrpld/ledger/detail/ReadViewFwdRange.ipp diff --git a/src/ripple/ledger/impl/View.cpp b/src/xrpld/ledger/detail/View.cpp similarity index 100% rename from src/ripple/ledger/impl/View.cpp rename to src/xrpld/ledger/detail/View.cpp diff --git a/src/ripple/net/AutoSocket.h b/src/xrpld/net/AutoSocket.h similarity index 100% rename from src/ripple/net/AutoSocket.h rename to src/xrpld/net/AutoSocket.h diff --git a/src/ripple/net/DatabaseBody.h b/src/xrpld/net/DatabaseBody.h similarity index 100% rename from src/ripple/net/DatabaseBody.h rename to src/xrpld/net/DatabaseBody.h diff --git a/src/ripple/net/DatabaseDownloader.h b/src/xrpld/net/DatabaseDownloader.h similarity index 100% rename from src/ripple/net/DatabaseDownloader.h rename to src/xrpld/net/DatabaseDownloader.h diff --git a/src/ripple/net/HTTPClient.h b/src/xrpld/net/HTTPClient.h similarity index 100% rename from src/ripple/net/HTTPClient.h rename to src/xrpld/net/HTTPClient.h diff --git a/src/ripple/net/HTTPClientSSLContext.h b/src/xrpld/net/HTTPClientSSLContext.h similarity index 100% rename from src/ripple/net/HTTPClientSSLContext.h rename to src/xrpld/net/HTTPClientSSLContext.h diff --git a/src/ripple/net/HTTPDownloader.h b/src/xrpld/net/HTTPDownloader.h similarity index 100% rename from src/ripple/net/HTTPDownloader.h rename to src/xrpld/net/HTTPDownloader.h diff --git a/src/ripple/net/HTTPStream.h b/src/xrpld/net/HTTPStream.h similarity index 100% rename from src/ripple/net/HTTPStream.h rename to src/xrpld/net/HTTPStream.h diff --git a/src/ripple/net/InfoSub.h b/src/xrpld/net/InfoSub.h similarity index 100% rename from src/ripple/net/InfoSub.h rename to src/xrpld/net/InfoSub.h diff --git a/src/ripple/net/RPCCall.h b/src/xrpld/net/RPCCall.h similarity index 100% rename from src/ripple/net/RPCCall.h rename to src/xrpld/net/RPCCall.h diff --git a/src/ripple/net/RPCSub.h b/src/xrpld/net/RPCSub.h similarity index 100% rename from src/ripple/net/RPCSub.h rename to src/xrpld/net/RPCSub.h diff --git a/src/ripple/net/RegisterSSLCerts.h b/src/xrpld/net/RegisterSSLCerts.h similarity index 100% rename from src/ripple/net/RegisterSSLCerts.h rename to src/xrpld/net/RegisterSSLCerts.h diff --git a/src/ripple/net/ShardDownloader.md b/src/xrpld/net/ShardDownloader.md similarity index 100% rename from src/ripple/net/ShardDownloader.md rename to src/xrpld/net/ShardDownloader.md diff --git a/src/ripple/net/impl/DatabaseBody.ipp b/src/xrpld/net/detail/DatabaseBody.ipp similarity index 100% rename from src/ripple/net/impl/DatabaseBody.ipp rename to src/xrpld/net/detail/DatabaseBody.ipp diff --git a/src/ripple/net/impl/DatabaseDownloader.cpp b/src/xrpld/net/detail/DatabaseDownloader.cpp similarity index 100% rename from src/ripple/net/impl/DatabaseDownloader.cpp rename to src/xrpld/net/detail/DatabaseDownloader.cpp diff --git a/src/ripple/net/impl/HTTPClient.cpp b/src/xrpld/net/detail/HTTPClient.cpp similarity index 100% rename from src/ripple/net/impl/HTTPClient.cpp rename to src/xrpld/net/detail/HTTPClient.cpp diff --git a/src/ripple/net/impl/HTTPDownloader.cpp b/src/xrpld/net/detail/HTTPDownloader.cpp similarity index 100% rename from src/ripple/net/impl/HTTPDownloader.cpp rename to src/xrpld/net/detail/HTTPDownloader.cpp diff --git a/src/ripple/net/impl/HTTPStream.cpp b/src/xrpld/net/detail/HTTPStream.cpp similarity index 100% rename from src/ripple/net/impl/HTTPStream.cpp rename to src/xrpld/net/detail/HTTPStream.cpp diff --git a/src/ripple/net/impl/InfoSub.cpp b/src/xrpld/net/detail/InfoSub.cpp similarity index 100% rename from src/ripple/net/impl/InfoSub.cpp rename to src/xrpld/net/detail/InfoSub.cpp diff --git a/src/ripple/net/impl/RPCCall.cpp b/src/xrpld/net/detail/RPCCall.cpp similarity index 100% rename from src/ripple/net/impl/RPCCall.cpp rename to src/xrpld/net/detail/RPCCall.cpp diff --git a/src/ripple/net/impl/RPCSub.cpp b/src/xrpld/net/detail/RPCSub.cpp similarity index 100% rename from src/ripple/net/impl/RPCSub.cpp rename to src/xrpld/net/detail/RPCSub.cpp diff --git a/src/ripple/net/impl/RegisterSSLCerts.cpp b/src/xrpld/net/detail/RegisterSSLCerts.cpp similarity index 100% rename from src/ripple/net/impl/RegisterSSLCerts.cpp rename to src/xrpld/net/detail/RegisterSSLCerts.cpp diff --git a/src/ripple/net/images/interrupt_sequence.png b/src/xrpld/net/images/interrupt_sequence.png similarity index 100% rename from src/ripple/net/images/interrupt_sequence.png rename to src/xrpld/net/images/interrupt_sequence.png diff --git a/src/ripple/net/images/states.png b/src/xrpld/net/images/states.png similarity index 100% rename from src/ripple/net/images/states.png rename to src/xrpld/net/images/states.png diff --git a/src/ripple/net/uml/interrupt_sequence.pu b/src/xrpld/net/uml/interrupt_sequence.pu similarity index 100% rename from src/ripple/net/uml/interrupt_sequence.pu rename to src/xrpld/net/uml/interrupt_sequence.pu diff --git a/src/ripple/net/uml/states.pu b/src/xrpld/net/uml/states.pu similarity index 100% rename from src/ripple/net/uml/states.pu rename to src/xrpld/net/uml/states.pu diff --git a/src/ripple/nodestore/Backend.h b/src/xrpld/nodestore/Backend.h similarity index 100% rename from src/ripple/nodestore/Backend.h rename to src/xrpld/nodestore/Backend.h diff --git a/src/ripple/nodestore/Database.h b/src/xrpld/nodestore/Database.h similarity index 100% rename from src/ripple/nodestore/Database.h rename to src/xrpld/nodestore/Database.h diff --git a/src/ripple/nodestore/DatabaseRotating.h b/src/xrpld/nodestore/DatabaseRotating.h similarity index 100% rename from src/ripple/nodestore/DatabaseRotating.h rename to src/xrpld/nodestore/DatabaseRotating.h diff --git a/src/ripple/nodestore/DatabaseShard.h b/src/xrpld/nodestore/DatabaseShard.h similarity index 100% rename from src/ripple/nodestore/DatabaseShard.h rename to src/xrpld/nodestore/DatabaseShard.h diff --git a/src/ripple/nodestore/DeterministicShard.md b/src/xrpld/nodestore/DeterministicShard.md similarity index 100% rename from src/ripple/nodestore/DeterministicShard.md rename to src/xrpld/nodestore/DeterministicShard.md diff --git a/src/ripple/nodestore/DummyScheduler.h b/src/xrpld/nodestore/DummyScheduler.h similarity index 100% rename from src/ripple/nodestore/DummyScheduler.h rename to src/xrpld/nodestore/DummyScheduler.h diff --git a/src/ripple/nodestore/Factory.h b/src/xrpld/nodestore/Factory.h similarity index 100% rename from src/ripple/nodestore/Factory.h rename to src/xrpld/nodestore/Factory.h diff --git a/src/ripple/nodestore/Manager.h b/src/xrpld/nodestore/Manager.h similarity index 100% rename from src/ripple/nodestore/Manager.h rename to src/xrpld/nodestore/Manager.h diff --git a/src/ripple/nodestore/NodeObject.h b/src/xrpld/nodestore/NodeObject.h similarity index 100% rename from src/ripple/nodestore/NodeObject.h rename to src/xrpld/nodestore/NodeObject.h diff --git a/src/ripple/nodestore/README.md b/src/xrpld/nodestore/README.md similarity index 100% rename from src/ripple/nodestore/README.md rename to src/xrpld/nodestore/README.md diff --git a/src/ripple/nodestore/Scheduler.h b/src/xrpld/nodestore/Scheduler.h similarity index 100% rename from src/ripple/nodestore/Scheduler.h rename to src/xrpld/nodestore/Scheduler.h diff --git a/src/ripple/nodestore/ShardInfo.h b/src/xrpld/nodestore/ShardInfo.h similarity index 100% rename from src/ripple/nodestore/ShardInfo.h rename to src/xrpld/nodestore/ShardInfo.h diff --git a/src/ripple/nodestore/ShardPool.md b/src/xrpld/nodestore/ShardPool.md similarity index 100% rename from src/ripple/nodestore/ShardPool.md rename to src/xrpld/nodestore/ShardPool.md diff --git a/src/ripple/nodestore/ShardSizeTuning.md b/src/xrpld/nodestore/ShardSizeTuning.md similarity index 100% rename from src/ripple/nodestore/ShardSizeTuning.md rename to src/xrpld/nodestore/ShardSizeTuning.md diff --git a/src/ripple/nodestore/Task.h b/src/xrpld/nodestore/Task.h similarity index 100% rename from src/ripple/nodestore/Task.h rename to src/xrpld/nodestore/Task.h diff --git a/src/ripple/nodestore/Types.h b/src/xrpld/nodestore/Types.h similarity index 100% rename from src/ripple/nodestore/Types.h rename to src/xrpld/nodestore/Types.h diff --git a/src/ripple/nodestore/backend/CassandraFactory.cpp b/src/xrpld/nodestore/backend/CassandraFactory.cpp similarity index 100% rename from src/ripple/nodestore/backend/CassandraFactory.cpp rename to src/xrpld/nodestore/backend/CassandraFactory.cpp diff --git a/src/ripple/nodestore/backend/MemoryFactory.cpp b/src/xrpld/nodestore/backend/MemoryFactory.cpp similarity index 100% rename from src/ripple/nodestore/backend/MemoryFactory.cpp rename to src/xrpld/nodestore/backend/MemoryFactory.cpp diff --git a/src/ripple/nodestore/backend/NuDBFactory.cpp b/src/xrpld/nodestore/backend/NuDBFactory.cpp similarity index 100% rename from src/ripple/nodestore/backend/NuDBFactory.cpp rename to src/xrpld/nodestore/backend/NuDBFactory.cpp diff --git a/src/ripple/nodestore/backend/NullFactory.cpp b/src/xrpld/nodestore/backend/NullFactory.cpp similarity index 100% rename from src/ripple/nodestore/backend/NullFactory.cpp rename to src/xrpld/nodestore/backend/NullFactory.cpp diff --git a/src/ripple/nodestore/backend/RocksDBFactory.cpp b/src/xrpld/nodestore/backend/RocksDBFactory.cpp similarity index 100% rename from src/ripple/nodestore/backend/RocksDBFactory.cpp rename to src/xrpld/nodestore/backend/RocksDBFactory.cpp diff --git a/src/ripple/nodestore/impl/BatchWriter.cpp b/src/xrpld/nodestore/detail/BatchWriter.cpp similarity index 100% rename from src/ripple/nodestore/impl/BatchWriter.cpp rename to src/xrpld/nodestore/detail/BatchWriter.cpp diff --git a/src/ripple/nodestore/impl/BatchWriter.h b/src/xrpld/nodestore/detail/BatchWriter.h similarity index 100% rename from src/ripple/nodestore/impl/BatchWriter.h rename to src/xrpld/nodestore/detail/BatchWriter.h diff --git a/src/ripple/nodestore/impl/Database.cpp b/src/xrpld/nodestore/detail/Database.cpp similarity index 100% rename from src/ripple/nodestore/impl/Database.cpp rename to src/xrpld/nodestore/detail/Database.cpp diff --git a/src/ripple/nodestore/impl/DatabaseNodeImp.cpp b/src/xrpld/nodestore/detail/DatabaseNodeImp.cpp similarity index 100% rename from src/ripple/nodestore/impl/DatabaseNodeImp.cpp rename to src/xrpld/nodestore/detail/DatabaseNodeImp.cpp diff --git a/src/ripple/nodestore/impl/DatabaseNodeImp.h b/src/xrpld/nodestore/detail/DatabaseNodeImp.h similarity index 100% rename from src/ripple/nodestore/impl/DatabaseNodeImp.h rename to src/xrpld/nodestore/detail/DatabaseNodeImp.h diff --git a/src/ripple/nodestore/impl/DatabaseRotatingImp.cpp b/src/xrpld/nodestore/detail/DatabaseRotatingImp.cpp similarity index 100% rename from src/ripple/nodestore/impl/DatabaseRotatingImp.cpp rename to src/xrpld/nodestore/detail/DatabaseRotatingImp.cpp diff --git a/src/ripple/nodestore/impl/DatabaseRotatingImp.h b/src/xrpld/nodestore/detail/DatabaseRotatingImp.h similarity index 100% rename from src/ripple/nodestore/impl/DatabaseRotatingImp.h rename to src/xrpld/nodestore/detail/DatabaseRotatingImp.h diff --git a/src/ripple/nodestore/impl/DatabaseShardImp.cpp b/src/xrpld/nodestore/detail/DatabaseShardImp.cpp similarity index 100% rename from src/ripple/nodestore/impl/DatabaseShardImp.cpp rename to src/xrpld/nodestore/detail/DatabaseShardImp.cpp diff --git a/src/ripple/nodestore/impl/DatabaseShardImp.h b/src/xrpld/nodestore/detail/DatabaseShardImp.h similarity index 100% rename from src/ripple/nodestore/impl/DatabaseShardImp.h rename to src/xrpld/nodestore/detail/DatabaseShardImp.h diff --git a/src/ripple/nodestore/impl/DecodedBlob.cpp b/src/xrpld/nodestore/detail/DecodedBlob.cpp similarity index 100% rename from src/ripple/nodestore/impl/DecodedBlob.cpp rename to src/xrpld/nodestore/detail/DecodedBlob.cpp diff --git a/src/ripple/nodestore/impl/DecodedBlob.h b/src/xrpld/nodestore/detail/DecodedBlob.h similarity index 100% rename from src/ripple/nodestore/impl/DecodedBlob.h rename to src/xrpld/nodestore/detail/DecodedBlob.h diff --git a/src/ripple/nodestore/impl/DeterministicShard.cpp b/src/xrpld/nodestore/detail/DeterministicShard.cpp similarity index 100% rename from src/ripple/nodestore/impl/DeterministicShard.cpp rename to src/xrpld/nodestore/detail/DeterministicShard.cpp diff --git a/src/ripple/nodestore/impl/DeterministicShard.h b/src/xrpld/nodestore/detail/DeterministicShard.h similarity index 100% rename from src/ripple/nodestore/impl/DeterministicShard.h rename to src/xrpld/nodestore/detail/DeterministicShard.h diff --git a/src/ripple/nodestore/impl/DummyScheduler.cpp b/src/xrpld/nodestore/detail/DummyScheduler.cpp similarity index 100% rename from src/ripple/nodestore/impl/DummyScheduler.cpp rename to src/xrpld/nodestore/detail/DummyScheduler.cpp diff --git a/src/ripple/nodestore/impl/EncodedBlob.h b/src/xrpld/nodestore/detail/EncodedBlob.h similarity index 100% rename from src/ripple/nodestore/impl/EncodedBlob.h rename to src/xrpld/nodestore/detail/EncodedBlob.h diff --git a/src/ripple/nodestore/impl/ManagerImp.cpp b/src/xrpld/nodestore/detail/ManagerImp.cpp similarity index 100% rename from src/ripple/nodestore/impl/ManagerImp.cpp rename to src/xrpld/nodestore/detail/ManagerImp.cpp diff --git a/src/ripple/nodestore/impl/ManagerImp.h b/src/xrpld/nodestore/detail/ManagerImp.h similarity index 100% rename from src/ripple/nodestore/impl/ManagerImp.h rename to src/xrpld/nodestore/detail/ManagerImp.h diff --git a/src/ripple/nodestore/impl/NodeObject.cpp b/src/xrpld/nodestore/detail/NodeObject.cpp similarity index 100% rename from src/ripple/nodestore/impl/NodeObject.cpp rename to src/xrpld/nodestore/detail/NodeObject.cpp diff --git a/src/ripple/nodestore/impl/Shard.cpp b/src/xrpld/nodestore/detail/Shard.cpp similarity index 100% rename from src/ripple/nodestore/impl/Shard.cpp rename to src/xrpld/nodestore/detail/Shard.cpp diff --git a/src/ripple/nodestore/impl/Shard.h b/src/xrpld/nodestore/detail/Shard.h similarity index 100% rename from src/ripple/nodestore/impl/Shard.h rename to src/xrpld/nodestore/detail/Shard.h diff --git a/src/ripple/nodestore/impl/ShardInfo.cpp b/src/xrpld/nodestore/detail/ShardInfo.cpp similarity index 100% rename from src/ripple/nodestore/impl/ShardInfo.cpp rename to src/xrpld/nodestore/detail/ShardInfo.cpp diff --git a/src/ripple/nodestore/impl/TaskQueue.cpp b/src/xrpld/nodestore/detail/TaskQueue.cpp similarity index 100% rename from src/ripple/nodestore/impl/TaskQueue.cpp rename to src/xrpld/nodestore/detail/TaskQueue.cpp diff --git a/src/ripple/nodestore/impl/TaskQueue.h b/src/xrpld/nodestore/detail/TaskQueue.h similarity index 100% rename from src/ripple/nodestore/impl/TaskQueue.h rename to src/xrpld/nodestore/detail/TaskQueue.h diff --git a/src/ripple/nodestore/impl/codec.h b/src/xrpld/nodestore/detail/codec.h similarity index 100% rename from src/ripple/nodestore/impl/codec.h rename to src/xrpld/nodestore/detail/codec.h diff --git a/src/ripple/nodestore/impl/varint.h b/src/xrpld/nodestore/detail/varint.h similarity index 100% rename from src/ripple/nodestore/impl/varint.h rename to src/xrpld/nodestore/detail/varint.h diff --git a/src/ripple/overlay/Cluster.h b/src/xrpld/overlay/Cluster.h similarity index 100% rename from src/ripple/overlay/Cluster.h rename to src/xrpld/overlay/Cluster.h diff --git a/src/ripple/overlay/ClusterNode.h b/src/xrpld/overlay/ClusterNode.h similarity index 100% rename from src/ripple/overlay/ClusterNode.h rename to src/xrpld/overlay/ClusterNode.h diff --git a/src/ripple/overlay/Compression.h b/src/xrpld/overlay/Compression.h similarity index 100% rename from src/ripple/overlay/Compression.h rename to src/xrpld/overlay/Compression.h diff --git a/src/ripple/overlay/Message.h b/src/xrpld/overlay/Message.h similarity index 100% rename from src/ripple/overlay/Message.h rename to src/xrpld/overlay/Message.h diff --git a/src/ripple/overlay/Overlay.h b/src/xrpld/overlay/Overlay.h similarity index 100% rename from src/ripple/overlay/Overlay.h rename to src/xrpld/overlay/Overlay.h diff --git a/src/ripple/overlay/Peer.h b/src/xrpld/overlay/Peer.h similarity index 100% rename from src/ripple/overlay/Peer.h rename to src/xrpld/overlay/Peer.h diff --git a/src/ripple/overlay/PeerReservationTable.h b/src/xrpld/overlay/PeerReservationTable.h similarity index 100% rename from src/ripple/overlay/PeerReservationTable.h rename to src/xrpld/overlay/PeerReservationTable.h diff --git a/src/ripple/overlay/PeerSet.h b/src/xrpld/overlay/PeerSet.h similarity index 100% rename from src/ripple/overlay/PeerSet.h rename to src/xrpld/overlay/PeerSet.h diff --git a/src/ripple/overlay/README.md b/src/xrpld/overlay/README.md similarity index 100% rename from src/ripple/overlay/README.md rename to src/xrpld/overlay/README.md diff --git a/src/ripple/overlay/ReduceRelayCommon.h b/src/xrpld/overlay/ReduceRelayCommon.h similarity index 100% rename from src/ripple/overlay/ReduceRelayCommon.h rename to src/xrpld/overlay/ReduceRelayCommon.h diff --git a/src/ripple/overlay/Slot.h b/src/xrpld/overlay/Slot.h similarity index 100% rename from src/ripple/overlay/Slot.h rename to src/xrpld/overlay/Slot.h diff --git a/src/ripple/overlay/Squelch.h b/src/xrpld/overlay/Squelch.h similarity index 100% rename from src/ripple/overlay/Squelch.h rename to src/xrpld/overlay/Squelch.h diff --git a/src/ripple/overlay/impl/Cluster.cpp b/src/xrpld/overlay/detail/Cluster.cpp similarity index 100% rename from src/ripple/overlay/impl/Cluster.cpp rename to src/xrpld/overlay/detail/Cluster.cpp diff --git a/src/ripple/overlay/impl/ConnectAttempt.cpp b/src/xrpld/overlay/detail/ConnectAttempt.cpp similarity index 100% rename from src/ripple/overlay/impl/ConnectAttempt.cpp rename to src/xrpld/overlay/detail/ConnectAttempt.cpp diff --git a/src/ripple/overlay/impl/ConnectAttempt.h b/src/xrpld/overlay/detail/ConnectAttempt.h similarity index 100% rename from src/ripple/overlay/impl/ConnectAttempt.h rename to src/xrpld/overlay/detail/ConnectAttempt.h diff --git a/src/ripple/overlay/impl/Handshake.cpp b/src/xrpld/overlay/detail/Handshake.cpp similarity index 100% rename from src/ripple/overlay/impl/Handshake.cpp rename to src/xrpld/overlay/detail/Handshake.cpp diff --git a/src/ripple/overlay/impl/Handshake.h b/src/xrpld/overlay/detail/Handshake.h similarity index 100% rename from src/ripple/overlay/impl/Handshake.h rename to src/xrpld/overlay/detail/Handshake.h diff --git a/src/ripple/overlay/impl/Message.cpp b/src/xrpld/overlay/detail/Message.cpp similarity index 100% rename from src/ripple/overlay/impl/Message.cpp rename to src/xrpld/overlay/detail/Message.cpp diff --git a/src/ripple/overlay/impl/OverlayImpl.cpp b/src/xrpld/overlay/detail/OverlayImpl.cpp similarity index 100% rename from src/ripple/overlay/impl/OverlayImpl.cpp rename to src/xrpld/overlay/detail/OverlayImpl.cpp diff --git a/src/ripple/overlay/impl/OverlayImpl.h b/src/xrpld/overlay/detail/OverlayImpl.h similarity index 100% rename from src/ripple/overlay/impl/OverlayImpl.h rename to src/xrpld/overlay/detail/OverlayImpl.h diff --git a/src/ripple/overlay/impl/PeerImp.cpp b/src/xrpld/overlay/detail/PeerImp.cpp similarity index 100% rename from src/ripple/overlay/impl/PeerImp.cpp rename to src/xrpld/overlay/detail/PeerImp.cpp diff --git a/src/ripple/overlay/impl/PeerImp.h b/src/xrpld/overlay/detail/PeerImp.h similarity index 100% rename from src/ripple/overlay/impl/PeerImp.h rename to src/xrpld/overlay/detail/PeerImp.h diff --git a/src/ripple/overlay/impl/PeerReservationTable.cpp b/src/xrpld/overlay/detail/PeerReservationTable.cpp similarity index 100% rename from src/ripple/overlay/impl/PeerReservationTable.cpp rename to src/xrpld/overlay/detail/PeerReservationTable.cpp diff --git a/src/ripple/overlay/impl/PeerSet.cpp b/src/xrpld/overlay/detail/PeerSet.cpp similarity index 100% rename from src/ripple/overlay/impl/PeerSet.cpp rename to src/xrpld/overlay/detail/PeerSet.cpp diff --git a/src/ripple/overlay/impl/ProtocolMessage.h b/src/xrpld/overlay/detail/ProtocolMessage.h similarity index 100% rename from src/ripple/overlay/impl/ProtocolMessage.h rename to src/xrpld/overlay/detail/ProtocolMessage.h diff --git a/src/ripple/overlay/impl/ProtocolVersion.cpp b/src/xrpld/overlay/detail/ProtocolVersion.cpp similarity index 100% rename from src/ripple/overlay/impl/ProtocolVersion.cpp rename to src/xrpld/overlay/detail/ProtocolVersion.cpp diff --git a/src/ripple/overlay/impl/ProtocolVersion.h b/src/xrpld/overlay/detail/ProtocolVersion.h similarity index 100% rename from src/ripple/overlay/impl/ProtocolVersion.h rename to src/xrpld/overlay/detail/ProtocolVersion.h diff --git a/src/ripple/overlay/impl/TrafficCount.cpp b/src/xrpld/overlay/detail/TrafficCount.cpp similarity index 100% rename from src/ripple/overlay/impl/TrafficCount.cpp rename to src/xrpld/overlay/detail/TrafficCount.cpp diff --git a/src/ripple/overlay/impl/TrafficCount.h b/src/xrpld/overlay/detail/TrafficCount.h similarity index 100% rename from src/ripple/overlay/impl/TrafficCount.h rename to src/xrpld/overlay/detail/TrafficCount.h diff --git a/src/ripple/overlay/impl/Tuning.h b/src/xrpld/overlay/detail/Tuning.h similarity index 100% rename from src/ripple/overlay/impl/Tuning.h rename to src/xrpld/overlay/detail/Tuning.h diff --git a/src/ripple/overlay/impl/TxMetrics.cpp b/src/xrpld/overlay/detail/TxMetrics.cpp similarity index 100% rename from src/ripple/overlay/impl/TxMetrics.cpp rename to src/xrpld/overlay/detail/TxMetrics.cpp diff --git a/src/ripple/overlay/impl/TxMetrics.h b/src/xrpld/overlay/detail/TxMetrics.h similarity index 100% rename from src/ripple/overlay/impl/TxMetrics.h rename to src/xrpld/overlay/detail/TxMetrics.h diff --git a/src/ripple/overlay/impl/ZeroCopyStream.h b/src/xrpld/overlay/detail/ZeroCopyStream.h similarity index 100% rename from src/ripple/overlay/impl/ZeroCopyStream.h rename to src/xrpld/overlay/detail/ZeroCopyStream.h diff --git a/src/ripple/overlay/make_Overlay.h b/src/xrpld/overlay/make_Overlay.h similarity index 100% rename from src/ripple/overlay/make_Overlay.h rename to src/xrpld/overlay/make_Overlay.h diff --git a/src/ripple/overlay/predicates.h b/src/xrpld/overlay/predicates.h similarity index 100% rename from src/ripple/overlay/predicates.h rename to src/xrpld/overlay/predicates.h diff --git a/src/ripple/peerfinder/PeerfinderManager.h b/src/xrpld/peerfinder/PeerfinderManager.h similarity index 100% rename from src/ripple/peerfinder/PeerfinderManager.h rename to src/xrpld/peerfinder/PeerfinderManager.h diff --git a/src/ripple/peerfinder/README.md b/src/xrpld/peerfinder/README.md similarity index 100% rename from src/ripple/peerfinder/README.md rename to src/xrpld/peerfinder/README.md diff --git a/src/ripple/peerfinder/Slot.h b/src/xrpld/peerfinder/Slot.h similarity index 100% rename from src/ripple/peerfinder/Slot.h rename to src/xrpld/peerfinder/Slot.h diff --git a/src/ripple/peerfinder/impl/Bootcache.cpp b/src/xrpld/peerfinder/detail/Bootcache.cpp similarity index 100% rename from src/ripple/peerfinder/impl/Bootcache.cpp rename to src/xrpld/peerfinder/detail/Bootcache.cpp diff --git a/src/ripple/peerfinder/impl/Bootcache.h b/src/xrpld/peerfinder/detail/Bootcache.h similarity index 100% rename from src/ripple/peerfinder/impl/Bootcache.h rename to src/xrpld/peerfinder/detail/Bootcache.h diff --git a/src/ripple/peerfinder/impl/Checker.h b/src/xrpld/peerfinder/detail/Checker.h similarity index 100% rename from src/ripple/peerfinder/impl/Checker.h rename to src/xrpld/peerfinder/detail/Checker.h diff --git a/src/ripple/peerfinder/impl/Counts.h b/src/xrpld/peerfinder/detail/Counts.h similarity index 100% rename from src/ripple/peerfinder/impl/Counts.h rename to src/xrpld/peerfinder/detail/Counts.h diff --git a/src/ripple/peerfinder/impl/Endpoint.cpp b/src/xrpld/peerfinder/detail/Endpoint.cpp similarity index 100% rename from src/ripple/peerfinder/impl/Endpoint.cpp rename to src/xrpld/peerfinder/detail/Endpoint.cpp diff --git a/src/ripple/peerfinder/impl/Fixed.h b/src/xrpld/peerfinder/detail/Fixed.h similarity index 100% rename from src/ripple/peerfinder/impl/Fixed.h rename to src/xrpld/peerfinder/detail/Fixed.h diff --git a/src/ripple/peerfinder/impl/Handouts.h b/src/xrpld/peerfinder/detail/Handouts.h similarity index 100% rename from src/ripple/peerfinder/impl/Handouts.h rename to src/xrpld/peerfinder/detail/Handouts.h diff --git a/src/ripple/peerfinder/impl/Livecache.h b/src/xrpld/peerfinder/detail/Livecache.h similarity index 100% rename from src/ripple/peerfinder/impl/Livecache.h rename to src/xrpld/peerfinder/detail/Livecache.h diff --git a/src/ripple/peerfinder/impl/Logic.h b/src/xrpld/peerfinder/detail/Logic.h similarity index 100% rename from src/ripple/peerfinder/impl/Logic.h rename to src/xrpld/peerfinder/detail/Logic.h diff --git a/src/ripple/peerfinder/impl/PeerfinderConfig.cpp b/src/xrpld/peerfinder/detail/PeerfinderConfig.cpp similarity index 100% rename from src/ripple/peerfinder/impl/PeerfinderConfig.cpp rename to src/xrpld/peerfinder/detail/PeerfinderConfig.cpp diff --git a/src/ripple/peerfinder/impl/PeerfinderManager.cpp b/src/xrpld/peerfinder/detail/PeerfinderManager.cpp similarity index 100% rename from src/ripple/peerfinder/impl/PeerfinderManager.cpp rename to src/xrpld/peerfinder/detail/PeerfinderManager.cpp diff --git a/src/ripple/peerfinder/impl/Reporting.h b/src/xrpld/peerfinder/detail/Reporting.h similarity index 100% rename from src/ripple/peerfinder/impl/Reporting.h rename to src/xrpld/peerfinder/detail/Reporting.h diff --git a/src/ripple/peerfinder/impl/SlotImp.cpp b/src/xrpld/peerfinder/detail/SlotImp.cpp similarity index 100% rename from src/ripple/peerfinder/impl/SlotImp.cpp rename to src/xrpld/peerfinder/detail/SlotImp.cpp diff --git a/src/ripple/peerfinder/impl/SlotImp.h b/src/xrpld/peerfinder/detail/SlotImp.h similarity index 100% rename from src/ripple/peerfinder/impl/SlotImp.h rename to src/xrpld/peerfinder/detail/SlotImp.h diff --git a/src/ripple/peerfinder/impl/Source.h b/src/xrpld/peerfinder/detail/Source.h similarity index 100% rename from src/ripple/peerfinder/impl/Source.h rename to src/xrpld/peerfinder/detail/Source.h diff --git a/src/ripple/peerfinder/impl/SourceStrings.cpp b/src/xrpld/peerfinder/detail/SourceStrings.cpp similarity index 100% rename from src/ripple/peerfinder/impl/SourceStrings.cpp rename to src/xrpld/peerfinder/detail/SourceStrings.cpp diff --git a/src/ripple/peerfinder/impl/SourceStrings.h b/src/xrpld/peerfinder/detail/SourceStrings.h similarity index 100% rename from src/ripple/peerfinder/impl/SourceStrings.h rename to src/xrpld/peerfinder/detail/SourceStrings.h diff --git a/src/ripple/peerfinder/impl/Store.h b/src/xrpld/peerfinder/detail/Store.h similarity index 100% rename from src/ripple/peerfinder/impl/Store.h rename to src/xrpld/peerfinder/detail/Store.h diff --git a/src/ripple/peerfinder/impl/StoreSqdb.h b/src/xrpld/peerfinder/detail/StoreSqdb.h similarity index 100% rename from src/ripple/peerfinder/impl/StoreSqdb.h rename to src/xrpld/peerfinder/detail/StoreSqdb.h diff --git a/src/ripple/peerfinder/impl/Tuning.h b/src/xrpld/peerfinder/detail/Tuning.h similarity index 100% rename from src/ripple/peerfinder/impl/Tuning.h rename to src/xrpld/peerfinder/detail/Tuning.h diff --git a/src/ripple/peerfinder/impl/iosformat.h b/src/xrpld/peerfinder/detail/iosformat.h similarity index 100% rename from src/ripple/peerfinder/impl/iosformat.h rename to src/xrpld/peerfinder/detail/iosformat.h diff --git a/src/ripple/peerfinder/make_Manager.h b/src/xrpld/peerfinder/make_Manager.h similarity index 100% rename from src/ripple/peerfinder/make_Manager.h rename to src/xrpld/peerfinder/make_Manager.h diff --git a/src/ripple/peerfinder/sim/FunctionQueue.h b/src/xrpld/peerfinder/sim/FunctionQueue.h similarity index 100% rename from src/ripple/peerfinder/sim/FunctionQueue.h rename to src/xrpld/peerfinder/sim/FunctionQueue.h diff --git a/src/ripple/peerfinder/sim/GraphAlgorithms.h b/src/xrpld/peerfinder/sim/GraphAlgorithms.h similarity index 100% rename from src/ripple/peerfinder/sim/GraphAlgorithms.h rename to src/xrpld/peerfinder/sim/GraphAlgorithms.h diff --git a/src/ripple/peerfinder/sim/Message.h b/src/xrpld/peerfinder/sim/Message.h similarity index 100% rename from src/ripple/peerfinder/sim/Message.h rename to src/xrpld/peerfinder/sim/Message.h diff --git a/src/ripple/peerfinder/sim/NodeSnapshot.h b/src/xrpld/peerfinder/sim/NodeSnapshot.h similarity index 100% rename from src/ripple/peerfinder/sim/NodeSnapshot.h rename to src/xrpld/peerfinder/sim/NodeSnapshot.h diff --git a/src/ripple/peerfinder/sim/Params.h b/src/xrpld/peerfinder/sim/Params.h similarity index 100% rename from src/ripple/peerfinder/sim/Params.h rename to src/xrpld/peerfinder/sim/Params.h diff --git a/src/ripple/peerfinder/sim/Predicates.h b/src/xrpld/peerfinder/sim/Predicates.h similarity index 100% rename from src/ripple/peerfinder/sim/Predicates.h rename to src/xrpld/peerfinder/sim/Predicates.h diff --git a/src/ripple/basics/PerfLog.h b/src/xrpld/perflog/PerfLog.h similarity index 100% rename from src/ripple/basics/PerfLog.h rename to src/xrpld/perflog/PerfLog.h diff --git a/src/ripple/perflog/impl/PerfLogImp.cpp b/src/xrpld/perflog/detail/PerfLogImp.cpp similarity index 100% rename from src/ripple/perflog/impl/PerfLogImp.cpp rename to src/xrpld/perflog/detail/PerfLogImp.cpp diff --git a/src/ripple/perflog/impl/PerfLogImp.h b/src/xrpld/perflog/detail/PerfLogImp.h similarity index 100% rename from src/ripple/perflog/impl/PerfLogImp.h rename to src/xrpld/perflog/detail/PerfLogImp.h diff --git a/src/ripple/rpc/BookChanges.h b/src/xrpld/rpc/BookChanges.h similarity index 100% rename from src/ripple/rpc/BookChanges.h rename to src/xrpld/rpc/BookChanges.h diff --git a/src/ripple/rpc/CTID.h b/src/xrpld/rpc/CTID.h similarity index 100% rename from src/ripple/rpc/CTID.h rename to src/xrpld/rpc/CTID.h diff --git a/src/ripple/rpc/Context.h b/src/xrpld/rpc/Context.h similarity index 100% rename from src/ripple/rpc/Context.h rename to src/xrpld/rpc/Context.h diff --git a/src/ripple/rpc/DeliveredAmount.h b/src/xrpld/rpc/DeliveredAmount.h similarity index 100% rename from src/ripple/rpc/DeliveredAmount.h rename to src/xrpld/rpc/DeliveredAmount.h diff --git a/src/ripple/rpc/GRPCHandlers.h b/src/xrpld/rpc/GRPCHandlers.h similarity index 100% rename from src/ripple/rpc/GRPCHandlers.h rename to src/xrpld/rpc/GRPCHandlers.h diff --git a/src/ripple/rpc/Output.h b/src/xrpld/rpc/Output.h similarity index 100% rename from src/ripple/rpc/Output.h rename to src/xrpld/rpc/Output.h diff --git a/src/ripple/rpc/README.md b/src/xrpld/rpc/README.md similarity index 100% rename from src/ripple/rpc/README.md rename to src/xrpld/rpc/README.md diff --git a/src/ripple/rpc/RPCHandler.h b/src/xrpld/rpc/RPCHandler.h similarity index 100% rename from src/ripple/rpc/RPCHandler.h rename to src/xrpld/rpc/RPCHandler.h diff --git a/src/ripple/rpc/Request.h b/src/xrpld/rpc/Request.h similarity index 100% rename from src/ripple/rpc/Request.h rename to src/xrpld/rpc/Request.h diff --git a/src/ripple/rpc/Role.h b/src/xrpld/rpc/Role.h similarity index 100% rename from src/ripple/rpc/Role.h rename to src/xrpld/rpc/Role.h diff --git a/src/ripple/rpc/ServerHandler.h b/src/xrpld/rpc/ServerHandler.h similarity index 100% rename from src/ripple/rpc/ServerHandler.h rename to src/xrpld/rpc/ServerHandler.h diff --git a/src/ripple/rpc/ShardArchiveHandler.h b/src/xrpld/rpc/ShardArchiveHandler.h similarity index 100% rename from src/ripple/rpc/ShardArchiveHandler.h rename to src/xrpld/rpc/ShardArchiveHandler.h diff --git a/src/ripple/rpc/ShardVerificationScheduler.h b/src/xrpld/rpc/ShardVerificationScheduler.h similarity index 100% rename from src/ripple/rpc/ShardVerificationScheduler.h rename to src/xrpld/rpc/ShardVerificationScheduler.h diff --git a/src/ripple/rpc/Status.h b/src/xrpld/rpc/Status.h similarity index 100% rename from src/ripple/rpc/Status.h rename to src/xrpld/rpc/Status.h diff --git a/src/ripple/rpc/impl/DeliveredAmount.cpp b/src/xrpld/rpc/detail/DeliveredAmount.cpp similarity index 100% rename from src/ripple/rpc/impl/DeliveredAmount.cpp rename to src/xrpld/rpc/detail/DeliveredAmount.cpp diff --git a/src/ripple/rpc/impl/Handler.cpp b/src/xrpld/rpc/detail/Handler.cpp similarity index 100% rename from src/ripple/rpc/impl/Handler.cpp rename to src/xrpld/rpc/detail/Handler.cpp diff --git a/src/ripple/rpc/impl/Handler.h b/src/xrpld/rpc/detail/Handler.h similarity index 100% rename from src/ripple/rpc/impl/Handler.h rename to src/xrpld/rpc/detail/Handler.h diff --git a/src/ripple/rpc/impl/LegacyPathFind.cpp b/src/xrpld/rpc/detail/LegacyPathFind.cpp similarity index 100% rename from src/ripple/rpc/impl/LegacyPathFind.cpp rename to src/xrpld/rpc/detail/LegacyPathFind.cpp diff --git a/src/ripple/rpc/impl/LegacyPathFind.h b/src/xrpld/rpc/detail/LegacyPathFind.h similarity index 100% rename from src/ripple/rpc/impl/LegacyPathFind.h rename to src/xrpld/rpc/detail/LegacyPathFind.h diff --git a/src/ripple/rpc/impl/RPCHandler.cpp b/src/xrpld/rpc/detail/RPCHandler.cpp similarity index 100% rename from src/ripple/rpc/impl/RPCHandler.cpp rename to src/xrpld/rpc/detail/RPCHandler.cpp diff --git a/src/ripple/rpc/impl/RPCHelpers.cpp b/src/xrpld/rpc/detail/RPCHelpers.cpp similarity index 100% rename from src/ripple/rpc/impl/RPCHelpers.cpp rename to src/xrpld/rpc/detail/RPCHelpers.cpp diff --git a/src/ripple/rpc/impl/RPCHelpers.h b/src/xrpld/rpc/detail/RPCHelpers.h similarity index 100% rename from src/ripple/rpc/impl/RPCHelpers.h rename to src/xrpld/rpc/detail/RPCHelpers.h diff --git a/src/ripple/rpc/impl/Role.cpp b/src/xrpld/rpc/detail/Role.cpp similarity index 100% rename from src/ripple/rpc/impl/Role.cpp rename to src/xrpld/rpc/detail/Role.cpp diff --git a/src/ripple/rpc/impl/ServerHandler.cpp b/src/xrpld/rpc/detail/ServerHandler.cpp similarity index 100% rename from src/ripple/rpc/impl/ServerHandler.cpp rename to src/xrpld/rpc/detail/ServerHandler.cpp diff --git a/src/ripple/rpc/impl/ShardArchiveHandler.cpp b/src/xrpld/rpc/detail/ShardArchiveHandler.cpp similarity index 100% rename from src/ripple/rpc/impl/ShardArchiveHandler.cpp rename to src/xrpld/rpc/detail/ShardArchiveHandler.cpp diff --git a/src/ripple/rpc/impl/ShardVerificationScheduler.cpp b/src/xrpld/rpc/detail/ShardVerificationScheduler.cpp similarity index 100% rename from src/ripple/rpc/impl/ShardVerificationScheduler.cpp rename to src/xrpld/rpc/detail/ShardVerificationScheduler.cpp diff --git a/src/ripple/rpc/impl/Status.cpp b/src/xrpld/rpc/detail/Status.cpp similarity index 100% rename from src/ripple/rpc/impl/Status.cpp rename to src/xrpld/rpc/detail/Status.cpp diff --git a/src/ripple/rpc/impl/TransactionSign.cpp b/src/xrpld/rpc/detail/TransactionSign.cpp similarity index 100% rename from src/ripple/rpc/impl/TransactionSign.cpp rename to src/xrpld/rpc/detail/TransactionSign.cpp diff --git a/src/ripple/rpc/impl/TransactionSign.h b/src/xrpld/rpc/detail/TransactionSign.h similarity index 100% rename from src/ripple/rpc/impl/TransactionSign.h rename to src/xrpld/rpc/detail/TransactionSign.h diff --git a/src/ripple/rpc/impl/Tuning.h b/src/xrpld/rpc/detail/Tuning.h similarity index 100% rename from src/ripple/rpc/impl/Tuning.h rename to src/xrpld/rpc/detail/Tuning.h diff --git a/src/ripple/rpc/impl/WSInfoSub.h b/src/xrpld/rpc/detail/WSInfoSub.h similarity index 100% rename from src/ripple/rpc/impl/WSInfoSub.h rename to src/xrpld/rpc/detail/WSInfoSub.h diff --git a/src/ripple/rpc/handlers/AMMInfo.cpp b/src/xrpld/rpc/handlers/AMMInfo.cpp similarity index 100% rename from src/ripple/rpc/handlers/AMMInfo.cpp rename to src/xrpld/rpc/handlers/AMMInfo.cpp diff --git a/src/ripple/rpc/handlers/AccountChannels.cpp b/src/xrpld/rpc/handlers/AccountChannels.cpp similarity index 100% rename from src/ripple/rpc/handlers/AccountChannels.cpp rename to src/xrpld/rpc/handlers/AccountChannels.cpp diff --git a/src/ripple/rpc/handlers/AccountCurrenciesHandler.cpp b/src/xrpld/rpc/handlers/AccountCurrenciesHandler.cpp similarity index 100% rename from src/ripple/rpc/handlers/AccountCurrenciesHandler.cpp rename to src/xrpld/rpc/handlers/AccountCurrenciesHandler.cpp diff --git a/src/ripple/rpc/handlers/AccountInfo.cpp b/src/xrpld/rpc/handlers/AccountInfo.cpp similarity index 100% rename from src/ripple/rpc/handlers/AccountInfo.cpp rename to src/xrpld/rpc/handlers/AccountInfo.cpp diff --git a/src/ripple/rpc/handlers/AccountLines.cpp b/src/xrpld/rpc/handlers/AccountLines.cpp similarity index 100% rename from src/ripple/rpc/handlers/AccountLines.cpp rename to src/xrpld/rpc/handlers/AccountLines.cpp diff --git a/src/ripple/rpc/handlers/AccountObjects.cpp b/src/xrpld/rpc/handlers/AccountObjects.cpp similarity index 100% rename from src/ripple/rpc/handlers/AccountObjects.cpp rename to src/xrpld/rpc/handlers/AccountObjects.cpp diff --git a/src/ripple/rpc/handlers/AccountOffers.cpp b/src/xrpld/rpc/handlers/AccountOffers.cpp similarity index 100% rename from src/ripple/rpc/handlers/AccountOffers.cpp rename to src/xrpld/rpc/handlers/AccountOffers.cpp diff --git a/src/ripple/rpc/handlers/AccountTx.cpp b/src/xrpld/rpc/handlers/AccountTx.cpp similarity index 100% rename from src/ripple/rpc/handlers/AccountTx.cpp rename to src/xrpld/rpc/handlers/AccountTx.cpp diff --git a/src/ripple/rpc/handlers/BlackList.cpp b/src/xrpld/rpc/handlers/BlackList.cpp similarity index 100% rename from src/ripple/rpc/handlers/BlackList.cpp rename to src/xrpld/rpc/handlers/BlackList.cpp diff --git a/src/ripple/rpc/handlers/BookOffers.cpp b/src/xrpld/rpc/handlers/BookOffers.cpp similarity index 100% rename from src/ripple/rpc/handlers/BookOffers.cpp rename to src/xrpld/rpc/handlers/BookOffers.cpp diff --git a/src/ripple/rpc/handlers/CanDelete.cpp b/src/xrpld/rpc/handlers/CanDelete.cpp similarity index 100% rename from src/ripple/rpc/handlers/CanDelete.cpp rename to src/xrpld/rpc/handlers/CanDelete.cpp diff --git a/src/ripple/rpc/handlers/Connect.cpp b/src/xrpld/rpc/handlers/Connect.cpp similarity index 100% rename from src/ripple/rpc/handlers/Connect.cpp rename to src/xrpld/rpc/handlers/Connect.cpp diff --git a/src/ripple/rpc/handlers/ConsensusInfo.cpp b/src/xrpld/rpc/handlers/ConsensusInfo.cpp similarity index 100% rename from src/ripple/rpc/handlers/ConsensusInfo.cpp rename to src/xrpld/rpc/handlers/ConsensusInfo.cpp diff --git a/src/ripple/rpc/handlers/CrawlShards.cpp b/src/xrpld/rpc/handlers/CrawlShards.cpp similarity index 100% rename from src/ripple/rpc/handlers/CrawlShards.cpp rename to src/xrpld/rpc/handlers/CrawlShards.cpp diff --git a/src/ripple/rpc/handlers/DepositAuthorized.cpp b/src/xrpld/rpc/handlers/DepositAuthorized.cpp similarity index 100% rename from src/ripple/rpc/handlers/DepositAuthorized.cpp rename to src/xrpld/rpc/handlers/DepositAuthorized.cpp diff --git a/src/ripple/rpc/handlers/DownloadShard.cpp b/src/xrpld/rpc/handlers/DownloadShard.cpp similarity index 100% rename from src/ripple/rpc/handlers/DownloadShard.cpp rename to src/xrpld/rpc/handlers/DownloadShard.cpp diff --git a/src/ripple/rpc/handlers/Feature1.cpp b/src/xrpld/rpc/handlers/Feature1.cpp similarity index 100% rename from src/ripple/rpc/handlers/Feature1.cpp rename to src/xrpld/rpc/handlers/Feature1.cpp diff --git a/src/ripple/rpc/handlers/Fee1.cpp b/src/xrpld/rpc/handlers/Fee1.cpp similarity index 100% rename from src/ripple/rpc/handlers/Fee1.cpp rename to src/xrpld/rpc/handlers/Fee1.cpp diff --git a/src/ripple/rpc/handlers/FetchInfo.cpp b/src/xrpld/rpc/handlers/FetchInfo.cpp similarity index 100% rename from src/ripple/rpc/handlers/FetchInfo.cpp rename to src/xrpld/rpc/handlers/FetchInfo.cpp diff --git a/src/ripple/rpc/handlers/GatewayBalances.cpp b/src/xrpld/rpc/handlers/GatewayBalances.cpp similarity index 100% rename from src/ripple/rpc/handlers/GatewayBalances.cpp rename to src/xrpld/rpc/handlers/GatewayBalances.cpp diff --git a/src/ripple/rpc/handlers/GetAggregatePrice.cpp b/src/xrpld/rpc/handlers/GetAggregatePrice.cpp similarity index 100% rename from src/ripple/rpc/handlers/GetAggregatePrice.cpp rename to src/xrpld/rpc/handlers/GetAggregatePrice.cpp diff --git a/src/ripple/rpc/handlers/GetCounts.cpp b/src/xrpld/rpc/handlers/GetCounts.cpp similarity index 100% rename from src/ripple/rpc/handlers/GetCounts.cpp rename to src/xrpld/rpc/handlers/GetCounts.cpp diff --git a/src/ripple/rpc/handlers/GetCounts.h b/src/xrpld/rpc/handlers/GetCounts.h similarity index 100% rename from src/ripple/rpc/handlers/GetCounts.h rename to src/xrpld/rpc/handlers/GetCounts.h diff --git a/src/ripple/rpc/handlers/Handlers.h b/src/xrpld/rpc/handlers/Handlers.h similarity index 100% rename from src/ripple/rpc/handlers/Handlers.h rename to src/xrpld/rpc/handlers/Handlers.h diff --git a/src/ripple/rpc/handlers/LedgerAccept.cpp b/src/xrpld/rpc/handlers/LedgerAccept.cpp similarity index 100% rename from src/ripple/rpc/handlers/LedgerAccept.cpp rename to src/xrpld/rpc/handlers/LedgerAccept.cpp diff --git a/src/ripple/rpc/handlers/LedgerCleanerHandler.cpp b/src/xrpld/rpc/handlers/LedgerCleanerHandler.cpp similarity index 100% rename from src/ripple/rpc/handlers/LedgerCleanerHandler.cpp rename to src/xrpld/rpc/handlers/LedgerCleanerHandler.cpp diff --git a/src/ripple/rpc/handlers/LedgerClosed.cpp b/src/xrpld/rpc/handlers/LedgerClosed.cpp similarity index 100% rename from src/ripple/rpc/handlers/LedgerClosed.cpp rename to src/xrpld/rpc/handlers/LedgerClosed.cpp diff --git a/src/ripple/rpc/handlers/LedgerCurrent.cpp b/src/xrpld/rpc/handlers/LedgerCurrent.cpp similarity index 100% rename from src/ripple/rpc/handlers/LedgerCurrent.cpp rename to src/xrpld/rpc/handlers/LedgerCurrent.cpp diff --git a/src/ripple/rpc/handlers/LedgerData.cpp b/src/xrpld/rpc/handlers/LedgerData.cpp similarity index 100% rename from src/ripple/rpc/handlers/LedgerData.cpp rename to src/xrpld/rpc/handlers/LedgerData.cpp diff --git a/src/ripple/rpc/handlers/LedgerDiff.cpp b/src/xrpld/rpc/handlers/LedgerDiff.cpp similarity index 100% rename from src/ripple/rpc/handlers/LedgerDiff.cpp rename to src/xrpld/rpc/handlers/LedgerDiff.cpp diff --git a/src/ripple/rpc/handlers/LedgerEntry.cpp b/src/xrpld/rpc/handlers/LedgerEntry.cpp similarity index 100% rename from src/ripple/rpc/handlers/LedgerEntry.cpp rename to src/xrpld/rpc/handlers/LedgerEntry.cpp diff --git a/src/ripple/rpc/handlers/LedgerHandler.cpp b/src/xrpld/rpc/handlers/LedgerHandler.cpp similarity index 100% rename from src/ripple/rpc/handlers/LedgerHandler.cpp rename to src/xrpld/rpc/handlers/LedgerHandler.cpp diff --git a/src/ripple/rpc/handlers/LedgerHandler.h b/src/xrpld/rpc/handlers/LedgerHandler.h similarity index 100% rename from src/ripple/rpc/handlers/LedgerHandler.h rename to src/xrpld/rpc/handlers/LedgerHandler.h diff --git a/src/ripple/rpc/handlers/LedgerHeader.cpp b/src/xrpld/rpc/handlers/LedgerHeader.cpp similarity index 100% rename from src/ripple/rpc/handlers/LedgerHeader.cpp rename to src/xrpld/rpc/handlers/LedgerHeader.cpp diff --git a/src/ripple/rpc/handlers/LedgerRequest.cpp b/src/xrpld/rpc/handlers/LedgerRequest.cpp similarity index 100% rename from src/ripple/rpc/handlers/LedgerRequest.cpp rename to src/xrpld/rpc/handlers/LedgerRequest.cpp diff --git a/src/ripple/rpc/handlers/LogLevel.cpp b/src/xrpld/rpc/handlers/LogLevel.cpp similarity index 100% rename from src/ripple/rpc/handlers/LogLevel.cpp rename to src/xrpld/rpc/handlers/LogLevel.cpp diff --git a/src/ripple/rpc/handlers/LogRotate.cpp b/src/xrpld/rpc/handlers/LogRotate.cpp similarity index 100% rename from src/ripple/rpc/handlers/LogRotate.cpp rename to src/xrpld/rpc/handlers/LogRotate.cpp diff --git a/src/ripple/rpc/handlers/Manifest.cpp b/src/xrpld/rpc/handlers/Manifest.cpp similarity index 100% rename from src/ripple/rpc/handlers/Manifest.cpp rename to src/xrpld/rpc/handlers/Manifest.cpp diff --git a/src/ripple/rpc/handlers/NFTOffers.cpp b/src/xrpld/rpc/handlers/NFTOffers.cpp similarity index 100% rename from src/ripple/rpc/handlers/NFTOffers.cpp rename to src/xrpld/rpc/handlers/NFTOffers.cpp diff --git a/src/ripple/rpc/handlers/NoRippleCheck.cpp b/src/xrpld/rpc/handlers/NoRippleCheck.cpp similarity index 100% rename from src/ripple/rpc/handlers/NoRippleCheck.cpp rename to src/xrpld/rpc/handlers/NoRippleCheck.cpp diff --git a/src/ripple/rpc/handlers/NodeToShard.cpp b/src/xrpld/rpc/handlers/NodeToShard.cpp similarity index 100% rename from src/ripple/rpc/handlers/NodeToShard.cpp rename to src/xrpld/rpc/handlers/NodeToShard.cpp diff --git a/src/ripple/rpc/handlers/OwnerInfo.cpp b/src/xrpld/rpc/handlers/OwnerInfo.cpp similarity index 100% rename from src/ripple/rpc/handlers/OwnerInfo.cpp rename to src/xrpld/rpc/handlers/OwnerInfo.cpp diff --git a/src/ripple/rpc/handlers/PathFind.cpp b/src/xrpld/rpc/handlers/PathFind.cpp similarity index 100% rename from src/ripple/rpc/handlers/PathFind.cpp rename to src/xrpld/rpc/handlers/PathFind.cpp diff --git a/src/ripple/rpc/handlers/PayChanClaim.cpp b/src/xrpld/rpc/handlers/PayChanClaim.cpp similarity index 100% rename from src/ripple/rpc/handlers/PayChanClaim.cpp rename to src/xrpld/rpc/handlers/PayChanClaim.cpp diff --git a/src/ripple/rpc/handlers/Peers.cpp b/src/xrpld/rpc/handlers/Peers.cpp similarity index 100% rename from src/ripple/rpc/handlers/Peers.cpp rename to src/xrpld/rpc/handlers/Peers.cpp diff --git a/src/ripple/rpc/handlers/Ping.cpp b/src/xrpld/rpc/handlers/Ping.cpp similarity index 100% rename from src/ripple/rpc/handlers/Ping.cpp rename to src/xrpld/rpc/handlers/Ping.cpp diff --git a/src/ripple/rpc/handlers/Print.cpp b/src/xrpld/rpc/handlers/Print.cpp similarity index 100% rename from src/ripple/rpc/handlers/Print.cpp rename to src/xrpld/rpc/handlers/Print.cpp diff --git a/src/ripple/rpc/handlers/Random.cpp b/src/xrpld/rpc/handlers/Random.cpp similarity index 100% rename from src/ripple/rpc/handlers/Random.cpp rename to src/xrpld/rpc/handlers/Random.cpp diff --git a/src/ripple/rpc/handlers/Reservations.cpp b/src/xrpld/rpc/handlers/Reservations.cpp similarity index 100% rename from src/ripple/rpc/handlers/Reservations.cpp rename to src/xrpld/rpc/handlers/Reservations.cpp diff --git a/src/ripple/rpc/handlers/RipplePathFind.cpp b/src/xrpld/rpc/handlers/RipplePathFind.cpp similarity index 100% rename from src/ripple/rpc/handlers/RipplePathFind.cpp rename to src/xrpld/rpc/handlers/RipplePathFind.cpp diff --git a/src/ripple/rpc/handlers/ServerInfo.cpp b/src/xrpld/rpc/handlers/ServerInfo.cpp similarity index 100% rename from src/ripple/rpc/handlers/ServerInfo.cpp rename to src/xrpld/rpc/handlers/ServerInfo.cpp diff --git a/src/ripple/rpc/handlers/ServerState.cpp b/src/xrpld/rpc/handlers/ServerState.cpp similarity index 100% rename from src/ripple/rpc/handlers/ServerState.cpp rename to src/xrpld/rpc/handlers/ServerState.cpp diff --git a/src/ripple/rpc/handlers/SignFor.cpp b/src/xrpld/rpc/handlers/SignFor.cpp similarity index 100% rename from src/ripple/rpc/handlers/SignFor.cpp rename to src/xrpld/rpc/handlers/SignFor.cpp diff --git a/src/ripple/rpc/handlers/SignHandler.cpp b/src/xrpld/rpc/handlers/SignHandler.cpp similarity index 100% rename from src/ripple/rpc/handlers/SignHandler.cpp rename to src/xrpld/rpc/handlers/SignHandler.cpp diff --git a/src/ripple/rpc/handlers/Stop.cpp b/src/xrpld/rpc/handlers/Stop.cpp similarity index 100% rename from src/ripple/rpc/handlers/Stop.cpp rename to src/xrpld/rpc/handlers/Stop.cpp diff --git a/src/ripple/rpc/handlers/Submit.cpp b/src/xrpld/rpc/handlers/Submit.cpp similarity index 100% rename from src/ripple/rpc/handlers/Submit.cpp rename to src/xrpld/rpc/handlers/Submit.cpp diff --git a/src/ripple/rpc/handlers/SubmitMultiSigned.cpp b/src/xrpld/rpc/handlers/SubmitMultiSigned.cpp similarity index 100% rename from src/ripple/rpc/handlers/SubmitMultiSigned.cpp rename to src/xrpld/rpc/handlers/SubmitMultiSigned.cpp diff --git a/src/ripple/rpc/handlers/Subscribe.cpp b/src/xrpld/rpc/handlers/Subscribe.cpp similarity index 100% rename from src/ripple/rpc/handlers/Subscribe.cpp rename to src/xrpld/rpc/handlers/Subscribe.cpp diff --git a/src/ripple/rpc/handlers/TransactionEntry.cpp b/src/xrpld/rpc/handlers/TransactionEntry.cpp similarity index 100% rename from src/ripple/rpc/handlers/TransactionEntry.cpp rename to src/xrpld/rpc/handlers/TransactionEntry.cpp diff --git a/src/ripple/rpc/handlers/Tx.cpp b/src/xrpld/rpc/handlers/Tx.cpp similarity index 100% rename from src/ripple/rpc/handlers/Tx.cpp rename to src/xrpld/rpc/handlers/Tx.cpp diff --git a/src/ripple/rpc/handlers/TxHistory.cpp b/src/xrpld/rpc/handlers/TxHistory.cpp similarity index 100% rename from src/ripple/rpc/handlers/TxHistory.cpp rename to src/xrpld/rpc/handlers/TxHistory.cpp diff --git a/src/ripple/rpc/handlers/TxReduceRelay.cpp b/src/xrpld/rpc/handlers/TxReduceRelay.cpp similarity index 100% rename from src/ripple/rpc/handlers/TxReduceRelay.cpp rename to src/xrpld/rpc/handlers/TxReduceRelay.cpp diff --git a/src/ripple/rpc/handlers/UnlList.cpp b/src/xrpld/rpc/handlers/UnlList.cpp similarity index 100% rename from src/ripple/rpc/handlers/UnlList.cpp rename to src/xrpld/rpc/handlers/UnlList.cpp diff --git a/src/ripple/rpc/handlers/Unsubscribe.cpp b/src/xrpld/rpc/handlers/Unsubscribe.cpp similarity index 100% rename from src/ripple/rpc/handlers/Unsubscribe.cpp rename to src/xrpld/rpc/handlers/Unsubscribe.cpp diff --git a/src/ripple/rpc/handlers/ValidationCreate.cpp b/src/xrpld/rpc/handlers/ValidationCreate.cpp similarity index 100% rename from src/ripple/rpc/handlers/ValidationCreate.cpp rename to src/xrpld/rpc/handlers/ValidationCreate.cpp diff --git a/src/ripple/rpc/handlers/ValidatorInfo.cpp b/src/xrpld/rpc/handlers/ValidatorInfo.cpp similarity index 100% rename from src/ripple/rpc/handlers/ValidatorInfo.cpp rename to src/xrpld/rpc/handlers/ValidatorInfo.cpp diff --git a/src/ripple/rpc/handlers/ValidatorListSites.cpp b/src/xrpld/rpc/handlers/ValidatorListSites.cpp similarity index 100% rename from src/ripple/rpc/handlers/ValidatorListSites.cpp rename to src/xrpld/rpc/handlers/ValidatorListSites.cpp diff --git a/src/ripple/rpc/handlers/Validators.cpp b/src/xrpld/rpc/handlers/Validators.cpp similarity index 100% rename from src/ripple/rpc/handlers/Validators.cpp rename to src/xrpld/rpc/handlers/Validators.cpp diff --git a/src/ripple/rpc/handlers/Version.h b/src/xrpld/rpc/handlers/Version.h similarity index 100% rename from src/ripple/rpc/handlers/Version.h rename to src/xrpld/rpc/handlers/Version.h diff --git a/src/ripple/rpc/handlers/WalletPropose.cpp b/src/xrpld/rpc/handlers/WalletPropose.cpp similarity index 100% rename from src/ripple/rpc/handlers/WalletPropose.cpp rename to src/xrpld/rpc/handlers/WalletPropose.cpp diff --git a/src/ripple/rpc/handlers/WalletPropose.h b/src/xrpld/rpc/handlers/WalletPropose.h similarity index 100% rename from src/ripple/rpc/handlers/WalletPropose.h rename to src/xrpld/rpc/handlers/WalletPropose.h diff --git a/src/ripple/rpc/json_body.h b/src/xrpld/rpc/json_body.h similarity index 100% rename from src/ripple/rpc/json_body.h rename to src/xrpld/rpc/json_body.h diff --git a/src/ripple/shamap/Family.h b/src/xrpld/shamap/Family.h similarity index 100% rename from src/ripple/shamap/Family.h rename to src/xrpld/shamap/Family.h diff --git a/src/ripple/shamap/FullBelowCache.h b/src/xrpld/shamap/FullBelowCache.h similarity index 100% rename from src/ripple/shamap/FullBelowCache.h rename to src/xrpld/shamap/FullBelowCache.h diff --git a/src/ripple/shamap/NodeFamily.h b/src/xrpld/shamap/NodeFamily.h similarity index 100% rename from src/ripple/shamap/NodeFamily.h rename to src/xrpld/shamap/NodeFamily.h diff --git a/src/ripple/shamap/README.md b/src/xrpld/shamap/README.md similarity index 100% rename from src/ripple/shamap/README.md rename to src/xrpld/shamap/README.md diff --git a/src/ripple/shamap/SHAMap.h b/src/xrpld/shamap/SHAMap.h similarity index 100% rename from src/ripple/shamap/SHAMap.h rename to src/xrpld/shamap/SHAMap.h diff --git a/src/ripple/shamap/SHAMapAccountStateLeafNode.h b/src/xrpld/shamap/SHAMapAccountStateLeafNode.h similarity index 100% rename from src/ripple/shamap/SHAMapAccountStateLeafNode.h rename to src/xrpld/shamap/SHAMapAccountStateLeafNode.h diff --git a/src/ripple/shamap/SHAMapAddNode.h b/src/xrpld/shamap/SHAMapAddNode.h similarity index 100% rename from src/ripple/shamap/SHAMapAddNode.h rename to src/xrpld/shamap/SHAMapAddNode.h diff --git a/src/ripple/shamap/SHAMapInnerNode.h b/src/xrpld/shamap/SHAMapInnerNode.h similarity index 100% rename from src/ripple/shamap/SHAMapInnerNode.h rename to src/xrpld/shamap/SHAMapInnerNode.h diff --git a/src/ripple/shamap/SHAMapItem.h b/src/xrpld/shamap/SHAMapItem.h similarity index 100% rename from src/ripple/shamap/SHAMapItem.h rename to src/xrpld/shamap/SHAMapItem.h diff --git a/src/ripple/shamap/SHAMapLeafNode.h b/src/xrpld/shamap/SHAMapLeafNode.h similarity index 100% rename from src/ripple/shamap/SHAMapLeafNode.h rename to src/xrpld/shamap/SHAMapLeafNode.h diff --git a/src/ripple/shamap/SHAMapMissingNode.h b/src/xrpld/shamap/SHAMapMissingNode.h similarity index 100% rename from src/ripple/shamap/SHAMapMissingNode.h rename to src/xrpld/shamap/SHAMapMissingNode.h diff --git a/src/ripple/shamap/SHAMapNodeID.h b/src/xrpld/shamap/SHAMapNodeID.h similarity index 100% rename from src/ripple/shamap/SHAMapNodeID.h rename to src/xrpld/shamap/SHAMapNodeID.h diff --git a/src/ripple/shamap/SHAMapSyncFilter.h b/src/xrpld/shamap/SHAMapSyncFilter.h similarity index 100% rename from src/ripple/shamap/SHAMapSyncFilter.h rename to src/xrpld/shamap/SHAMapSyncFilter.h diff --git a/src/ripple/shamap/SHAMapTreeNode.h b/src/xrpld/shamap/SHAMapTreeNode.h similarity index 100% rename from src/ripple/shamap/SHAMapTreeNode.h rename to src/xrpld/shamap/SHAMapTreeNode.h diff --git a/src/ripple/shamap/SHAMapTxLeafNode.h b/src/xrpld/shamap/SHAMapTxLeafNode.h similarity index 100% rename from src/ripple/shamap/SHAMapTxLeafNode.h rename to src/xrpld/shamap/SHAMapTxLeafNode.h diff --git a/src/ripple/shamap/SHAMapTxPlusMetaLeafNode.h b/src/xrpld/shamap/SHAMapTxPlusMetaLeafNode.h similarity index 100% rename from src/ripple/shamap/SHAMapTxPlusMetaLeafNode.h rename to src/xrpld/shamap/SHAMapTxPlusMetaLeafNode.h diff --git a/src/ripple/shamap/ShardFamily.h b/src/xrpld/shamap/ShardFamily.h similarity index 100% rename from src/ripple/shamap/ShardFamily.h rename to src/xrpld/shamap/ShardFamily.h diff --git a/src/ripple/shamap/TreeNodeCache.h b/src/xrpld/shamap/TreeNodeCache.h similarity index 100% rename from src/ripple/shamap/TreeNodeCache.h rename to src/xrpld/shamap/TreeNodeCache.h diff --git a/src/ripple/shamap/impl/NodeFamily.cpp b/src/xrpld/shamap/detail/NodeFamily.cpp similarity index 100% rename from src/ripple/shamap/impl/NodeFamily.cpp rename to src/xrpld/shamap/detail/NodeFamily.cpp diff --git a/src/ripple/shamap/impl/SHAMap.cpp b/src/xrpld/shamap/detail/SHAMap.cpp similarity index 100% rename from src/ripple/shamap/impl/SHAMap.cpp rename to src/xrpld/shamap/detail/SHAMap.cpp diff --git a/src/ripple/shamap/impl/SHAMapDelta.cpp b/src/xrpld/shamap/detail/SHAMapDelta.cpp similarity index 100% rename from src/ripple/shamap/impl/SHAMapDelta.cpp rename to src/xrpld/shamap/detail/SHAMapDelta.cpp diff --git a/src/ripple/shamap/impl/SHAMapInnerNode.cpp b/src/xrpld/shamap/detail/SHAMapInnerNode.cpp similarity index 100% rename from src/ripple/shamap/impl/SHAMapInnerNode.cpp rename to src/xrpld/shamap/detail/SHAMapInnerNode.cpp diff --git a/src/ripple/shamap/impl/SHAMapLeafNode.cpp b/src/xrpld/shamap/detail/SHAMapLeafNode.cpp similarity index 100% rename from src/ripple/shamap/impl/SHAMapLeafNode.cpp rename to src/xrpld/shamap/detail/SHAMapLeafNode.cpp diff --git a/src/ripple/shamap/impl/SHAMapNodeID.cpp b/src/xrpld/shamap/detail/SHAMapNodeID.cpp similarity index 100% rename from src/ripple/shamap/impl/SHAMapNodeID.cpp rename to src/xrpld/shamap/detail/SHAMapNodeID.cpp diff --git a/src/ripple/shamap/impl/SHAMapSync.cpp b/src/xrpld/shamap/detail/SHAMapSync.cpp similarity index 100% rename from src/ripple/shamap/impl/SHAMapSync.cpp rename to src/xrpld/shamap/detail/SHAMapSync.cpp diff --git a/src/ripple/shamap/impl/SHAMapTreeNode.cpp b/src/xrpld/shamap/detail/SHAMapTreeNode.cpp similarity index 100% rename from src/ripple/shamap/impl/SHAMapTreeNode.cpp rename to src/xrpld/shamap/detail/SHAMapTreeNode.cpp diff --git a/src/ripple/shamap/impl/ShardFamily.cpp b/src/xrpld/shamap/detail/ShardFamily.cpp similarity index 100% rename from src/ripple/shamap/impl/ShardFamily.cpp rename to src/xrpld/shamap/detail/ShardFamily.cpp diff --git a/src/ripple/shamap/impl/TaggedPointer.h b/src/xrpld/shamap/detail/TaggedPointer.h similarity index 100% rename from src/ripple/shamap/impl/TaggedPointer.h rename to src/xrpld/shamap/detail/TaggedPointer.h diff --git a/src/ripple/shamap/impl/TaggedPointer.ipp b/src/xrpld/shamap/detail/TaggedPointer.ipp similarity index 100% rename from src/ripple/shamap/impl/TaggedPointer.ipp rename to src/xrpld/shamap/detail/TaggedPointer.ipp diff --git a/src/ripple/unity/rocksdb.h b/src/xrpld/unity/rocksdb.h similarity index 100% rename from src/ripple/unity/rocksdb.h rename to src/xrpld/unity/rocksdb.h From 1d23148e6dd53957fcb6205c07a5c6cd7b64d50c Mon Sep 17 00:00:00 2001 From: Pretty Printer Date: Thu, 20 Jun 2024 09:22:26 -0500 Subject: [PATCH 17/82] Rewrite includes (#4997) --- include/xrpl/basics/BasicConfig.h | 2 +- include/xrpl/basics/Buffer.h | 2 +- include/xrpl/basics/CompressionAlgorithms.h | 2 +- include/xrpl/basics/CountedObject.h | 2 +- include/xrpl/basics/Expected.h | 2 +- include/xrpl/basics/FeeUnits.h | 2 +- include/xrpl/basics/IOUAmount.h | 6 +- include/xrpl/basics/KeyCache.h | 4 +- include/xrpl/basics/Log.h | 4 +- include/xrpl/basics/Number.h | 2 +- include/xrpl/basics/RangeSet.h | 2 +- include/xrpl/basics/Resolver.h | 2 +- include/xrpl/basics/ResolverAsio.h | 4 +- include/xrpl/basics/SHAMapHash.h | 2 +- include/xrpl/basics/SlabAllocator.h | 2 +- include/xrpl/basics/Slice.h | 4 +- include/xrpl/basics/StringUtilities.h | 4 +- include/xrpl/basics/TaggedCache.h | 10 +- include/xrpl/basics/UnorderedContainers.h | 10 +- include/xrpl/basics/XRPAmount.h | 8 +- include/xrpl/basics/base_uint.h | 12 +- include/xrpl/basics/chrono.h | 6 +- include/xrpl/basics/contract.h | 2 +- include/xrpl/basics/hardened_hash.h | 4 +- include/xrpl/basics/random.h | 2 +- include/xrpl/basics/tagged_integer.h | 2 +- include/xrpl/beast/clock/manual_clock.h | 2 +- .../beast/container/aged_container_utility.h | 2 +- include/xrpl/beast/container/aged_map.h | 2 +- include/xrpl/beast/container/aged_multimap.h | 2 +- include/xrpl/beast/container/aged_multiset.h | 2 +- include/xrpl/beast/container/aged_set.h | 2 +- .../xrpl/beast/container/aged_unordered_map.h | 2 +- .../beast/container/aged_unordered_multimap.h | 2 +- .../beast/container/aged_unordered_multiset.h | 2 +- .../xrpl/beast/container/aged_unordered_set.h | 2 +- .../container/detail/aged_ordered_container.h | 10 +- .../detail/aged_unordered_container.h | 10 +- include/xrpl/beast/hash/uhash.h | 4 +- include/xrpl/beast/insight/Collector.h | 10 +- include/xrpl/beast/insight/Counter.h | 2 +- include/xrpl/beast/insight/Event.h | 2 +- include/xrpl/beast/insight/Gauge.h | 2 +- include/xrpl/beast/insight/Group.h | 2 +- include/xrpl/beast/insight/Groups.h | 4 +- include/xrpl/beast/insight/Hook.h | 2 +- include/xrpl/beast/insight/Insight.h | 26 ++-- include/xrpl/beast/insight/Meter.h | 2 +- include/xrpl/beast/insight/NullCollector.h | 2 +- include/xrpl/beast/insight/StatsDCollector.h | 6 +- include/xrpl/beast/net/IPAddress.h | 8 +- include/xrpl/beast/net/IPAddressConversion.h | 2 +- include/xrpl/beast/net/IPAddressV4.h | 2 +- include/xrpl/beast/net/IPEndpoint.h | 6 +- include/xrpl/beast/test/fail_counter.h | 2 +- include/xrpl/beast/test/fail_stream.h | 12 +- include/xrpl/beast/test/pipe_stream.h | 14 +-- include/xrpl/beast/test/string_iostream.h | 10 +- include/xrpl/beast/test/string_istream.h | 8 +- include/xrpl/beast/test/string_ostream.h | 10 +- include/xrpl/beast/unit_test.h | 20 +-- include/xrpl/beast/unit_test/global_suites.h | 2 +- include/xrpl/beast/unit_test/match.h | 2 +- include/xrpl/beast/unit_test/recorder.h | 4 +- include/xrpl/beast/unit_test/reporter.h | 4 +- include/xrpl/beast/unit_test/results.h | 2 +- include/xrpl/beast/unit_test/runner.h | 2 +- include/xrpl/beast/unit_test/suite.h | 4 +- include/xrpl/beast/unit_test/suite_list.h | 4 +- include/xrpl/beast/unit_test/thread.h | 2 +- include/xrpl/beast/utility/PropertyStream.h | 2 +- include/xrpl/beast/utility/WrappedSink.h | 2 +- include/xrpl/json/JsonPropertyStream.h | 4 +- include/xrpl/json/Object.h | 2 +- include/xrpl/json/Writer.h | 8 +- include/xrpl/json/detail/json_assert.h | 2 +- include/xrpl/json/json_reader.h | 4 +- include/xrpl/json/json_value.h | 2 +- include/xrpl/json/json_writer.h | 4 +- include/xrpl/protocol/AMMCore.h | 10 +- include/xrpl/protocol/AccountID.h | 10 +- include/xrpl/protocol/AmountConversions.h | 6 +- include/xrpl/protocol/Book.h | 4 +- include/xrpl/protocol/ErrorCodes.h | 4 +- include/xrpl/protocol/Feature.h | 2 +- include/xrpl/protocol/Fees.h | 2 +- include/xrpl/protocol/HashPrefix.h | 2 +- include/xrpl/protocol/Indexes.h | 18 +-- include/xrpl/protocol/InnerObjectFormats.h | 2 +- include/xrpl/protocol/Issue.h | 4 +- include/xrpl/protocol/Keylet.h | 4 +- include/xrpl/protocol/KnownFormats.h | 6 +- include/xrpl/protocol/LedgerFormats.h | 2 +- include/xrpl/protocol/LedgerHeader.h | 12 +- include/xrpl/protocol/MultiApiJson.h | 4 +- .../xrpl/protocol/NFTSyntheticSerializer.h | 6 +- include/xrpl/protocol/NFTokenID.h | 8 +- include/xrpl/protocol/NFTokenOfferID.h | 8 +- include/xrpl/protocol/PayChan.h | 8 +- include/xrpl/protocol/Protocol.h | 4 +- include/xrpl/protocol/PublicKey.h | 12 +- include/xrpl/protocol/Quality.h | 8 +- include/xrpl/protocol/QualityFunction.h | 6 +- include/xrpl/protocol/RPCErr.h | 2 +- include/xrpl/protocol/Rate.h | 2 +- include/xrpl/protocol/RippleLedgerHash.h | 2 +- include/xrpl/protocol/Rules.h | 6 +- include/xrpl/protocol/SField.h | 4 +- include/xrpl/protocol/SOTemplate.h | 4 +- include/xrpl/protocol/STAccount.h | 6 +- include/xrpl/protocol/STAmount.h | 20 +-- include/xrpl/protocol/STArray.h | 4 +- include/xrpl/protocol/STBase.h | 6 +- include/xrpl/protocol/STBitString.h | 6 +- include/xrpl/protocol/STBlob.h | 8 +- include/xrpl/protocol/STCurrency.h | 10 +- include/xrpl/protocol/STExchange.h | 16 +-- include/xrpl/protocol/STInteger.h | 4 +- include/xrpl/protocol/STIssue.h | 10 +- include/xrpl/protocol/STLedgerEntry.h | 4 +- include/xrpl/protocol/STObject.h | 28 ++--- include/xrpl/protocol/STParsedJSON.h | 2 +- include/xrpl/protocol/STPathSet.h | 10 +- include/xrpl/protocol/STTx.h | 16 +-- include/xrpl/protocol/STValidation.h | 10 +- include/xrpl/protocol/STVector256.h | 8 +- include/xrpl/protocol/STXChainBridge.h | 8 +- include/xrpl/protocol/SecretKey.h | 12 +- include/xrpl/protocol/Seed.h | 6 +- include/xrpl/protocol/Serializer.h | 18 +-- include/xrpl/protocol/Sign.h | 8 +- include/xrpl/protocol/SystemParameters.h | 4 +- include/xrpl/protocol/TER.h | 4 +- include/xrpl/protocol/TxFormats.h | 2 +- include/xrpl/protocol/TxMeta.h | 8 +- include/xrpl/protocol/UintTypes.h | 8 +- include/xrpl/protocol/XChainAttestations.h | 20 +-- include/xrpl/protocol/detail/STVar.h | 6 +- include/xrpl/protocol/detail/b58_utils.h | 2 +- include/xrpl/protocol/digest.h | 4 +- include/xrpl/protocol/json_get_or_throw.h | 10 +- include/xrpl/protocol/jss.h | 2 +- include/xrpl/protocol/messages.h | 2 +- include/xrpl/protocol/nft.h | 6 +- include/xrpl/protocol/nftPageMask.h | 2 +- include/xrpl/protocol/serialize.h | 6 +- include/xrpl/protocol/st.h | 30 ++--- include/xrpl/protocol/tokens.h | 6 +- include/xrpl/resource/Consumer.h | 6 +- include/xrpl/resource/Fees.h | 2 +- include/xrpl/resource/Gossip.h | 2 +- include/xrpl/resource/ResourceManager.h | 14 +-- include/xrpl/resource/detail/Entry.h | 10 +- include/xrpl/resource/detail/Import.h | 4 +- include/xrpl/resource/detail/Key.h | 4 +- include/xrpl/resource/detail/Logic.h | 22 ++-- include/xrpl/server/Handoff.h | 2 +- include/xrpl/server/Port.h | 4 +- include/xrpl/server/Server.h | 8 +- include/xrpl/server/Session.h | 8 +- include/xrpl/server/SimpleWriter.h | 2 +- include/xrpl/server/WSSession.h | 6 +- include/xrpl/server/detail/BaseHTTPPeer.h | 8 +- include/xrpl/server/detail/BasePeer.h | 8 +- include/xrpl/server/detail/BaseWSPeer.h | 12 +- include/xrpl/server/detail/Door.h | 10 +- include/xrpl/server/detail/JSONRPCUtil.h | 4 +- include/xrpl/server/detail/PlainHTTPPeer.h | 6 +- include/xrpl/server/detail/PlainWSPeer.h | 2 +- include/xrpl/server/detail/SSLHTTPPeer.h | 4 +- include/xrpl/server/detail/SSLWSPeer.h | 4 +- include/xrpl/server/detail/ServerImpl.h | 10 +- src/libxrpl/basics/Archive.cpp | 4 +- src/libxrpl/basics/BasicConfig.cpp | 4 +- src/libxrpl/basics/CountedObject.cpp | 2 +- src/libxrpl/basics/FileUtilities.cpp | 2 +- src/libxrpl/basics/IOUAmount.cpp | 4 +- src/libxrpl/basics/Log.cpp | 6 +- src/libxrpl/basics/Number.cpp | 2 +- src/libxrpl/basics/ResolverAsio.cpp | 8 +- src/libxrpl/basics/StringUtilities.cpp | 12 +- src/libxrpl/basics/UptimeClock.cpp | 2 +- src/libxrpl/basics/base64.cpp | 2 +- src/libxrpl/basics/contract.cpp | 4 +- src/libxrpl/basics/make_SSLContext.cpp | 4 +- src/libxrpl/basics/mulDiv.cpp | 2 +- .../basics/partitioned_unordered_map.cpp | 10 +- .../beast/clock/basic_seconds_clock.cpp | 2 +- src/libxrpl/beast/core/CurrentThreadName.cpp | 2 +- src/libxrpl/beast/core/SemanticVersion.cpp | 4 +- src/libxrpl/beast/insight/Collector.cpp | 2 +- src/libxrpl/beast/insight/Groups.cpp | 6 +- src/libxrpl/beast/insight/Hook.cpp | 2 +- src/libxrpl/beast/insight/Metric.cpp | 8 +- src/libxrpl/beast/insight/NullCollector.cpp | 2 +- src/libxrpl/beast/insight/StatsDCollector.cpp | 16 +-- src/libxrpl/beast/net/IPAddressConversion.cpp | 2 +- src/libxrpl/beast/net/IPAddressV4.cpp | 2 +- src/libxrpl/beast/net/IPAddressV6.cpp | 4 +- src/libxrpl/beast/net/IPEndpoint.cpp | 2 +- .../beast/utility/src/beast_Journal.cpp | 2 +- .../utility/src/beast_PropertyStream.cpp | 2 +- src/libxrpl/crypto/RFC1751.cpp | 2 +- src/libxrpl/crypto/csprng.cpp | 4 +- src/libxrpl/crypto/secure_erase.cpp | 2 +- src/libxrpl/json/JsonPropertyStream.cpp | 4 +- src/libxrpl/json/Object.cpp | 4 +- src/libxrpl/json/Output.cpp | 4 +- src/libxrpl/json/Writer.cpp | 4 +- src/libxrpl/json/json_reader.cpp | 4 +- src/libxrpl/json/json_value.cpp | 10 +- src/libxrpl/json/json_valueiterator.cpp | 2 +- src/libxrpl/json/json_writer.cpp | 2 +- src/libxrpl/json/to_string.cpp | 4 +- src/libxrpl/protocol/AMMCore.cpp | 12 +- src/libxrpl/protocol/AccountID.cpp | 12 +- src/libxrpl/protocol/Book.cpp | 2 +- src/libxrpl/protocol/BuildInfo.cpp | 8 +- src/libxrpl/protocol/ErrorCodes.cpp | 2 +- src/libxrpl/protocol/Feature.cpp | 8 +- src/libxrpl/protocol/Indexes.cpp | 14 +-- src/libxrpl/protocol/InnerObjectFormats.cpp | 6 +- src/libxrpl/protocol/Issue.cpp | 10 +- src/libxrpl/protocol/Keylet.cpp | 4 +- src/libxrpl/protocol/LedgerFormats.cpp | 4 +- src/libxrpl/protocol/LedgerHeader.cpp | 2 +- .../protocol/NFTSyntheticSerializer.cpp | 8 +- src/libxrpl/protocol/NFTokenID.cpp | 4 +- src/libxrpl/protocol/NFTokenOfferID.cpp | 4 +- src/libxrpl/protocol/PublicKey.cpp | 10 +- src/libxrpl/protocol/Quality.cpp | 2 +- src/libxrpl/protocol/QualityFunction.cpp | 4 +- src/libxrpl/protocol/RPCErr.cpp | 4 +- src/libxrpl/protocol/Rate2.cpp | 4 +- src/libxrpl/protocol/Rules.cpp | 6 +- src/libxrpl/protocol/SField.cpp | 2 +- src/libxrpl/protocol/SOTemplate.cpp | 2 +- src/libxrpl/protocol/STAccount.cpp | 2 +- src/libxrpl/protocol/STAmount.cpp | 16 +-- src/libxrpl/protocol/STArray.cpp | 8 +- src/libxrpl/protocol/STBase.cpp | 2 +- src/libxrpl/protocol/STBlob.cpp | 4 +- src/libxrpl/protocol/STCurrency.cpp | 6 +- src/libxrpl/protocol/STInteger.cpp | 16 +-- src/libxrpl/protocol/STIssue.cpp | 10 +- src/libxrpl/protocol/STLedgerEntry.cpp | 20 +-- src/libxrpl/protocol/STObject.cpp | 18 +-- src/libxrpl/protocol/STParsedJSON.cpp | 46 +++---- src/libxrpl/protocol/STPathSet.cpp | 12 +- src/libxrpl/protocol/STTx.cpp | 32 ++--- src/libxrpl/protocol/STValidation.cpp | 10 +- src/libxrpl/protocol/STVar.cpp | 34 +++--- src/libxrpl/protocol/STVector256.cpp | 8 +- src/libxrpl/protocol/STXChainBridge.cpp | 26 ++-- src/libxrpl/protocol/SecretKey.cpp | 16 +-- src/libxrpl/protocol/Seed.cpp | 22 ++-- src/libxrpl/protocol/Serializer.cpp | 8 +- src/libxrpl/protocol/Sign.cpp | 2 +- src/libxrpl/protocol/TER.cpp | 2 +- src/libxrpl/protocol/TxFormats.cpp | 8 +- src/libxrpl/protocol/TxMeta.cpp | 10 +- src/libxrpl/protocol/UintTypes.cpp | 8 +- src/libxrpl/protocol/XChainAttestations.cpp | 34 +++--- src/libxrpl/protocol/digest.cpp | 2 +- src/libxrpl/protocol/tokens.cpp | 8 +- src/libxrpl/resource/Charge.cpp | 2 +- src/libxrpl/resource/Consumer.cpp | 6 +- src/libxrpl/resource/Fees.cpp | 2 +- src/libxrpl/resource/ResourceManager.cpp | 12 +- src/libxrpl/server/JSONRPCUtil.cpp | 12 +- src/libxrpl/server/Port.cpp | 8 +- src/test/app/AMMCalc_test.cpp | 4 +- src/test/app/AMMExtended_test.cpp | 26 ++-- src/test/app/AMM_test.cpp | 24 ++-- src/test/app/AccountDelete_test.cpp | 4 +- src/test/app/AccountTxPaging_test.cpp | 12 +- src/test/app/AmendmentTable_test.cpp | 26 ++-- src/test/app/Check_test.cpp | 4 +- src/test/app/Clawback_test.cpp | 12 +- src/test/app/CrossingLimits_test.cpp | 4 +- src/test/app/DID_test.cpp | 10 +- src/test/app/DNS_test.cpp | 4 +- src/test/app/DeliverMin_test.cpp | 4 +- src/test/app/DepositAuth_test.cpp | 2 +- src/test/app/Discrepancy_test.cpp | 10 +- src/test/app/Escrow_test.cpp | 12 +- src/test/app/FeeVote_test.cpp | 4 +- src/test/app/Flow_test.cpp | 18 +-- src/test/app/Freeze_test.cpp | 10 +- src/test/app/HashRouter_test.cpp | 6 +- src/test/app/LedgerHistory_test.cpp | 16 +-- src/test/app/LedgerLoad_test.cpp | 12 +- src/test/app/LedgerMaster_test.cpp | 4 +- src/test/app/LedgerReplay_test.cpp | 22 ++-- src/test/app/LoadFeeTrack_test.cpp | 8 +- src/test/app/Manifest_test.cpp | 22 ++-- src/test/app/MultiSign_test.cpp | 6 +- src/test/app/NFTokenBurn_test.cpp | 6 +- src/test/app/NFTokenDir_test.cpp | 8 +- src/test/app/NFToken_test.cpp | 8 +- src/test/app/NetworkID_test.cpp | 6 +- src/test/app/OfferStream_test.cpp | 4 +- src/test/app/Offer_test.cpp | 6 +- src/test/app/Oracle_test.cpp | 2 +- src/test/app/OversizeMeta_test.cpp | 4 +- src/test/app/Path_test.cpp | 32 ++--- src/test/app/PayChan_test.cpp | 18 +-- src/test/app/PayStrand_test.cpp | 24 ++-- src/test/app/PseudoTx_test.cpp | 8 +- src/test/app/RCLCensorshipDetector_test.cpp | 4 +- src/test/app/RCLValidations_test.cpp | 14 +-- src/test/app/ReducedOffer_test.cpp | 6 +- src/test/app/Regression_test.cpp | 10 +- src/test/app/SHAMapStore_test.cpp | 10 +- src/test/app/SetAuth_test.cpp | 4 +- src/test/app/SetRegularKey_test.cpp | 4 +- src/test/app/SetTrust_test.cpp | 4 +- src/test/app/Taker_test.cpp | 6 +- src/test/app/TheoreticalQuality_test.cpp | 24 ++-- src/test/app/Ticket_test.cpp | 6 +- src/test/app/Transaction_ordering_test.cpp | 4 +- src/test/app/TrustAndBalance_test.cpp | 8 +- src/test/app/TxQ_test.cpp | 16 +-- src/test/app/ValidatorKeys_test.cpp | 12 +- src/test/app/ValidatorList_test.cpp | 24 ++-- src/test/app/ValidatorSite_test.cpp | 26 ++-- src/test/app/XChain_test.cpp | 18 +-- src/test/app/tx/apply_test.cpp | 6 +- src/test/basics/Buffer_test.cpp | 4 +- src/test/basics/DetectCrash_test.cpp | 2 +- src/test/basics/Expected_test.cpp | 6 +- src/test/basics/FeeUnits_test.cpp | 6 +- src/test/basics/FileUtilities_test.cpp | 6 +- src/test/basics/IOUAmount_test.cpp | 4 +- src/test/basics/KeyCache_test.cpp | 12 +- src/test/basics/Number_test.cpp | 8 +- src/test/basics/PerfLog_test.cpp | 14 +-- src/test/basics/RangeSet_test.cpp | 4 +- src/test/basics/Slice_test.cpp | 4 +- src/test/basics/StringUtilities_test.cpp | 8 +- src/test/basics/TaggedCache_test.cpp | 10 +- src/test/basics/XRPAmount_test.cpp | 4 +- src/test/basics/base58_test.cpp | 6 +- src/test/basics/base64_test.cpp | 4 +- src/test/basics/base_uint_test.cpp | 8 +- src/test/basics/contract_test.cpp | 4 +- src/test/basics/hardened_hash_test.cpp | 4 +- src/test/basics/join_test.cpp | 4 +- src/test/basics/mulDiv_test.cpp | 4 +- src/test/basics/scope_test.cpp | 4 +- src/test/basics/tagged_integer_test.cpp | 4 +- src/test/beast/IPEndpointCommon.h | 4 +- src/test/beast/IPEndpoint_test.cpp | 8 +- src/test/beast/LexicalCast_test.cpp | 6 +- src/test/beast/SemanticVersion_test.cpp | 4 +- .../beast/aged_associative_container_test.cpp | 22 ++-- .../beast/beast_CurrentThreadName_test.cpp | 4 +- src/test/beast/beast_Journal_test.cpp | 4 +- src/test/beast/beast_PropertyStream_test.cpp | 4 +- src/test/beast/beast_Zero_test.cpp | 4 +- src/test/beast/beast_abstract_clock_test.cpp | 6 +- .../beast/beast_basic_seconds_clock_test.cpp | 4 +- .../beast/beast_io_latency_probe_test.cpp | 6 +- src/test/beast/define_print.cpp | 6 +- src/test/conditions/PreimageSha256_test.cpp | 16 +-- .../consensus/ByzantineFailureSim_test.cpp | 4 +- src/test/consensus/Consensus_test.cpp | 8 +- .../DistributedValidatorsSim_test.cpp | 4 +- src/test/consensus/LedgerTiming_test.cpp | 4 +- src/test/consensus/LedgerTrie_test.cpp | 6 +- src/test/consensus/NegativeUNL_test.cpp | 16 +-- src/test/consensus/ScaleFreeSim_test.cpp | 4 +- src/test/consensus/Validations_test.cpp | 10 +- src/test/core/ClosureCounter_test.cpp | 4 +- src/test/core/Config_test.cpp | 12 +- src/test/core/Coroutine_test.cpp | 4 +- src/test/core/CryptoPRNG_test.cpp | 6 +- src/test/core/JobQueue_test.cpp | 4 +- src/test/core/SociDB_test.cpp | 10 +- src/test/core/Workers_test.cpp | 10 +- src/test/csf/BasicNetwork_test.cpp | 4 +- src/test/csf/Digraph_test.cpp | 4 +- src/test/csf/Histogram_test.cpp | 2 +- src/test/csf/Peer.h | 14 +-- src/test/csf/PeerGroup.h | 2 +- src/test/csf/Proposal.h | 2 +- src/test/csf/Scheduler.h | 4 +- src/test/csf/Scheduler_test.cpp | 4 +- src/test/csf/SimTime.h | 2 +- src/test/csf/TrustGraph.h | 2 +- src/test/csf/Tx.h | 4 +- src/test/csf/Validation.h | 2 +- src/test/csf/collectors.h | 2 +- src/test/csf/events.h | 2 +- src/test/csf/impl/ledgers.cpp | 2 +- src/test/csf/ledgers.h | 14 +-- src/test/csf/timers.h | 4 +- src/test/json/Object_test.cpp | 4 +- src/test/json/Output_test.cpp | 4 +- src/test/json/TestOutputSuite.h | 4 +- src/test/json/Writer_test.cpp | 6 +- src/test/json/json_value_test.cpp | 12 +- src/test/jtx.h | 2 +- src/test/jtx/AMM.h | 8 +- src/test/jtx/AMMTest.h | 4 +- src/test/jtx/AbstractClient.h | 2 +- src/test/jtx/Account.h | 8 +- src/test/jtx/CaptureLogs.h | 2 +- src/test/jtx/CheckMessageLogs.h | 2 +- src/test/jtx/Env.h | 38 +++--- src/test/jtx/Env_test.cpp | 16 +-- src/test/jtx/JSONRPCClient.h | 4 +- src/test/jtx/JTx.h | 8 +- src/test/jtx/ManualTimeKeeper.h | 2 +- src/test/jtx/Oracle.h | 2 +- src/test/jtx/PathSet.h | 4 +- src/test/jtx/TestHelpers.h | 12 +- src/test/jtx/TestSuite.h | 2 +- src/test/jtx/TrustedPublisherServer.h | 14 +-- src/test/jtx/WSClient.h | 2 +- src/test/jtx/WSClient_test.cpp | 2 +- src/test/jtx/amount.h | 14 +-- src/test/jtx/attester.h | 4 +- src/test/jtx/delivermin.h | 2 +- src/test/jtx/envconfig.h | 2 +- src/test/jtx/fee.h | 4 +- src/test/jtx/flags.h | 6 +- src/test/jtx/impl/AMM.cpp | 10 +- src/test/jtx/impl/AMMTest.cpp | 8 +- src/test/jtx/impl/Account.cpp | 2 +- src/test/jtx/impl/Env.cpp | 42 +++---- src/test/jtx/impl/JSONRPCClient.cpp | 10 +- src/test/jtx/impl/Oracle.cpp | 4 +- src/test/jtx/impl/TestHelpers.cpp | 2 +- src/test/jtx/impl/WSClient.cpp | 14 +-- src/test/jtx/impl/acctdelete.cpp | 2 +- src/test/jtx/impl/amount.cpp | 6 +- src/test/jtx/impl/attester.cpp | 10 +- src/test/jtx/impl/check.cpp | 4 +- src/test/jtx/impl/delivermin.cpp | 2 +- src/test/jtx/impl/deposit.cpp | 2 +- src/test/jtx/impl/did.cpp | 4 +- src/test/jtx/impl/envconfig.cpp | 2 +- src/test/jtx/impl/fee.cpp | 2 +- src/test/jtx/impl/flags.cpp | 2 +- src/test/jtx/impl/jtx_json.cpp | 4 +- src/test/jtx/impl/last_ledger_sequence.cpp | 2 +- src/test/jtx/impl/memo.cpp | 4 +- src/test/jtx/impl/multisign.cpp | 14 +-- src/test/jtx/impl/offer.cpp | 2 +- src/test/jtx/impl/paths.cpp | 4 +- src/test/jtx/impl/pay.cpp | 4 +- src/test/jtx/impl/quality2.cpp | 4 +- src/test/jtx/impl/rate.cpp | 6 +- src/test/jtx/impl/regkey.cpp | 2 +- src/test/jtx/impl/sendmax.cpp | 2 +- src/test/jtx/impl/seq.cpp | 2 +- src/test/jtx/impl/tag.cpp | 2 +- src/test/jtx/impl/ticket.cpp | 2 +- src/test/jtx/impl/token.cpp | 6 +- src/test/jtx/impl/trust.cpp | 6 +- src/test/jtx/impl/txflags.cpp | 2 +- src/test/jtx/impl/utility.cpp | 20 +-- src/test/jtx/impl/xchain_bridge.cpp | 18 +-- src/test/jtx/jtx_json.h | 2 +- src/test/jtx/multisign.h | 6 +- src/test/jtx/offer.h | 4 +- src/test/jtx/owners.h | 8 +- src/test/jtx/paths.h | 2 +- src/test/jtx/pay.h | 2 +- src/test/jtx/prop.h | 2 +- src/test/jtx/rate.h | 2 +- src/test/jtx/regkey.h | 2 +- src/test/jtx/require.h | 2 +- src/test/jtx/sendmax.h | 2 +- src/test/jtx/token.h | 2 +- src/test/jtx/trust.h | 4 +- src/test/jtx/utility.h | 10 +- src/test/jtx/xchain_bridge.h | 6 +- src/test/ledger/BookDirs_test.cpp | 4 +- src/test/ledger/Directory_test.cpp | 16 +-- src/test/ledger/Invariants_test.cpp | 12 +- src/test/ledger/PaymentSandbox_test.cpp | 10 +- src/test/ledger/PendingSaves_test.cpp | 4 +- src/test/ledger/SkipList_test.cpp | 8 +- src/test/ledger/View_test.cpp | 16 +-- src/test/net/DatabaseDownloader_test.cpp | 8 +- src/test/nodestore/Backend_test.cpp | 10 +- src/test/nodestore/Basics_test.cpp | 8 +- src/test/nodestore/DatabaseShard_test.cpp | 30 ++--- src/test/nodestore/Database_test.cpp | 8 +- src/test/nodestore/TestBase.h | 16 +-- src/test/nodestore/Timing_test.cpp | 24 ++-- src/test/nodestore/import_test.cpp | 14 +-- src/test/nodestore/varint_test.cpp | 4 +- src/test/overlay/ProtocolVersion_test.cpp | 4 +- src/test/overlay/cluster_test.cpp | 8 +- src/test/overlay/compression_test.cpp | 46 +++---- src/test/overlay/handshake_test.cpp | 4 +- src/test/overlay/reduce_relay_test.cpp | 16 +-- src/test/overlay/short_read_test.cpp | 6 +- src/test/overlay/tx_reduce_relay_test.cpp | 10 +- src/test/peerfinder/Livecache_test.cpp | 12 +- src/test/peerfinder/PeerFinder_test.cpp | 16 +-- src/test/protocol/ApiVersion_test.cpp | 8 +- src/test/protocol/BuildInfo_test.cpp | 4 +- src/test/protocol/Hooks_test.cpp | 6 +- src/test/protocol/InnerObjectFormats_test.cpp | 12 +- src/test/protocol/Issue_test.cpp | 8 +- src/test/protocol/Memo_test.cpp | 4 +- src/test/protocol/MultiApiJson_test.cpp | 4 +- src/test/protocol/PublicKey_test.cpp | 6 +- src/test/protocol/Quality_test.cpp | 4 +- src/test/protocol/STAccount_test.cpp | 4 +- src/test/protocol/STAmount_test.cpp | 8 +- src/test/protocol/STObject_test.cpp | 12 +- src/test/protocol/STTx_test.cpp | 22 ++-- src/test/protocol/STValidation_test.cpp | 18 +-- src/test/protocol/SecretKey_test.cpp | 12 +- src/test/protocol/Seed_test.cpp | 14 +-- src/test/protocol/SeqProxy_test.cpp | 4 +- src/test/protocol/TER_test.cpp | 4 +- src/test/protocol/types_test.cpp | 4 +- src/test/resource/Logic_test.cpp | 12 +- src/test/rpc/AMMInfo_test.cpp | 4 +- src/test/rpc/AccountCurrencies_test.cpp | 4 +- src/test/rpc/AccountInfo_test.cpp | 10 +- src/test/rpc/AccountLinesRPC_test.cpp | 8 +- src/test/rpc/AccountObjects_test.cpp | 8 +- src/test/rpc/AccountOffers_test.cpp | 2 +- src/test/rpc/AccountSet_test.cpp | 12 +- src/test/rpc/AccountTx_test.cpp | 6 +- src/test/rpc/AmendmentBlocked_test.cpp | 8 +- src/test/rpc/Book_test.cpp | 8 +- src/test/rpc/DeliveredAmount_test.cpp | 6 +- src/test/rpc/DepositAuthorized_test.cpp | 2 +- src/test/rpc/Feature_test.cpp | 6 +- src/test/rpc/GRPCTestClientBase.h | 4 +- src/test/rpc/GatewayBalances_test.cpp | 8 +- src/test/rpc/GetAggregatePrice_test.cpp | 4 +- src/test/rpc/GetCounts_test.cpp | 8 +- src/test/rpc/Handler_test.cpp | 4 +- src/test/rpc/JSONRPC_test.cpp | 18 +-- src/test/rpc/KeyGeneration_test.cpp | 12 +- src/test/rpc/LedgerClosed_test.cpp | 4 +- src/test/rpc/LedgerData_test.cpp | 4 +- src/test/rpc/LedgerHeader_test.cpp | 2 +- src/test/rpc/LedgerRPC_test.cpp | 16 +-- src/test/rpc/LedgerRequestRPC_test.cpp | 10 +- src/test/rpc/ManifestRPC_test.cpp | 6 +- src/test/rpc/NoRippleCheck_test.cpp | 18 +-- src/test/rpc/NoRipple_test.cpp | 6 +- src/test/rpc/NodeToShardRPC_test.cpp | 12 +- src/test/rpc/OwnerInfo_test.cpp | 8 +- src/test/rpc/Peers_test.cpp | 6 +- src/test/rpc/RPCCall_test.cpp | 10 +- src/test/rpc/RPCOverload_test.cpp | 6 +- src/test/rpc/ReportingETL_test.cpp | 8 +- src/test/rpc/RobustTransaction_test.cpp | 6 +- src/test/rpc/Roles_test.cpp | 6 +- src/test/rpc/ServerInfo_test.cpp | 8 +- src/test/rpc/ShardArchiveHandler_test.cpp | 16 +-- src/test/rpc/Status_test.cpp | 6 +- src/test/rpc/Subscribe_test.cpp | 16 +-- src/test/rpc/TransactionEntry_test.cpp | 8 +- src/test/rpc/TransactionHistory_test.cpp | 6 +- src/test/rpc/Transaction_test.cpp | 12 +- src/test/rpc/ValidatorInfo_test.cpp | 6 +- src/test/rpc/ValidatorRPC_test.cpp | 16 +-- src/test/rpc/Version_test.cpp | 4 +- src/test/server/ServerStatus_test.cpp | 22 ++-- src/test/server/Server_test.cpp | 12 +- src/test/shamap/FetchPack_test.cpp | 22 ++-- src/test/shamap/SHAMapSync_test.cpp | 12 +- src/test/shamap/SHAMap_test.cpp | 10 +- src/test/shamap/common.h | 10 +- src/test/unit_test/FileDirGuard.h | 4 +- src/test/unit_test/SuiteJournal.h | 4 +- src/test/unit_test/multi_runner.cpp | 2 +- src/test/unit_test/multi_runner.h | 4 +- .../app/consensus/RCLCensorshipDetector.h | 4 +- src/xrpld/app/consensus/RCLConsensus.cpp | 52 ++++---- src/xrpld/app/consensus/RCLConsensus.h | 30 ++--- src/xrpld/app/consensus/RCLCxLedger.h | 8 +- src/xrpld/app/consensus/RCLCxPeerPos.cpp | 12 +- src/xrpld/app/consensus/RCLCxPeerPos.h | 16 +-- src/xrpld/app/consensus/RCLCxTx.h | 8 +- src/xrpld/app/consensus/RCLValidations.cpp | 26 ++-- src/xrpld/app/consensus/RCLValidations.h | 10 +- .../app/ledger/AbstractFetchPackContainer.h | 4 +- src/xrpld/app/ledger/AcceptedLedger.cpp | 4 +- src/xrpld/app/ledger/AcceptedLedger.h | 4 +- src/xrpld/app/ledger/AcceptedLedgerTx.cpp | 10 +- src/xrpld/app/ledger/AcceptedLedgerTx.h | 4 +- src/xrpld/app/ledger/AccountStateSF.cpp | 2 +- src/xrpld/app/ledger/AccountStateSF.h | 6 +- src/xrpld/app/ledger/BookListeners.cpp | 6 +- src/xrpld/app/ledger/BookListeners.h | 4 +- src/xrpld/app/ledger/BuildLedger.h | 6 +- src/xrpld/app/ledger/ConsensusTransSetSF.cpp | 20 +-- src/xrpld/app/ledger/ConsensusTransSetSF.h | 6 +- src/xrpld/app/ledger/InboundLedger.h | 10 +- src/xrpld/app/ledger/InboundLedgers.h | 4 +- src/xrpld/app/ledger/InboundTransactions.h | 6 +- src/xrpld/app/ledger/Ledger.cpp | 68 +++++------ src/xrpld/app/ledger/Ledger.h | 22 ++-- src/xrpld/app/ledger/LedgerCleaner.h | 8 +- src/xrpld/app/ledger/LedgerHistory.cpp | 12 +- src/xrpld/app/ledger/LedgerHistory.h | 10 +- src/xrpld/app/ledger/LedgerHolder.h | 4 +- src/xrpld/app/ledger/LedgerMaster.h | 34 +++--- src/xrpld/app/ledger/LedgerReplay.h | 2 +- src/xrpld/app/ledger/LedgerReplayTask.h | 6 +- src/xrpld/app/ledger/LedgerReplayer.h | 8 +- src/xrpld/app/ledger/LedgerToJson.h | 20 +-- src/xrpld/app/ledger/LocalTxs.h | 4 +- src/xrpld/app/ledger/OpenLedger.h | 16 +-- src/xrpld/app/ledger/OrderBookDB.cpp | 18 +-- src/xrpld/app/ledger/OrderBookDB.h | 8 +- src/xrpld/app/ledger/PendingSaves.h | 2 +- src/xrpld/app/ledger/TransactionMaster.h | 10 +- src/xrpld/app/ledger/TransactionStateSF.cpp | 2 +- src/xrpld/app/ledger/TransactionStateSF.h | 6 +- src/xrpld/app/ledger/detail/BuildLedger.cpp | 16 +-- src/xrpld/app/ledger/detail/InboundLedger.cpp | 30 ++--- .../app/ledger/detail/InboundLedgers.cpp | 22 ++-- .../app/ledger/detail/InboundTransactions.cpp | 18 +-- src/xrpld/app/ledger/detail/LedgerCleaner.cpp | 12 +- .../app/ledger/detail/LedgerDeltaAcquire.cpp | 16 +-- .../app/ledger/detail/LedgerDeltaAcquire.h | 10 +- src/xrpld/app/ledger/detail/LedgerMaster.cpp | 70 +++++------ src/xrpld/app/ledger/detail/LedgerReplay.cpp | 4 +- .../ledger/detail/LedgerReplayMsgHandler.cpp | 10 +- .../ledger/detail/LedgerReplayMsgHandler.h | 4 +- .../app/ledger/detail/LedgerReplayTask.cpp | 12 +- .../app/ledger/detail/LedgerReplayer.cpp | 8 +- src/xrpld/app/ledger/detail/LedgerToJson.cpp | 22 ++-- src/xrpld/app/ledger/detail/LocalTxs.cpp | 8 +- src/xrpld/app/ledger/detail/OpenLedger.cpp | 20 +-- .../app/ledger/detail/SkipListAcquire.cpp | 12 +- src/xrpld/app/ledger/detail/SkipListAcquire.h | 10 +- .../app/ledger/detail/TimeoutCounter.cpp | 8 +- src/xrpld/app/ledger/detail/TimeoutCounter.h | 8 +- .../app/ledger/detail/TransactionAcquire.cpp | 16 +-- .../app/ledger/detail/TransactionAcquire.h | 6 +- .../app/ledger/detail/TransactionMaster.cpp | 10 +- src/xrpld/app/main/Application.cpp | 114 +++++++++--------- src/xrpld/app/main/Application.h | 14 +-- src/xrpld/app/main/BasicApp.cpp | 4 +- src/xrpld/app/main/CollectorManager.cpp | 2 +- src/xrpld/app/main/CollectorManager.h | 4 +- src/xrpld/app/main/GRPCServer.cpp | 12 +- src/xrpld/app/main/GRPCServer.h | 26 ++-- src/xrpld/app/main/LoadManager.cpp | 14 +-- src/xrpld/app/main/LoadManager.h | 2 +- src/xrpld/app/main/Main.cpp | 34 +++--- src/xrpld/app/main/NodeIdentity.cpp | 10 +- src/xrpld/app/main/NodeIdentity.h | 6 +- src/xrpld/app/main/NodeStoreScheduler.cpp | 2 +- src/xrpld/app/main/NodeStoreScheduler.h | 4 +- src/xrpld/app/misc/AMMHelpers.h | 24 ++-- src/xrpld/app/misc/AMMUtils.h | 12 +- src/xrpld/app/misc/AmendmentTable.h | 10 +- src/xrpld/app/misc/CanonicalTXSet.cpp | 2 +- src/xrpld/app/misc/CanonicalTXSet.h | 8 +- src/xrpld/app/misc/DeliverMax.h | 2 +- src/xrpld/app/misc/FeeVote.h | 10 +- src/xrpld/app/misc/FeeVoteImpl.cpp | 14 +-- src/xrpld/app/misc/HashRouter.cpp | 2 +- src/xrpld/app/misc/HashRouter.h | 10 +- src/xrpld/app/misc/LoadFeeTrack.h | 8 +- src/xrpld/app/misc/Manifest.h | 8 +- src/xrpld/app/misc/NegativeUNLVote.cpp | 8 +- src/xrpld/app/misc/NegativeUNLVote.h | 10 +- src/xrpld/app/misc/NetworkOPs.cpp | 102 ++++++++-------- src/xrpld/app/misc/NetworkOPs.h | 14 +-- src/xrpld/app/misc/SHAMapStore.h | 6 +- src/xrpld/app/misc/SHAMapStoreImp.cpp | 24 ++-- src/xrpld/app/misc/SHAMapStoreImp.h | 16 +-- src/xrpld/app/misc/Transaction.h | 16 +-- src/xrpld/app/misc/TxQ.h | 14 +-- src/xrpld/app/misc/ValidatorKeys.h | 8 +- src/xrpld/app/misc/ValidatorList.h | 16 +-- src/xrpld/app/misc/ValidatorSite.h | 14 +-- src/xrpld/app/misc/detail/AMMHelpers.cpp | 2 +- src/xrpld/app/misc/detail/AMMUtils.cpp | 12 +- src/xrpld/app/misc/detail/AccountTxPaging.cpp | 14 +-- src/xrpld/app/misc/detail/AccountTxPaging.h | 2 +- src/xrpld/app/misc/detail/AmendmentTable.cpp | 16 +-- src/xrpld/app/misc/detail/DeliverMax.cpp | 4 +- src/xrpld/app/misc/detail/LoadFeeTrack.cpp | 18 +-- src/xrpld/app/misc/detail/Manifest.cpp | 18 +-- src/xrpld/app/misc/detail/Transaction.cpp | 30 ++--- src/xrpld/app/misc/detail/TxQ.cpp | 18 +-- src/xrpld/app/misc/detail/ValidatorKeys.cpp | 12 +- src/xrpld/app/misc/detail/ValidatorList.cpp | 28 ++--- src/xrpld/app/misc/detail/ValidatorSite.cpp | 20 +-- src/xrpld/app/misc/detail/WorkBase.h | 6 +- src/xrpld/app/misc/detail/WorkFile.h | 6 +- src/xrpld/app/misc/detail/WorkPlain.h | 2 +- src/xrpld/app/misc/detail/WorkSSL.h | 8 +- src/xrpld/app/misc/detail/detail/WorkSSL.cpp | 2 +- src/xrpld/app/paths/AMMContext.h | 2 +- src/xrpld/app/paths/AMMLiquidity.h | 16 +-- src/xrpld/app/paths/AMMOffer.h | 8 +- src/xrpld/app/paths/AccountCurrencies.cpp | 2 +- src/xrpld/app/paths/AccountCurrencies.h | 4 +- src/xrpld/app/paths/Credit.cpp | 8 +- src/xrpld/app/paths/Credit.h | 6 +- src/xrpld/app/paths/Flow.cpp | 18 +-- src/xrpld/app/paths/Flow.h | 6 +- src/xrpld/app/paths/PathRequest.cpp | 32 ++--- src/xrpld/app/paths/PathRequest.h | 12 +- src/xrpld/app/paths/PathRequests.cpp | 18 +-- src/xrpld/app/paths/PathRequests.h | 8 +- src/xrpld/app/paths/Pathfinder.cpp | 24 ++-- src/xrpld/app/paths/Pathfinder.h | 12 +- src/xrpld/app/paths/RippleCalc.cpp | 12 +- src/xrpld/app/paths/RippleCalc.h | 8 +- src/xrpld/app/paths/RippleLineCache.cpp | 6 +- src/xrpld/app/paths/RippleLineCache.h | 8 +- src/xrpld/app/paths/TrustLine.cpp | 6 +- src/xrpld/app/paths/TrustLine.h | 10 +- src/xrpld/app/paths/detail/AMMLiquidity.cpp | 4 +- src/xrpld/app/paths/detail/AMMOffer.cpp | 6 +- src/xrpld/app/paths/detail/AmountSpec.h | 6 +- src/xrpld/app/paths/detail/BookStep.cpp | 30 ++--- src/xrpld/app/paths/detail/DirectStep.cpp | 16 +-- src/xrpld/app/paths/detail/FlowDebugInfo.h | 8 +- src/xrpld/app/paths/detail/PathfinderUtils.h | 2 +- src/xrpld/app/paths/detail/PaySteps.cpp | 14 +-- src/xrpld/app/paths/detail/StepChecks.h | 10 +- src/xrpld/app/paths/detail/Steps.h | 12 +- src/xrpld/app/paths/detail/StrandFlow.h | 24 ++-- .../app/paths/detail/XRPEndpointStep.cpp | 20 +-- src/xrpld/app/rdb/Download.h | 12 +- src/xrpld/app/rdb/PeerFinder.h | 6 +- src/xrpld/app/rdb/RelationalDatabase.h | 14 +-- src/xrpld/app/rdb/ShardArchive.h | 2 +- src/xrpld/app/rdb/State.h | 12 +- src/xrpld/app/rdb/UnitaryShard.h | 8 +- src/xrpld/app/rdb/Vacuum.h | 2 +- src/xrpld/app/rdb/Wallet.h | 12 +- src/xrpld/app/rdb/backend/PostgresDatabase.h | 2 +- src/xrpld/app/rdb/backend/SQLiteDatabase.h | 2 +- src/xrpld/app/rdb/backend/detail/Node.h | 12 +- .../rdb/backend/detail/PostgresDatabase.cpp | 34 +++--- .../app/rdb/backend/detail/SQLiteDatabase.cpp | 30 ++--- src/xrpld/app/rdb/backend/detail/Shard.h | 10 +- .../app/rdb/backend/detail/detail/Node.cpp | 26 ++-- .../app/rdb/backend/detail/detail/Shard.cpp | 14 +-- src/xrpld/app/rdb/detail/Download.cpp | 2 +- src/xrpld/app/rdb/detail/PeerFinder.cpp | 2 +- .../app/rdb/detail/RelationalDatabase.cpp | 8 +- src/xrpld/app/rdb/detail/ShardArchive.cpp | 2 +- src/xrpld/app/rdb/detail/State.cpp | 2 +- src/xrpld/app/rdb/detail/UnitaryShard.cpp | 4 +- src/xrpld/app/rdb/detail/Vacuum.cpp | 2 +- src/xrpld/app/rdb/detail/Wallet.cpp | 2 +- src/xrpld/app/reporting/ETLHelpers.h | 4 +- src/xrpld/app/reporting/ETLSource.cpp | 10 +- src/xrpld/app/reporting/ETLSource.h | 10 +- src/xrpld/app/reporting/P2pProxy.cpp | 8 +- src/xrpld/app/reporting/P2pProxy.h | 8 +- src/xrpld/app/reporting/ReportingETL.cpp | 10 +- src/xrpld/app/reporting/ReportingETL.h | 30 ++--- src/xrpld/app/tx/apply.h | 10 +- src/xrpld/app/tx/applySteps.h | 4 +- src/xrpld/app/tx/detail/AMMBid.cpp | 22 ++-- src/xrpld/app/tx/detail/AMMBid.h | 2 +- src/xrpld/app/tx/detail/AMMCreate.cpp | 24 ++-- src/xrpld/app/tx/detail/AMMCreate.h | 2 +- src/xrpld/app/tx/detail/AMMDelete.cpp | 18 +-- src/xrpld/app/tx/detail/AMMDelete.h | 2 +- src/xrpld/app/tx/detail/AMMDeposit.cpp | 20 +-- src/xrpld/app/tx/detail/AMMDeposit.h | 2 +- src/xrpld/app/tx/detail/AMMVote.cpp | 18 +-- src/xrpld/app/tx/detail/AMMVote.h | 2 +- src/xrpld/app/tx/detail/AMMWithdraw.cpp | 20 +-- src/xrpld/app/tx/detail/AMMWithdraw.h | 2 +- src/xrpld/app/tx/detail/ApplyContext.cpp | 14 +-- src/xrpld/app/tx/detail/ApplyContext.h | 12 +- src/xrpld/app/tx/detail/BookTip.cpp | 4 +- src/xrpld/app/tx/detail/BookTip.h | 6 +- src/xrpld/app/tx/detail/CancelCheck.cpp | 20 +-- src/xrpld/app/tx/detail/CancelCheck.h | 2 +- src/xrpld/app/tx/detail/CancelOffer.cpp | 8 +- src/xrpld/app/tx/detail/CancelOffer.h | 8 +- src/xrpld/app/tx/detail/CashCheck.cpp | 20 +-- src/xrpld/app/tx/detail/CashCheck.h | 2 +- src/xrpld/app/tx/detail/Change.cpp | 20 +-- src/xrpld/app/tx/detail/Change.h | 12 +- src/xrpld/app/tx/detail/Clawback.cpp | 14 +-- src/xrpld/app/tx/detail/Clawback.h | 2 +- src/xrpld/app/tx/detail/CreateCheck.cpp | 16 +-- src/xrpld/app/tx/detail/CreateCheck.h | 2 +- src/xrpld/app/tx/detail/CreateOffer.cpp | 16 +-- src/xrpld/app/tx/detail/CreateOffer.h | 6 +- src/xrpld/app/tx/detail/CreateTicket.cpp | 14 +-- src/xrpld/app/tx/detail/CreateTicket.h | 8 +- src/xrpld/app/tx/detail/DID.cpp | 18 +-- src/xrpld/app/tx/detail/DID.h | 2 +- src/xrpld/app/tx/detail/DeleteAccount.cpp | 30 ++--- src/xrpld/app/tx/detail/DeleteAccount.h | 6 +- src/xrpld/app/tx/detail/DeleteOracle.cpp | 12 +- src/xrpld/app/tx/detail/DeleteOracle.h | 2 +- src/xrpld/app/tx/detail/DepositPreauth.cpp | 14 +-- src/xrpld/app/tx/detail/DepositPreauth.h | 2 +- src/xrpld/app/tx/detail/Escrow.cpp | 32 ++--- src/xrpld/app/tx/detail/Escrow.h | 2 +- src/xrpld/app/tx/detail/InvariantCheck.cpp | 24 ++-- src/xrpld/app/tx/detail/InvariantCheck.h | 10 +- .../app/tx/detail/NFTokenAcceptOffer.cpp | 14 +-- src/xrpld/app/tx/detail/NFTokenAcceptOffer.h | 2 +- src/xrpld/app/tx/detail/NFTokenBurn.cpp | 16 +-- src/xrpld/app/tx/detail/NFTokenBurn.h | 2 +- .../app/tx/detail/NFTokenCancelOffer.cpp | 12 +- src/xrpld/app/tx/detail/NFTokenCancelOffer.h | 2 +- .../app/tx/detail/NFTokenCreateOffer.cpp | 12 +- src/xrpld/app/tx/detail/NFTokenCreateOffer.h | 2 +- src/xrpld/app/tx/detail/NFTokenMint.cpp | 18 +-- src/xrpld/app/tx/detail/NFTokenMint.h | 4 +- src/xrpld/app/tx/detail/NFTokenUtils.cpp | 18 +-- src/xrpld/app/tx/detail/NFTokenUtils.h | 14 +-- src/xrpld/app/tx/detail/Offer.h | 12 +- src/xrpld/app/tx/detail/OfferStream.cpp | 6 +- src/xrpld/app/tx/detail/OfferStream.h | 14 +-- src/xrpld/app/tx/detail/PayChan.cpp | 26 ++-- src/xrpld/app/tx/detail/PayChan.h | 2 +- src/xrpld/app/tx/detail/Payment.cpp | 16 +-- src/xrpld/app/tx/detail/Payment.h | 8 +- src/xrpld/app/tx/detail/SetAccount.cpp | 18 +-- src/xrpld/app/tx/detail/SetAccount.h | 12 +- src/xrpld/app/tx/detail/SetOracle.cpp | 16 +-- src/xrpld/app/tx/detail/SetOracle.h | 2 +- src/xrpld/app/tx/detail/SetRegularKey.cpp | 8 +- src/xrpld/app/tx/detail/SetRegularKey.h | 8 +- src/xrpld/app/tx/detail/SetSignerList.cpp | 20 +-- src/xrpld/app/tx/detail/SetSignerList.h | 18 +-- src/xrpld/app/tx/detail/SetTrust.cpp | 16 +-- src/xrpld/app/tx/detail/SetTrust.h | 10 +- src/xrpld/app/tx/detail/SignerEntries.cpp | 8 +- src/xrpld/app/tx/detail/SignerEntries.h | 14 +-- src/xrpld/app/tx/detail/Taker.cpp | 6 +- src/xrpld/app/tx/detail/Taker.h | 16 +-- src/xrpld/app/tx/detail/Transactor.cpp | 32 ++--- src/xrpld/app/tx/detail/Transactor.h | 8 +- src/xrpld/app/tx/detail/XChainBridge.cpp | 50 ++++---- src/xrpld/app/tx/detail/XChainBridge.h | 6 +- src/xrpld/app/tx/detail/apply.cpp | 10 +- src/xrpld/app/tx/detail/applySteps.cpp | 70 +++++------ src/xrpld/conditions/Condition.h | 6 +- src/xrpld/conditions/Fulfillment.h | 8 +- src/xrpld/conditions/detail/Condition.cpp | 10 +- src/xrpld/conditions/detail/Fulfillment.cpp | 10 +- src/xrpld/conditions/detail/PreimageSha256.h | 12 +- src/xrpld/conditions/detail/error.cpp | 4 +- src/xrpld/conditions/detail/utils.h | 8 +- src/xrpld/consensus/Consensus.cpp | 4 +- src/xrpld/consensus/Consensus.h | 18 +-- src/xrpld/consensus/ConsensusProposal.h | 10 +- src/xrpld/consensus/ConsensusTypes.h | 6 +- src/xrpld/consensus/DisputedTx.h | 14 +-- src/xrpld/consensus/LedgerTiming.h | 4 +- src/xrpld/consensus/LedgerTrie.h | 4 +- src/xrpld/consensus/Validations.h | 14 +-- src/xrpld/core/ClosureCounter.h | 2 +- src/xrpld/core/Config.h | 12 +- src/xrpld/core/Coro.ipp | 2 +- src/xrpld/core/DatabaseCon.h | 6 +- src/xrpld/core/Job.h | 6 +- src/xrpld/core/JobQueue.h | 14 +-- src/xrpld/core/JobTypeData.h | 6 +- src/xrpld/core/JobTypeInfo.h | 2 +- src/xrpld/core/JobTypes.h | 4 +- src/xrpld/core/LoadMonitor.h | 6 +- src/xrpld/core/Pg.cpp | 4 +- src/xrpld/core/Pg.h | 6 +- src/xrpld/core/SociDB.h | 4 +- src/xrpld/core/TimeKeeper.h | 4 +- src/xrpld/core/detail/Config.cpp | 22 ++-- src/xrpld/core/detail/DatabaseCon.cpp | 8 +- src/xrpld/core/detail/Job.cpp | 4 +- src/xrpld/core/detail/JobQueue.cpp | 6 +- src/xrpld/core/detail/LoadEvent.cpp | 4 +- src/xrpld/core/detail/LoadMonitor.cpp | 6 +- src/xrpld/core/detail/SociDB.cpp | 12 +- src/xrpld/core/detail/Workers.cpp | 6 +- src/xrpld/core/detail/Workers.h | 4 +- src/xrpld/ledger/ApplyView.h | 6 +- src/xrpld/ledger/ApplyViewImpl.h | 8 +- src/xrpld/ledger/BookDirs.h | 2 +- src/xrpld/ledger/CachedSLEs.h | 6 +- src/xrpld/ledger/CachedView.h | 6 +- src/xrpld/ledger/Directory.h | 4 +- src/xrpld/ledger/OpenView.h | 8 +- src/xrpld/ledger/PaymentSandbox.h | 8 +- src/xrpld/ledger/RawView.h | 6 +- src/xrpld/ledger/ReadView.h | 32 ++--- src/xrpld/ledger/Sandbox.h | 4 +- src/xrpld/ledger/View.h | 26 ++-- src/xrpld/ledger/detail/ApplyStateTable.cpp | 10 +- src/xrpld/ledger/detail/ApplyStateTable.h | 14 +-- src/xrpld/ledger/detail/ApplyView.cpp | 6 +- src/xrpld/ledger/detail/ApplyViewBase.cpp | 4 +- src/xrpld/ledger/detail/ApplyViewBase.h | 10 +- src/xrpld/ledger/detail/ApplyViewImpl.cpp | 4 +- src/xrpld/ledger/detail/BookDirs.cpp | 6 +- src/xrpld/ledger/detail/CachedView.cpp | 6 +- src/xrpld/ledger/detail/Directory.cpp | 2 +- src/xrpld/ledger/detail/OpenView.cpp | 4 +- src/xrpld/ledger/detail/PaymentSandbox.cpp | 12 +- src/xrpld/ledger/detail/RawStateTable.cpp | 4 +- src/xrpld/ledger/detail/RawStateTable.h | 4 +- src/xrpld/ledger/detail/ReadView.cpp | 2 +- src/xrpld/ledger/detail/View.cpp | 18 +-- src/xrpld/net/AutoSocket.h | 4 +- src/xrpld/net/DatabaseBody.h | 4 +- src/xrpld/net/DatabaseDownloader.h | 4 +- src/xrpld/net/HTTPClient.h | 4 +- src/xrpld/net/HTTPClientSSLContext.h | 8 +- src/xrpld/net/HTTPDownloader.h | 6 +- src/xrpld/net/HTTPStream.h | 4 +- src/xrpld/net/InfoSub.h | 12 +- src/xrpld/net/RPCCall.h | 6 +- src/xrpld/net/RPCSub.h | 4 +- src/xrpld/net/RegisterSSLCerts.h | 2 +- src/xrpld/net/detail/DatabaseBody.ipp | 2 +- src/xrpld/net/detail/DatabaseDownloader.cpp | 2 +- src/xrpld/net/detail/HTTPClient.cpp | 14 +-- src/xrpld/net/detail/HTTPDownloader.cpp | 2 +- src/xrpld/net/detail/HTTPStream.cpp | 2 +- src/xrpld/net/detail/InfoSub.cpp | 2 +- src/xrpld/net/detail/RPCCall.cpp | 42 +++---- src/xrpld/net/detail/RPCSub.cpp | 12 +- src/xrpld/net/detail/RegisterSSLCerts.cpp | 2 +- src/xrpld/nodestore/Backend.h | 2 +- src/xrpld/nodestore/Database.h | 10 +- src/xrpld/nodestore/DatabaseRotating.h | 2 +- src/xrpld/nodestore/DatabaseShard.h | 10 +- src/xrpld/nodestore/DummyScheduler.h | 2 +- src/xrpld/nodestore/Factory.h | 6 +- src/xrpld/nodestore/Manager.h | 6 +- src/xrpld/nodestore/NodeObject.h | 6 +- src/xrpld/nodestore/Scheduler.h | 2 +- src/xrpld/nodestore/ShardInfo.h | 6 +- src/xrpld/nodestore/Types.h | 4 +- .../nodestore/backend/CassandraFactory.cpp | 22 ++-- src/xrpld/nodestore/backend/MemoryFactory.cpp | 6 +- src/xrpld/nodestore/backend/NuDBFactory.cpp | 12 +- src/xrpld/nodestore/backend/NullFactory.cpp | 6 +- .../nodestore/backend/RocksDBFactory.cpp | 22 ++-- src/xrpld/nodestore/detail/BatchWriter.cpp | 2 +- src/xrpld/nodestore/detail/BatchWriter.h | 6 +- src/xrpld/nodestore/detail/Database.cpp | 14 +-- .../nodestore/detail/DatabaseNodeImp.cpp | 6 +- src/xrpld/nodestore/detail/DatabaseNodeImp.h | 6 +- .../nodestore/detail/DatabaseRotatingImp.cpp | 6 +- .../nodestore/detail/DatabaseRotatingImp.h | 2 +- .../nodestore/detail/DatabaseShardImp.cpp | 32 ++--- src/xrpld/nodestore/detail/DatabaseShardImp.h | 6 +- src/xrpld/nodestore/detail/DecodedBlob.cpp | 4 +- src/xrpld/nodestore/detail/DecodedBlob.h | 2 +- .../nodestore/detail/DeterministicShard.cpp | 14 +-- .../nodestore/detail/DeterministicShard.h | 4 +- src/xrpld/nodestore/detail/DummyScheduler.cpp | 2 +- src/xrpld/nodestore/detail/EncodedBlob.h | 4 +- src/xrpld/nodestore/detail/ManagerImp.cpp | 4 +- src/xrpld/nodestore/detail/ManagerImp.h | 2 +- src/xrpld/nodestore/detail/NodeObject.cpp | 2 +- src/xrpld/nodestore/detail/Shard.cpp | 20 +-- src/xrpld/nodestore/detail/Shard.h | 22 ++-- src/xrpld/nodestore/detail/ShardInfo.cpp | 10 +- src/xrpld/nodestore/detail/TaskQueue.cpp | 2 +- src/xrpld/nodestore/detail/TaskQueue.h | 2 +- src/xrpld/nodestore/detail/codec.h | 10 +- src/xrpld/overlay/Cluster.h | 14 +-- src/xrpld/overlay/ClusterNode.h | 4 +- src/xrpld/overlay/Compression.h | 4 +- src/xrpld/overlay/Message.h | 8 +- src/xrpld/overlay/Overlay.h | 10 +- src/xrpld/overlay/Peer.h | 10 +- src/xrpld/overlay/PeerReservationTable.h | 10 +- src/xrpld/overlay/PeerSet.h | 10 +- src/xrpld/overlay/Slot.h | 18 +-- src/xrpld/overlay/Squelch.h | 8 +- src/xrpld/overlay/detail/Cluster.cpp | 16 +-- src/xrpld/overlay/detail/ConnectAttempt.cpp | 10 +- src/xrpld/overlay/detail/ConnectAttempt.h | 4 +- src/xrpld/overlay/detail/Handshake.cpp | 14 +-- src/xrpld/overlay/detail/Handshake.h | 8 +- src/xrpld/overlay/detail/Message.cpp | 4 +- src/xrpld/overlay/detail/OverlayImpl.cpp | 40 +++--- src/xrpld/overlay/detail/OverlayImpl.h | 30 ++--- src/xrpld/overlay/detail/PeerImp.cpp | 44 +++---- src/xrpld/overlay/detail/PeerImp.h | 32 ++--- .../overlay/detail/PeerReservationTable.cpp | 16 +-- src/xrpld/overlay/detail/PeerSet.cpp | 8 +- src/xrpld/overlay/detail/ProtocolMessage.h | 10 +- src/xrpld/overlay/detail/ProtocolVersion.cpp | 6 +- src/xrpld/overlay/detail/TrafficCount.cpp | 2 +- src/xrpld/overlay/detail/TrafficCount.h | 4 +- src/xrpld/overlay/detail/TxMetrics.cpp | 4 +- src/xrpld/overlay/detail/TxMetrics.h | 4 +- src/xrpld/overlay/make_Overlay.h | 8 +- src/xrpld/overlay/predicates.h | 4 +- src/xrpld/peerfinder/PeerfinderManager.h | 8 +- src/xrpld/peerfinder/Slot.h | 4 +- src/xrpld/peerfinder/detail/Bootcache.cpp | 8 +- src/xrpld/peerfinder/detail/Bootcache.h | 10 +- src/xrpld/peerfinder/detail/Checker.h | 2 +- src/xrpld/peerfinder/detail/Counts.h | 8 +- src/xrpld/peerfinder/detail/Endpoint.cpp | 4 +- src/xrpld/peerfinder/detail/Fixed.h | 2 +- src/xrpld/peerfinder/detail/Handouts.h | 6 +- src/xrpld/peerfinder/detail/Livecache.h | 14 +-- src/xrpld/peerfinder/detail/Logic.h | 32 ++--- .../peerfinder/detail/PeerfinderConfig.cpp | 4 +- .../peerfinder/detail/PeerfinderManager.cpp | 10 +- src/xrpld/peerfinder/detail/SlotImp.cpp | 6 +- src/xrpld/peerfinder/detail/SlotImp.h | 8 +- src/xrpld/peerfinder/detail/Source.h | 2 +- src/xrpld/peerfinder/detail/SourceStrings.cpp | 2 +- src/xrpld/peerfinder/detail/SourceStrings.h | 2 +- src/xrpld/peerfinder/detail/StoreSqdb.h | 8 +- src/xrpld/peerfinder/make_Manager.h | 2 +- src/xrpld/perflog/PerfLog.h | 6 +- src/xrpld/perflog/detail/PerfLogImp.cpp | 18 +-- src/xrpld/perflog/detail/PerfLogImp.h | 10 +- src/xrpld/rpc/Context.h | 10 +- src/xrpld/rpc/DeliveredAmount.h | 4 +- src/xrpld/rpc/GRPCHandlers.h | 4 +- src/xrpld/rpc/RPCHandler.h | 8 +- src/xrpld/rpc/Request.h | 8 +- src/xrpld/rpc/Role.h | 10 +- src/xrpld/rpc/ServerHandler.h | 16 +-- src/xrpld/rpc/ShardArchiveHandler.h | 12 +- src/xrpld/rpc/ShardVerificationScheduler.h | 2 +- src/xrpld/rpc/Status.h | 4 +- src/xrpld/rpc/detail/DeliveredAmount.cpp | 22 ++-- src/xrpld/rpc/detail/Handler.cpp | 10 +- src/xrpld/rpc/detail/Handler.h | 14 +-- src/xrpld/rpc/detail/LegacyPathFind.cpp | 12 +- src/xrpld/rpc/detail/RPCHandler.cpp | 46 +++---- src/xrpld/rpc/detail/RPCHelpers.cpp | 32 ++--- src/xrpld/rpc/detail/RPCHelpers.h | 22 ++-- src/xrpld/rpc/detail/Role.cpp | 2 +- src/xrpld/rpc/detail/ServerHandler.cpp | 54 ++++----- src/xrpld/rpc/detail/ShardArchiveHandler.cpp | 16 +-- .../rpc/detail/ShardVerificationScheduler.cpp | 4 +- src/xrpld/rpc/detail/Status.cpp | 2 +- src/xrpld/rpc/detail/TransactionSign.cpp | 46 +++---- src/xrpld/rpc/detail/TransactionSign.h | 6 +- src/xrpld/rpc/detail/WSInfoSub.h | 10 +- src/xrpld/rpc/handlers/AMMInfo.cpp | 18 +-- src/xrpld/rpc/handlers/AccountChannels.cpp | 24 ++-- .../rpc/handlers/AccountCurrenciesHandler.cpp | 16 +-- src/xrpld/rpc/handlers/AccountInfo.cpp | 22 ++-- src/xrpld/rpc/handlers/AccountLines.cpp | 20 +-- src/xrpld/rpc/handlers/AccountObjects.cpp | 26 ++-- src/xrpld/rpc/handlers/AccountOffers.cpp | 22 ++-- src/xrpld/rpc/handlers/AccountTx.cpp | 40 +++--- src/xrpld/rpc/handlers/BlackList.cpp | 8 +- src/xrpld/rpc/handlers/BookOffers.cpp | 24 ++-- src/xrpld/rpc/handlers/CanDelete.cpp | 16 +-- src/xrpld/rpc/handlers/Connect.cpp | 18 +-- src/xrpld/rpc/handlers/ConsensusInfo.cpp | 14 +-- src/xrpld/rpc/handlers/CrawlShards.cpp | 18 +-- src/xrpld/rpc/handlers/DepositAuthorized.cpp | 14 +-- src/xrpld/rpc/handlers/DownloadShard.cpp | 18 +-- src/xrpld/rpc/handlers/Feature1.cpp | 16 +-- src/xrpld/rpc/handlers/Fee1.cpp | 14 +-- src/xrpld/rpc/handlers/FetchInfo.cpp | 14 +-- src/xrpld/rpc/handlers/GatewayBalances.cpp | 22 ++-- src/xrpld/rpc/handlers/GetAggregatePrice.cpp | 16 +-- src/xrpld/rpc/handlers/GetCounts.cpp | 32 ++--- src/xrpld/rpc/handlers/GetCounts.h | 4 +- src/xrpld/rpc/handlers/Handlers.h | 2 +- src/xrpld/rpc/handlers/LedgerAccept.cpp | 18 +-- .../rpc/handlers/LedgerCleanerHandler.cpp | 10 +- src/xrpld/rpc/handlers/LedgerClosed.cpp | 10 +- src/xrpld/rpc/handlers/LedgerCurrent.cpp | 12 +- src/xrpld/rpc/handlers/LedgerData.cpp | 20 +-- src/xrpld/rpc/handlers/LedgerDiff.cpp | 4 +- src/xrpld/rpc/handlers/LedgerEntry.cpp | 28 ++--- src/xrpld/rpc/handlers/LedgerHandler.cpp | 20 +-- src/xrpld/rpc/handlers/LedgerHandler.h | 22 ++-- src/xrpld/rpc/handlers/LedgerHeader.cpp | 10 +- src/xrpld/rpc/handlers/LedgerRequest.cpp | 22 ++-- src/xrpld/rpc/handlers/LogLevel.cpp | 14 +-- src/xrpld/rpc/handlers/LogRotate.cpp | 8 +- src/xrpld/rpc/handlers/Manifest.cpp | 14 +-- src/xrpld/rpc/handlers/NFTOffers.cpp | 22 ++-- src/xrpld/rpc/handlers/NoRippleCheck.cpp | 22 ++-- src/xrpld/rpc/handlers/NodeToShard.cpp | 16 +-- src/xrpld/rpc/handlers/OwnerInfo.cpp | 16 +-- src/xrpld/rpc/handlers/PathFind.cpp | 18 +-- src/xrpld/rpc/handlers/PayChanClaim.cpp | 24 ++-- src/xrpld/rpc/handlers/Peers.cpp | 16 +-- src/xrpld/rpc/handlers/Ping.cpp | 8 +- src/xrpld/rpc/handlers/Print.cpp | 10 +- src/xrpld/rpc/handlers/Random.cpp | 14 +-- src/xrpld/rpc/handlers/Reservations.cpp | 14 +-- src/xrpld/rpc/handlers/RipplePathFind.cpp | 14 +-- src/xrpld/rpc/handlers/ServerInfo.cpp | 28 ++--- src/xrpld/rpc/handlers/ServerState.cpp | 14 +-- src/xrpld/rpc/handlers/SignFor.cpp | 12 +- src/xrpld/rpc/handlers/SignHandler.cpp | 10 +- src/xrpld/rpc/handlers/Stop.cpp | 6 +- src/xrpld/rpc/handlers/Submit.cpp | 22 ++-- src/xrpld/rpc/handlers/SubmitMultiSigned.cpp | 12 +- src/xrpld/rpc/handlers/Subscribe.cpp | 26 ++-- src/xrpld/rpc/handlers/TransactionEntry.cpp | 14 +-- src/xrpld/rpc/handlers/Tx.cpp | 32 ++--- src/xrpld/rpc/handlers/TxHistory.cpp | 30 ++--- src/xrpld/rpc/handlers/TxReduceRelay.cpp | 8 +- src/xrpld/rpc/handlers/UnlList.cpp | 12 +- src/xrpld/rpc/handlers/Unsubscribe.cpp | 16 +-- src/xrpld/rpc/handlers/ValidationCreate.cpp | 12 +- src/xrpld/rpc/handlers/ValidatorInfo.cpp | 14 +-- src/xrpld/rpc/handlers/ValidatorListSites.cpp | 10 +- src/xrpld/rpc/handlers/Validators.cpp | 10 +- src/xrpld/rpc/handlers/Version.h | 2 +- src/xrpld/rpc/handlers/WalletPropose.cpp | 22 ++-- src/xrpld/rpc/handlers/WalletPropose.h | 2 +- src/xrpld/rpc/json_body.h | 4 +- src/xrpld/shamap/Family.h | 10 +- src/xrpld/shamap/FullBelowCache.h | 10 +- src/xrpld/shamap/NodeFamily.h | 4 +- src/xrpld/shamap/SHAMap.h | 26 ++-- src/xrpld/shamap/SHAMapAccountStateLeafNode.h | 12 +- src/xrpld/shamap/SHAMapInnerNode.h | 12 +- src/xrpld/shamap/SHAMapItem.h | 10 +- src/xrpld/shamap/SHAMapLeafNode.h | 6 +- src/xrpld/shamap/SHAMapMissingNode.h | 4 +- src/xrpld/shamap/SHAMapNodeID.h | 4 +- src/xrpld/shamap/SHAMapSyncFilter.h | 4 +- src/xrpld/shamap/SHAMapTreeNode.h | 14 +-- src/xrpld/shamap/SHAMapTxLeafNode.h | 12 +- src/xrpld/shamap/SHAMapTxPlusMetaLeafNode.h | 12 +- src/xrpld/shamap/ShardFamily.h | 4 +- src/xrpld/shamap/TreeNodeCache.h | 2 +- src/xrpld/shamap/detail/NodeFamily.cpp | 8 +- src/xrpld/shamap/detail/SHAMap.cpp | 14 +-- src/xrpld/shamap/detail/SHAMapDelta.cpp | 4 +- src/xrpld/shamap/detail/SHAMapInnerNode.cpp | 22 ++-- src/xrpld/shamap/detail/SHAMapLeafNode.cpp | 6 +- src/xrpld/shamap/detail/SHAMapNodeID.cpp | 10 +- src/xrpld/shamap/detail/SHAMapSync.cpp | 6 +- src/xrpld/shamap/detail/SHAMapTreeNode.cpp | 26 ++-- src/xrpld/shamap/detail/ShardFamily.cpp | 10 +- src/xrpld/shamap/detail/TaggedPointer.h | 2 +- src/xrpld/shamap/detail/TaggedPointer.ipp | 6 +- 1153 files changed, 5480 insertions(+), 5480 deletions(-) diff --git a/include/xrpl/basics/BasicConfig.h b/include/xrpl/basics/BasicConfig.h index db293979f13..8f522cdd2f2 100644 --- a/include/xrpl/basics/BasicConfig.h +++ b/include/xrpl/basics/BasicConfig.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_BASICS_BASICCONFIG_H_INCLUDED #define RIPPLE_BASICS_BASICCONFIG_H_INCLUDED -#include +#include #include #include #include diff --git a/include/xrpl/basics/Buffer.h b/include/xrpl/basics/Buffer.h index 706b8b627f1..25ae8ca315c 100644 --- a/include/xrpl/basics/Buffer.h +++ b/include/xrpl/basics/Buffer.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_BASICS_BUFFER_H_INCLUDED #define RIPPLE_BASICS_BUFFER_H_INCLUDED -#include +#include #include #include #include diff --git a/include/xrpl/basics/CompressionAlgorithms.h b/include/xrpl/basics/CompressionAlgorithms.h index eef2608916d..4defd5a4904 100644 --- a/include/xrpl/basics/CompressionAlgorithms.h +++ b/include/xrpl/basics/CompressionAlgorithms.h @@ -20,7 +20,7 @@ #ifndef RIPPLED_COMPRESSIONALGORITHMS_H_INCLUDED #define RIPPLED_COMPRESSIONALGORITHMS_H_INCLUDED -#include +#include #include #include #include diff --git a/include/xrpl/basics/CountedObject.h b/include/xrpl/basics/CountedObject.h index 690841fe1ef..9ea76aa3bd0 100644 --- a/include/xrpl/basics/CountedObject.h +++ b/include/xrpl/basics/CountedObject.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_BASICS_COUNTEDOBJECT_H_INCLUDED #define RIPPLE_BASICS_COUNTEDOBJECT_H_INCLUDED -#include +#include #include #include #include diff --git a/include/xrpl/basics/Expected.h b/include/xrpl/basics/Expected.h index bb699579b17..745fa50a69f 100644 --- a/include/xrpl/basics/Expected.h +++ b/include/xrpl/basics/Expected.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_BASICS_EXPECTED_H_INCLUDED #define RIPPLE_BASICS_EXPECTED_H_INCLUDED -#include +#include #include diff --git a/include/xrpl/basics/FeeUnits.h b/include/xrpl/basics/FeeUnits.h index 35e0ff24d05..9d5e6e216a4 100644 --- a/include/xrpl/basics/FeeUnits.h +++ b/include/xrpl/basics/FeeUnits.h @@ -19,7 +19,7 @@ #ifndef BASICS_FEES_H_INCLUDED #define BASICS_FEES_H_INCLUDED -#include +#include #include #include #include diff --git a/include/xrpl/basics/IOUAmount.h b/include/xrpl/basics/IOUAmount.h index 2380a7d15e1..221434aa85a 100644 --- a/include/xrpl/basics/IOUAmount.h +++ b/include/xrpl/basics/IOUAmount.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_BASICS_IOUAMOUNT_H_INCLUDED #define RIPPLE_BASICS_IOUAMOUNT_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/basics/KeyCache.h b/include/xrpl/basics/KeyCache.h index d8fa4910ab9..1439a8b3344 100644 --- a/include/xrpl/basics/KeyCache.h +++ b/include/xrpl/basics/KeyCache.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_BASICS_KEYCACHE_H #define RIPPLE_BASICS_KEYCACHE_H -#include -#include +#include +#include namespace ripple { diff --git a/include/xrpl/basics/Log.h b/include/xrpl/basics/Log.h index 929225c0433..0117f2f9aab 100644 --- a/include/xrpl/basics/Log.h +++ b/include/xrpl/basics/Log.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_BASICS_LOG_H_INCLUDED #define RIPPLE_BASICS_LOG_H_INCLUDED -#include -#include +#include +#include #include #include #include diff --git a/include/xrpl/basics/Number.h b/include/xrpl/basics/Number.h index cdc25b3b27d..30ce3f73173 100644 --- a/include/xrpl/basics/Number.h +++ b/include/xrpl/basics/Number.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_BASICS_NUMBER_H_INCLUDED #define RIPPLE_BASICS_NUMBER_H_INCLUDED -#include +#include #include #include #include diff --git a/include/xrpl/basics/RangeSet.h b/include/xrpl/basics/RangeSet.h index 3a9e470ddfb..0ffed2db1e2 100644 --- a/include/xrpl/basics/RangeSet.h +++ b/include/xrpl/basics/RangeSet.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_BASICS_RANGESET_H_INCLUDED #define RIPPLE_BASICS_RANGESET_H_INCLUDED -#include +#include #include #include diff --git a/include/xrpl/basics/Resolver.h b/include/xrpl/basics/Resolver.h index abf04005707..6cba352e0a0 100644 --- a/include/xrpl/basics/Resolver.h +++ b/include/xrpl/basics/Resolver.h @@ -23,7 +23,7 @@ #include #include -#include +#include namespace ripple { diff --git a/include/xrpl/basics/ResolverAsio.h b/include/xrpl/basics/ResolverAsio.h index 191cdc097ad..51fcbdfb0d8 100644 --- a/include/xrpl/basics/ResolverAsio.h +++ b/include/xrpl/basics/ResolverAsio.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_BASICS_RESOLVERASIO_H_INCLUDED #define RIPPLE_BASICS_RESOLVERASIO_H_INCLUDED -#include -#include +#include +#include #include namespace ripple { diff --git a/include/xrpl/basics/SHAMapHash.h b/include/xrpl/basics/SHAMapHash.h index 796510ba182..7e93ead78d3 100644 --- a/include/xrpl/basics/SHAMapHash.h +++ b/include/xrpl/basics/SHAMapHash.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_BASICS_SHAMAP_HASH_H_INCLUDED #define RIPPLE_BASICS_SHAMAP_HASH_H_INCLUDED -#include +#include #include diff --git a/include/xrpl/basics/SlabAllocator.h b/include/xrpl/basics/SlabAllocator.h index ece96d0b873..5c4cba343cf 100644 --- a/include/xrpl/basics/SlabAllocator.h +++ b/include/xrpl/basics/SlabAllocator.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_BASICS_SLABALLOCATOR_H_INCLUDED #define RIPPLE_BASICS_SLABALLOCATOR_H_INCLUDED -#include +#include #include #include diff --git a/include/xrpl/basics/Slice.h b/include/xrpl/basics/Slice.h index 0ba6a94b62b..00126f8882d 100644 --- a/include/xrpl/basics/Slice.h +++ b/include/xrpl/basics/Slice.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_BASICS_SLICE_H_INCLUDED #define RIPPLE_BASICS_SLICE_H_INCLUDED -#include -#include +#include +#include #include #include #include diff --git a/include/xrpl/basics/StringUtilities.h b/include/xrpl/basics/StringUtilities.h index 69314ce096e..23d60e2db49 100644 --- a/include/xrpl/basics/StringUtilities.h +++ b/include/xrpl/basics/StringUtilities.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_BASICS_STRINGUTILITIES_H_INCLUDED #define RIPPLE_BASICS_STRINGUTILITIES_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/include/xrpl/basics/TaggedCache.h b/include/xrpl/basics/TaggedCache.h index 6765ff16bee..1fcdc3707b6 100644 --- a/include/xrpl/basics/TaggedCache.h +++ b/include/xrpl/basics/TaggedCache.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED #define RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/basics/UnorderedContainers.h b/include/xrpl/basics/UnorderedContainers.h index e929ebec898..b689a1b6ac8 100644 --- a/include/xrpl/basics/UnorderedContainers.h +++ b/include/xrpl/basics/UnorderedContainers.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_BASICS_UNORDEREDCONTAINERS_H_INCLUDED #define RIPPLE_BASICS_UNORDEREDCONTAINERS_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/include/xrpl/basics/XRPAmount.h b/include/xrpl/basics/XRPAmount.h index 08f82b1752e..1d3b32f169b 100644 --- a/include/xrpl/basics/XRPAmount.h +++ b/include/xrpl/basics/XRPAmount.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_BASICS_XRPAMOUNT_H_INCLUDED #define RIPPLE_BASICS_XRPAMOUNT_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/include/xrpl/basics/base_uint.h b/include/xrpl/basics/base_uint.h index 8b15b082647..2b44d3072ee 100644 --- a/include/xrpl/basics/base_uint.h +++ b/include/xrpl/basics/base_uint.h @@ -25,12 +25,12 @@ #ifndef RIPPLE_BASICS_BASE_UINT_H_INCLUDED #define RIPPLE_BASICS_BASE_UINT_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/basics/chrono.h b/include/xrpl/basics/chrono.h index ea82f928b7e..d739b6bf44b 100644 --- a/include/xrpl/basics/chrono.h +++ b/include/xrpl/basics/chrono.h @@ -22,9 +22,9 @@ #include -#include -#include -#include +#include +#include +#include #include #include diff --git a/include/xrpl/basics/contract.h b/include/xrpl/basics/contract.h index 80aeee7a387..bdfc8aac362 100644 --- a/include/xrpl/basics/contract.h +++ b/include/xrpl/basics/contract.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_BASICS_CONTRACT_H_INCLUDED #define RIPPLE_BASICS_CONTRACT_H_INCLUDED -#include +#include #include #include #include diff --git a/include/xrpl/basics/hardened_hash.h b/include/xrpl/basics/hardened_hash.h index bc20409286e..0b77b0a07a8 100644 --- a/include/xrpl/basics/hardened_hash.h +++ b/include/xrpl/basics/hardened_hash.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_BASICS_HARDENED_HASH_H_INCLUDED #define RIPPLE_BASICS_HARDENED_HASH_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/include/xrpl/basics/random.h b/include/xrpl/basics/random.h index 3af8be54109..87b303bf6d5 100644 --- a/include/xrpl/basics/random.h +++ b/include/xrpl/basics/random.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_BASICS_RANDOM_H_INCLUDED #define RIPPLE_BASICS_RANDOM_H_INCLUDED -#include +#include #include #include #include diff --git a/include/xrpl/basics/tagged_integer.h b/include/xrpl/basics/tagged_integer.h index fe11f882726..3ab8c534098 100644 --- a/include/xrpl/basics/tagged_integer.h +++ b/include/xrpl/basics/tagged_integer.h @@ -20,7 +20,7 @@ #ifndef BEAST_UTILITY_TAGGED_INTEGER_H_INCLUDED #define BEAST_UTILITY_TAGGED_INTEGER_H_INCLUDED -#include +#include #include #include #include diff --git a/include/xrpl/beast/clock/manual_clock.h b/include/xrpl/beast/clock/manual_clock.h index 808b0071006..97be8e79b90 100644 --- a/include/xrpl/beast/clock/manual_clock.h +++ b/include/xrpl/beast/clock/manual_clock.h @@ -20,7 +20,7 @@ #ifndef BEAST_CHRONO_MANUAL_CLOCK_H_INCLUDED #define BEAST_CHRONO_MANUAL_CLOCK_H_INCLUDED -#include +#include #include namespace beast { diff --git a/include/xrpl/beast/container/aged_container_utility.h b/include/xrpl/beast/container/aged_container_utility.h index dc57c229fb5..b64cefbf5ad 100644 --- a/include/xrpl/beast/container/aged_container_utility.h +++ b/include/xrpl/beast/container/aged_container_utility.h @@ -20,7 +20,7 @@ #ifndef BEAST_CONTAINER_AGED_CONTAINER_UTILITY_H_INCLUDED #define BEAST_CONTAINER_AGED_CONTAINER_UTILITY_H_INCLUDED -#include +#include #include diff --git a/include/xrpl/beast/container/aged_map.h b/include/xrpl/beast/container/aged_map.h index f675846fa64..5b56cde9625 100644 --- a/include/xrpl/beast/container/aged_map.h +++ b/include/xrpl/beast/container/aged_map.h @@ -20,7 +20,7 @@ #ifndef BEAST_CONTAINER_AGED_MAP_H_INCLUDED #define BEAST_CONTAINER_AGED_MAP_H_INCLUDED -#include +#include #include #include diff --git a/include/xrpl/beast/container/aged_multimap.h b/include/xrpl/beast/container/aged_multimap.h index b4668851c3d..aa6c01f5b32 100644 --- a/include/xrpl/beast/container/aged_multimap.h +++ b/include/xrpl/beast/container/aged_multimap.h @@ -20,7 +20,7 @@ #ifndef BEAST_CONTAINER_AGED_MULTIMAP_H_INCLUDED #define BEAST_CONTAINER_AGED_MULTIMAP_H_INCLUDED -#include +#include #include #include diff --git a/include/xrpl/beast/container/aged_multiset.h b/include/xrpl/beast/container/aged_multiset.h index 6d62bcbeb36..d43cc8d5a70 100644 --- a/include/xrpl/beast/container/aged_multiset.h +++ b/include/xrpl/beast/container/aged_multiset.h @@ -20,7 +20,7 @@ #ifndef BEAST_CONTAINER_AGED_MULTISET_H_INCLUDED #define BEAST_CONTAINER_AGED_MULTISET_H_INCLUDED -#include +#include #include #include diff --git a/include/xrpl/beast/container/aged_set.h b/include/xrpl/beast/container/aged_set.h index 0a9d82f6cb2..aa31a47af4a 100644 --- a/include/xrpl/beast/container/aged_set.h +++ b/include/xrpl/beast/container/aged_set.h @@ -20,7 +20,7 @@ #ifndef BEAST_CONTAINER_AGED_SET_H_INCLUDED #define BEAST_CONTAINER_AGED_SET_H_INCLUDED -#include +#include #include #include diff --git a/include/xrpl/beast/container/aged_unordered_map.h b/include/xrpl/beast/container/aged_unordered_map.h index 1b6a147ef03..b466c87b3ff 100644 --- a/include/xrpl/beast/container/aged_unordered_map.h +++ b/include/xrpl/beast/container/aged_unordered_map.h @@ -20,7 +20,7 @@ #ifndef BEAST_CONTAINER_AGED_UNORDERED_MAP_H_INCLUDED #define BEAST_CONTAINER_AGED_UNORDERED_MAP_H_INCLUDED -#include +#include #include #include diff --git a/include/xrpl/beast/container/aged_unordered_multimap.h b/include/xrpl/beast/container/aged_unordered_multimap.h index 1298cd51d0e..e64c8415c61 100644 --- a/include/xrpl/beast/container/aged_unordered_multimap.h +++ b/include/xrpl/beast/container/aged_unordered_multimap.h @@ -20,7 +20,7 @@ #ifndef BEAST_CONTAINER_AGED_UNORDERED_MULTIMAP_H_INCLUDED #define BEAST_CONTAINER_AGED_UNORDERED_MULTIMAP_H_INCLUDED -#include +#include #include #include diff --git a/include/xrpl/beast/container/aged_unordered_multiset.h b/include/xrpl/beast/container/aged_unordered_multiset.h index 5e9f682aa6b..499dc7d6780 100644 --- a/include/xrpl/beast/container/aged_unordered_multiset.h +++ b/include/xrpl/beast/container/aged_unordered_multiset.h @@ -20,7 +20,7 @@ #ifndef BEAST_CONTAINER_AGED_UNORDERED_MULTISET_H_INCLUDED #define BEAST_CONTAINER_AGED_UNORDERED_MULTISET_H_INCLUDED -#include +#include #include #include diff --git a/include/xrpl/beast/container/aged_unordered_set.h b/include/xrpl/beast/container/aged_unordered_set.h index adb411c344c..45fc6cd0ed8 100644 --- a/include/xrpl/beast/container/aged_unordered_set.h +++ b/include/xrpl/beast/container/aged_unordered_set.h @@ -20,7 +20,7 @@ #ifndef BEAST_CONTAINER_AGED_UNORDERED_SET_H_INCLUDED #define BEAST_CONTAINER_AGED_UNORDERED_SET_H_INCLUDED -#include +#include #include #include diff --git a/include/xrpl/beast/container/detail/aged_ordered_container.h b/include/xrpl/beast/container/detail/aged_ordered_container.h index 10dca962b13..90a8ea147ae 100644 --- a/include/xrpl/beast/container/detail/aged_ordered_container.h +++ b/include/xrpl/beast/container/detail/aged_ordered_container.h @@ -20,11 +20,11 @@ #ifndef BEAST_CONTAINER_DETAIL_AGED_ORDERED_CONTAINER_H_INCLUDED #define BEAST_CONTAINER_DETAIL_AGED_ORDERED_CONTAINER_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/beast/container/detail/aged_unordered_container.h b/include/xrpl/beast/container/detail/aged_unordered_container.h index fcdccd2a637..45efb3f5561 100644 --- a/include/xrpl/beast/container/detail/aged_unordered_container.h +++ b/include/xrpl/beast/container/detail/aged_unordered_container.h @@ -20,11 +20,11 @@ #ifndef BEAST_CONTAINER_DETAIL_AGED_UNORDERED_CONTAINER_H_INCLUDED #define BEAST_CONTAINER_DETAIL_AGED_UNORDERED_CONTAINER_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/beast/hash/uhash.h b/include/xrpl/beast/hash/uhash.h index 921ea3c9840..ab3eaad0392 100644 --- a/include/xrpl/beast/hash/uhash.h +++ b/include/xrpl/beast/hash/uhash.h @@ -21,8 +21,8 @@ #ifndef BEAST_HASH_UHASH_H_INCLUDED #define BEAST_HASH_UHASH_H_INCLUDED -#include -#include +#include +#include namespace beast { diff --git a/include/xrpl/beast/insight/Collector.h b/include/xrpl/beast/insight/Collector.h index a71b1092c85..eab2bd7d70c 100644 --- a/include/xrpl/beast/insight/Collector.h +++ b/include/xrpl/beast/insight/Collector.h @@ -20,11 +20,11 @@ #ifndef BEAST_INSIGHT_COLLECTOR_H_INCLUDED #define BEAST_INSIGHT_COLLECTOR_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include diff --git a/include/xrpl/beast/insight/Counter.h b/include/xrpl/beast/insight/Counter.h index 069505e4ce5..3f3a251de89 100644 --- a/include/xrpl/beast/insight/Counter.h +++ b/include/xrpl/beast/insight/Counter.h @@ -20,7 +20,7 @@ #ifndef BEAST_INSIGHT_COUNTER_H_INCLUDED #define BEAST_INSIGHT_COUNTER_H_INCLUDED -#include +#include #include diff --git a/include/xrpl/beast/insight/Event.h b/include/xrpl/beast/insight/Event.h index 5319a9a6677..407dd233e95 100644 --- a/include/xrpl/beast/insight/Event.h +++ b/include/xrpl/beast/insight/Event.h @@ -20,7 +20,7 @@ #ifndef BEAST_INSIGHT_EVENT_H_INCLUDED #define BEAST_INSIGHT_EVENT_H_INCLUDED -#include +#include #include #include diff --git a/include/xrpl/beast/insight/Gauge.h b/include/xrpl/beast/insight/Gauge.h index 76f84080766..b1e8bedfac2 100644 --- a/include/xrpl/beast/insight/Gauge.h +++ b/include/xrpl/beast/insight/Gauge.h @@ -20,7 +20,7 @@ #ifndef BEAST_INSIGHT_GAUGE_H_INCLUDED #define BEAST_INSIGHT_GAUGE_H_INCLUDED -#include +#include #include diff --git a/include/xrpl/beast/insight/Group.h b/include/xrpl/beast/insight/Group.h index a37656b81a5..f11b1397c8b 100644 --- a/include/xrpl/beast/insight/Group.h +++ b/include/xrpl/beast/insight/Group.h @@ -20,7 +20,7 @@ #ifndef BEAST_INSIGHT_GROUP_H_INCLUDED #define BEAST_INSIGHT_GROUP_H_INCLUDED -#include +#include #include #include diff --git a/include/xrpl/beast/insight/Groups.h b/include/xrpl/beast/insight/Groups.h index 817ad87bd1a..456deb79073 100644 --- a/include/xrpl/beast/insight/Groups.h +++ b/include/xrpl/beast/insight/Groups.h @@ -20,8 +20,8 @@ #ifndef BEAST_INSIGHT_GROUPS_H_INCLUDED #define BEAST_INSIGHT_GROUPS_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/include/xrpl/beast/insight/Hook.h b/include/xrpl/beast/insight/Hook.h index 04647f4b632..affa42bb828 100644 --- a/include/xrpl/beast/insight/Hook.h +++ b/include/xrpl/beast/insight/Hook.h @@ -20,7 +20,7 @@ #ifndef BEAST_INSIGHT_HOOK_H_INCLUDED #define BEAST_INSIGHT_HOOK_H_INCLUDED -#include +#include #include diff --git a/include/xrpl/beast/insight/Insight.h b/include/xrpl/beast/insight/Insight.h index f34f7317483..1c2c1375a28 100644 --- a/include/xrpl/beast/insight/Insight.h +++ b/include/xrpl/beast/insight/Insight.h @@ -20,18 +20,18 @@ #ifndef BEAST_INSIGHT_H_INCLUDED #define BEAST_INSIGHT_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #endif diff --git a/include/xrpl/beast/insight/Meter.h b/include/xrpl/beast/insight/Meter.h index 376dcae0521..febd5cb3dc4 100644 --- a/include/xrpl/beast/insight/Meter.h +++ b/include/xrpl/beast/insight/Meter.h @@ -22,7 +22,7 @@ #include -#include +#include namespace beast { namespace insight { diff --git a/include/xrpl/beast/insight/NullCollector.h b/include/xrpl/beast/insight/NullCollector.h index db98153836e..4379c3ceb98 100644 --- a/include/xrpl/beast/insight/NullCollector.h +++ b/include/xrpl/beast/insight/NullCollector.h @@ -20,7 +20,7 @@ #ifndef BEAST_INSIGHT_NULLCOLLECTOR_H_INCLUDED #define BEAST_INSIGHT_NULLCOLLECTOR_H_INCLUDED -#include +#include namespace beast { namespace insight { diff --git a/include/xrpl/beast/insight/StatsDCollector.h b/include/xrpl/beast/insight/StatsDCollector.h index d95aee04d0b..78195048d7f 100644 --- a/include/xrpl/beast/insight/StatsDCollector.h +++ b/include/xrpl/beast/insight/StatsDCollector.h @@ -20,10 +20,10 @@ #ifndef BEAST_INSIGHT_STATSDCOLLECTOR_H_INCLUDED #define BEAST_INSIGHT_STATSDCOLLECTOR_H_INCLUDED -#include +#include -#include -#include +#include +#include namespace beast { namespace insight { diff --git a/include/xrpl/beast/net/IPAddress.h b/include/xrpl/beast/net/IPAddress.h index d8820ec40b5..f3a1a7348f2 100644 --- a/include/xrpl/beast/net/IPAddress.h +++ b/include/xrpl/beast/net/IPAddress.h @@ -20,10 +20,10 @@ #ifndef BEAST_NET_IPADDRESS_H_INCLUDED #define BEAST_NET_IPADDRESS_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/beast/net/IPAddressConversion.h b/include/xrpl/beast/net/IPAddressConversion.h index e37dd5b6c61..982a8e50f26 100644 --- a/include/xrpl/beast/net/IPAddressConversion.h +++ b/include/xrpl/beast/net/IPAddressConversion.h @@ -20,7 +20,7 @@ #ifndef BEAST_NET_IPADDRESSCONVERSION_H_INCLUDED #define BEAST_NET_IPADDRESSCONVERSION_H_INCLUDED -#include +#include #include diff --git a/include/xrpl/beast/net/IPAddressV4.h b/include/xrpl/beast/net/IPAddressV4.h index 2c6f6a8cced..7711a970dec 100644 --- a/include/xrpl/beast/net/IPAddressV4.h +++ b/include/xrpl/beast/net/IPAddressV4.h @@ -20,7 +20,7 @@ #ifndef BEAST_NET_IPADDRESSV4_H_INCLUDED #define BEAST_NET_IPADDRESSV4_H_INCLUDED -#include +#include #include #include #include diff --git a/include/xrpl/beast/net/IPEndpoint.h b/include/xrpl/beast/net/IPEndpoint.h index 19ce36dcc3b..e66e7f4caae 100644 --- a/include/xrpl/beast/net/IPEndpoint.h +++ b/include/xrpl/beast/net/IPEndpoint.h @@ -20,9 +20,9 @@ #ifndef BEAST_NET_IPENDPOINT_H_INCLUDED #define BEAST_NET_IPENDPOINT_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include diff --git a/include/xrpl/beast/test/fail_counter.h b/include/xrpl/beast/test/fail_counter.h index 8a11602e22d..d0cae77ddad 100644 --- a/include/xrpl/beast/test/fail_counter.h +++ b/include/xrpl/beast/test/fail_counter.h @@ -8,8 +8,8 @@ #ifndef BEAST_TEST_FAIL_COUNTER_HPP #define BEAST_TEST_FAIL_COUNTER_HPP +#include #include -#include namespace beast { namespace test { diff --git a/include/xrpl/beast/test/fail_stream.h b/include/xrpl/beast/test/fail_stream.h index a1465f006ca..161e73ef091 100644 --- a/include/xrpl/beast/test/fail_stream.h +++ b/include/xrpl/beast/test/fail_stream.h @@ -8,13 +8,13 @@ #ifndef BEAST_TEST_FAIL_STREAM_HPP #define BEAST_TEST_FAIL_STREAM_HPP +#include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include -#include namespace beast { namespace test { diff --git a/include/xrpl/beast/test/pipe_stream.h b/include/xrpl/beast/test/pipe_stream.h index 1aaaadfa4ff..762419a539a 100644 --- a/include/xrpl/beast/test/pipe_stream.h +++ b/include/xrpl/beast/test/pipe_stream.h @@ -8,17 +8,17 @@ #ifndef BEAST_TEST_PIPE_STREAM_HPP #define BEAST_TEST_PIPE_STREAM_HPP +#include +#include +#include +#include +#include +#include +#include #include #include #include #include -#include -#include -#include -#include -#include -#include -#include #include #include #include diff --git a/include/xrpl/beast/test/string_iostream.h b/include/xrpl/beast/test/string_iostream.h index 56f741be068..bed6299a2bc 100644 --- a/include/xrpl/beast/test/string_iostream.h +++ b/include/xrpl/beast/test/string_iostream.h @@ -8,14 +8,14 @@ #ifndef BEAST_TEST_STRING_IOSTREAM_HPP #define BEAST_TEST_STRING_IOSTREAM_HPP +#include +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include -#include #include namespace beast { diff --git a/include/xrpl/beast/test/string_istream.h b/include/xrpl/beast/test/string_istream.h index 81f35469905..83cb3cfef5d 100644 --- a/include/xrpl/beast/test/string_istream.h +++ b/include/xrpl/beast/test/string_istream.h @@ -8,13 +8,13 @@ #ifndef BEAST_TEST_STRING_ISTREAM_HPP #define BEAST_TEST_STRING_ISTREAM_HPP +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include #include namespace beast { diff --git a/include/xrpl/beast/test/string_ostream.h b/include/xrpl/beast/test/string_ostream.h index 4cca9e7fce0..9edf69be88f 100644 --- a/include/xrpl/beast/test/string_ostream.h +++ b/include/xrpl/beast/test/string_ostream.h @@ -8,14 +8,14 @@ #ifndef BEAST_TEST_STRING_OSTREAM_HPP #define BEAST_TEST_STRING_OSTREAM_HPP +#include +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include -#include #include namespace beast { diff --git a/include/xrpl/beast/unit_test.h b/include/xrpl/beast/unit_test.h index 70747ea341b..eff82583ea7 100644 --- a/include/xrpl/beast/unit_test.h +++ b/include/xrpl/beast/unit_test.h @@ -20,16 +20,16 @@ #ifndef BEAST_UNIT_TEST_H_INCLUDED #define BEAST_UNIT_TEST_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #ifndef BEAST_EXPECT #define BEAST_EXPECT_S1(x) #x diff --git a/include/xrpl/beast/unit_test/global_suites.h b/include/xrpl/beast/unit_test/global_suites.h index 3fcdcc052bf..64bbbc7a268 100644 --- a/include/xrpl/beast/unit_test/global_suites.h +++ b/include/xrpl/beast/unit_test/global_suites.h @@ -8,7 +8,7 @@ #ifndef BEAST_UNIT_TEST_GLOBAL_SUITES_HPP #define BEAST_UNIT_TEST_GLOBAL_SUITES_HPP -#include +#include namespace beast { namespace unit_test { diff --git a/include/xrpl/beast/unit_test/match.h b/include/xrpl/beast/unit_test/match.h index 306bc569982..e8e12bd5568 100644 --- a/include/xrpl/beast/unit_test/match.h +++ b/include/xrpl/beast/unit_test/match.h @@ -8,7 +8,7 @@ #ifndef BEAST_UNIT_TEST_MATCH_HPP #define BEAST_UNIT_TEST_MATCH_HPP -#include +#include #include namespace beast { diff --git a/include/xrpl/beast/unit_test/recorder.h b/include/xrpl/beast/unit_test/recorder.h index 439e194c335..fbe6ab6c10d 100644 --- a/include/xrpl/beast/unit_test/recorder.h +++ b/include/xrpl/beast/unit_test/recorder.h @@ -8,8 +8,8 @@ #ifndef BEAST_UNIT_TEST_RECORDER_HPP #define BEAST_UNIT_TEST_RECORDER_HPP -#include -#include +#include +#include namespace beast { namespace unit_test { diff --git a/include/xrpl/beast/unit_test/reporter.h b/include/xrpl/beast/unit_test/reporter.h index 76b65a8b1e5..956def1c30d 100644 --- a/include/xrpl/beast/unit_test/reporter.h +++ b/include/xrpl/beast/unit_test/reporter.h @@ -8,8 +8,8 @@ #ifndef BEAST_UNIT_TEST_REPORTER_HPP #define BEAST_UNIT_TEST_REPORTER_HPP -#include -#include +#include +#include #include #include #include diff --git a/include/xrpl/beast/unit_test/results.h b/include/xrpl/beast/unit_test/results.h index dd43fb17a72..96fedc9b75f 100644 --- a/include/xrpl/beast/unit_test/results.h +++ b/include/xrpl/beast/unit_test/results.h @@ -8,7 +8,7 @@ #ifndef BEAST_UNIT_TEST_RESULTS_HPP #define BEAST_UNIT_TEST_RESULTS_HPP -#include +#include #include #include diff --git a/include/xrpl/beast/unit_test/runner.h b/include/xrpl/beast/unit_test/runner.h index bdee7aee5a8..6330f2c8c81 100644 --- a/include/xrpl/beast/unit_test/runner.h +++ b/include/xrpl/beast/unit_test/runner.h @@ -8,7 +8,7 @@ #ifndef BEAST_UNIT_TEST_RUNNER_H_INCLUDED #define BEAST_UNIT_TEST_RUNNER_H_INCLUDED -#include +#include #include #include #include diff --git a/include/xrpl/beast/unit_test/suite.h b/include/xrpl/beast/unit_test/suite.h index 23c4c4fad1f..d49730d4d5f 100644 --- a/include/xrpl/beast/unit_test/suite.h +++ b/include/xrpl/beast/unit_test/suite.h @@ -8,7 +8,7 @@ #ifndef BEAST_UNIT_TEST_SUITE_HPP #define BEAST_UNIT_TEST_SUITE_HPP -#include +#include #include #include #include @@ -646,7 +646,7 @@ suite::run(runner& r) #define BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Class, Module, Library, Priority) #else -#include +#include #define BEAST_DEFINE_TESTSUITE(Class, Module, Library) \ BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, false, 0) #define BEAST_DEFINE_TESTSUITE_MANUAL(Class, Module, Library) \ diff --git a/include/xrpl/beast/unit_test/suite_list.h b/include/xrpl/beast/unit_test/suite_list.h index a1aed563c71..5856b4c7dba 100644 --- a/include/xrpl/beast/unit_test/suite_list.h +++ b/include/xrpl/beast/unit_test/suite_list.h @@ -8,8 +8,8 @@ #ifndef BEAST_UNIT_TEST_SUITE_LIST_HPP #define BEAST_UNIT_TEST_SUITE_LIST_HPP -#include -#include +#include +#include #include #include #include diff --git a/include/xrpl/beast/unit_test/thread.h b/include/xrpl/beast/unit_test/thread.h index 8b2d024a840..e94108f7879 100644 --- a/include/xrpl/beast/unit_test/thread.h +++ b/include/xrpl/beast/unit_test/thread.h @@ -8,7 +8,7 @@ #ifndef BEAST_UNIT_TEST_THREAD_HPP #define BEAST_UNIT_TEST_THREAD_HPP -#include +#include #include #include #include diff --git a/include/xrpl/beast/utility/PropertyStream.h b/include/xrpl/beast/utility/PropertyStream.h index dbcc8a2d793..5eaf70453e8 100644 --- a/include/xrpl/beast/utility/PropertyStream.h +++ b/include/xrpl/beast/utility/PropertyStream.h @@ -20,7 +20,7 @@ #ifndef BEAST_UTILITY_PROPERTYSTREAM_H_INCLUDED #define BEAST_UTILITY_PROPERTYSTREAM_H_INCLUDED -#include +#include #include #include diff --git a/include/xrpl/beast/utility/WrappedSink.h b/include/xrpl/beast/utility/WrappedSink.h index ba714248a06..f22455a52c4 100644 --- a/include/xrpl/beast/utility/WrappedSink.h +++ b/include/xrpl/beast/utility/WrappedSink.h @@ -20,7 +20,7 @@ #ifndef BEAST_UTILITY_WRAPPEDSINK_H_INCLUDED #define BEAST_UTILITY_WRAPPEDSINK_H_INCLUDED -#include +#include namespace beast { diff --git a/include/xrpl/json/JsonPropertyStream.h b/include/xrpl/json/JsonPropertyStream.h index 0f25e59eb59..fdc21971978 100644 --- a/include/xrpl/json/JsonPropertyStream.h +++ b/include/xrpl/json/JsonPropertyStream.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_JSON_JSONPROPERTYSTREAM_H_INCLUDED #define RIPPLE_JSON_JSONPROPERTYSTREAM_H_INCLUDED -#include -#include +#include +#include namespace ripple { diff --git a/include/xrpl/json/Object.h b/include/xrpl/json/Object.h index 04501033335..ec60e562028 100644 --- a/include/xrpl/json/Object.h +++ b/include/xrpl/json/Object.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_JSON_OBJECT_H_INCLUDED #define RIPPLE_JSON_OBJECT_H_INCLUDED -#include +#include #include namespace Json { diff --git a/include/xrpl/json/Writer.h b/include/xrpl/json/Writer.h index 5801caf8514..882e944093e 100644 --- a/include/xrpl/json/Writer.h +++ b/include/xrpl/json/Writer.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_JSON_WRITER_H_INCLUDED #define RIPPLE_JSON_WRITER_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include namespace Json { diff --git a/include/xrpl/json/detail/json_assert.h b/include/xrpl/json/detail/json_assert.h index b7297e016c6..c401ccf7200 100644 --- a/include/xrpl/json/detail/json_assert.h +++ b/include/xrpl/json/detail/json_assert.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_JSON_JSON_ASSERT_H_INCLUDED #define RIPPLE_JSON_JSON_ASSERT_H_INCLUDED -#include +#include #define JSON_ASSERT_UNREACHABLE assert(false) #define JSON_ASSERT(condition) \ diff --git a/include/xrpl/json/json_reader.h b/include/xrpl/json/json_reader.h index caa657eb765..6fb07c318d8 100644 --- a/include/xrpl/json/json_reader.h +++ b/include/xrpl/json/json_reader.h @@ -22,8 +22,8 @@ #define CPPTL_JSON_READER_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/include/xrpl/json/json_value.h b/include/xrpl/json/json_value.h index c8312e51448..c2f9184d79a 100644 --- a/include/xrpl/json/json_value.h +++ b/include/xrpl/json/json_value.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_JSON_JSON_VALUE_H_INCLUDED #define RIPPLE_JSON_JSON_VALUE_H_INCLUDED -#include +#include #include #include #include diff --git a/include/xrpl/json/json_writer.h b/include/xrpl/json/json_writer.h index d1ddcd4decf..86a5ecd984a 100644 --- a/include/xrpl/json/json_writer.h +++ b/include/xrpl/json/json_writer.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_JSON_JSON_WRITER_H_INCLUDED #define RIPPLE_JSON_JSON_WRITER_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/include/xrpl/protocol/AMMCore.h b/include/xrpl/protocol/AMMCore.h index 816bf86214b..32988af5fc7 100644 --- a/include/xrpl/protocol/AMMCore.h +++ b/include/xrpl/protocol/AMMCore.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_PROTOCOL_AMMCORE_H_INCLUDED #define RIPPLE_PROTOCOL_AMMCORE_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/include/xrpl/protocol/AccountID.h b/include/xrpl/protocol/AccountID.h index 27e1f452293..ebe7f014d9c 100644 --- a/include/xrpl/protocol/AccountID.h +++ b/include/xrpl/protocol/AccountID.h @@ -20,13 +20,13 @@ #ifndef RIPPLE_PROTOCOL_ACCOUNTID_H_INCLUDED #define RIPPLE_PROTOCOL_ACCOUNTID_H_INCLUDED -#include +#include // VFALCO Uncomment when the header issues are resolved //#include -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/include/xrpl/protocol/AmountConversions.h b/include/xrpl/protocol/AmountConversions.h index dc0defe6972..0348e3c975d 100644 --- a/include/xrpl/protocol/AmountConversions.h +++ b/include/xrpl/protocol/AmountConversions.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_PROTOCOL_AMOUNTCONVERSION_H_INCLUDED #define RIPPLE_PROTOCOL_AMOUNTCONVERSION_H_INCLUDED -#include -#include -#include +#include +#include +#include #include diff --git a/include/xrpl/protocol/Book.h b/include/xrpl/protocol/Book.h index 609989062c0..164a5ccfa99 100644 --- a/include/xrpl/protocol/Book.h +++ b/include/xrpl/protocol/Book.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_PROTOCOL_BOOK_H_INCLUDED #define RIPPLE_PROTOCOL_BOOK_H_INCLUDED -#include -#include +#include +#include #include namespace ripple { diff --git a/include/xrpl/protocol/ErrorCodes.h b/include/xrpl/protocol/ErrorCodes.h index ad849f2b4ef..6d5590ec605 100644 --- a/include/xrpl/protocol/ErrorCodes.h +++ b/include/xrpl/protocol/ErrorCodes.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_PROTOCOL_ERRORCODES_H_INCLUDED #define RIPPLE_PROTOCOL_ERRORCODES_H_INCLUDED -#include -#include +#include +#include namespace ripple { diff --git a/include/xrpl/protocol/Feature.h b/include/xrpl/protocol/Feature.h index e0864540cc5..d2be4c934f6 100644 --- a/include/xrpl/protocol/Feature.h +++ b/include/xrpl/protocol/Feature.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PROTOCOL_FEATURE_H_INCLUDED #define RIPPLE_PROTOCOL_FEATURE_H_INCLUDED -#include +#include #include #include #include diff --git a/include/xrpl/protocol/Fees.h b/include/xrpl/protocol/Fees.h index d155b869d1d..7b4671a91d9 100644 --- a/include/xrpl/protocol/Fees.h +++ b/include/xrpl/protocol/Fees.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PROTOCOL_FEES_H_INCLUDED #define RIPPLE_PROTOCOL_FEES_H_INCLUDED -#include +#include namespace ripple { diff --git a/include/xrpl/protocol/HashPrefix.h b/include/xrpl/protocol/HashPrefix.h index 409f9de9b51..0979756b6e1 100644 --- a/include/xrpl/protocol/HashPrefix.h +++ b/include/xrpl/protocol/HashPrefix.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PROTOCOL_HASHPREFIX_H_INCLUDED #define RIPPLE_PROTOCOL_HASHPREFIX_H_INCLUDED -#include +#include #include namespace ripple { diff --git a/include/xrpl/protocol/Indexes.h b/include/xrpl/protocol/Indexes.h index d83599f892f..d57525121de 100644 --- a/include/xrpl/protocol/Indexes.h +++ b/include/xrpl/protocol/Indexes.h @@ -20,15 +20,15 @@ #ifndef RIPPLE_PROTOCOL_INDEXES_H_INCLUDED #define RIPPLE_PROTOCOL_INDEXES_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/include/xrpl/protocol/InnerObjectFormats.h b/include/xrpl/protocol/InnerObjectFormats.h index 33a155d03cb..06ca5af385c 100644 --- a/include/xrpl/protocol/InnerObjectFormats.h +++ b/include/xrpl/protocol/InnerObjectFormats.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PROTOCOL_INNER_OBJECT_FORMATS_H_INCLUDED #define RIPPLE_PROTOCOL_INNER_OBJECT_FORMATS_H_INCLUDED -#include +#include namespace ripple { diff --git a/include/xrpl/protocol/Issue.h b/include/xrpl/protocol/Issue.h index 1956b942e2b..a18502f2138 100644 --- a/include/xrpl/protocol/Issue.h +++ b/include/xrpl/protocol/Issue.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_PROTOCOL_ISSUE_H_INCLUDED #define RIPPLE_PROTOCOL_ISSUE_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/include/xrpl/protocol/Keylet.h b/include/xrpl/protocol/Keylet.h index 1c08ce855c6..d3bda103314 100644 --- a/include/xrpl/protocol/Keylet.h +++ b/include/xrpl/protocol/Keylet.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_PROTOCOL_KEYLET_H_INCLUDED #define RIPPLE_PROTOCOL_KEYLET_H_INCLUDED -#include -#include +#include +#include namespace ripple { diff --git a/include/xrpl/protocol/KnownFormats.h b/include/xrpl/protocol/KnownFormats.h index b59742259ad..5f5a04be1b3 100644 --- a/include/xrpl/protocol/KnownFormats.h +++ b/include/xrpl/protocol/KnownFormats.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_PROTOCOL_KNOWNFORMATS_H_INCLUDED #define RIPPLE_PROTOCOL_KNOWNFORMATS_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/protocol/LedgerFormats.h b/include/xrpl/protocol/LedgerFormats.h index e0ea7bf6f46..0ee6c992d8d 100644 --- a/include/xrpl/protocol/LedgerFormats.h +++ b/include/xrpl/protocol/LedgerFormats.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PROTOCOL_LEDGERFORMATS_H_INCLUDED #define RIPPLE_PROTOCOL_LEDGERFORMATS_H_INCLUDED -#include +#include namespace ripple { diff --git a/include/xrpl/protocol/LedgerHeader.h b/include/xrpl/protocol/LedgerHeader.h index 2adcfcfd209..663eb709be2 100644 --- a/include/xrpl/protocol/LedgerHeader.h +++ b/include/xrpl/protocol/LedgerHeader.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_PROTOCOL_LEDGERHEADER_H_INCLUDED #define RIPPLE_PROTOCOL_LEDGERHEADER_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/include/xrpl/protocol/MultiApiJson.h b/include/xrpl/protocol/MultiApiJson.h index b6d1843ae69..4514c54ea34 100644 --- a/include/xrpl/protocol/MultiApiJson.h +++ b/include/xrpl/protocol/MultiApiJson.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_JSON_MULTIAPIJSON_H_INCLUDED #define RIPPLE_JSON_MULTIAPIJSON_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/include/xrpl/protocol/NFTSyntheticSerializer.h b/include/xrpl/protocol/NFTSyntheticSerializer.h index f9a0cd50a46..e57b3ff71c9 100644 --- a/include/xrpl/protocol/NFTSyntheticSerializer.h +++ b/include/xrpl/protocol/NFTSyntheticSerializer.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_PROTOCOL_NFTSYNTHETICSERIALIZER_H_INCLUDED #define RIPPLE_PROTOCOL_NFTSYNTHETICSERIALIZER_H_INCLUDED -#include -#include -#include +#include +#include +#include #include diff --git a/include/xrpl/protocol/NFTokenID.h b/include/xrpl/protocol/NFTokenID.h index f29713aba7b..b9ea75d2036 100644 --- a/include/xrpl/protocol/NFTokenID.h +++ b/include/xrpl/protocol/NFTokenID.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_PROTOCOL_NFTOKENID_H_INCLUDED #define RIPPLE_PROTOCOL_NFTOKENID_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/include/xrpl/protocol/NFTokenOfferID.h b/include/xrpl/protocol/NFTokenOfferID.h index 777324f4243..9645b0b34da 100644 --- a/include/xrpl/protocol/NFTokenOfferID.h +++ b/include/xrpl/protocol/NFTokenOfferID.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_PROTOCOL_NFTOKENOFFERID_H_INCLUDED #define RIPPLE_PROTOCOL_NFTOKENOFFERID_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/include/xrpl/protocol/PayChan.h b/include/xrpl/protocol/PayChan.h index 216835de270..8344120ccd6 100644 --- a/include/xrpl/protocol/PayChan.h +++ b/include/xrpl/protocol/PayChan.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_PROTOCOL_PAYCHAN_H_INCLUDED #define RIPPLE_PROTOCOL_PAYCHAN_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/include/xrpl/protocol/Protocol.h b/include/xrpl/protocol/Protocol.h index bd723627494..8d8a71dfef8 100644 --- a/include/xrpl/protocol/Protocol.h +++ b/include/xrpl/protocol/Protocol.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_PROTOCOL_PROTOCOL_H_INCLUDED #define RIPPLE_PROTOCOL_PROTOCOL_H_INCLUDED -#include -#include +#include +#include #include namespace ripple { diff --git a/include/xrpl/protocol/PublicKey.h b/include/xrpl/protocol/PublicKey.h index 9cf1a456953..c68656877c9 100644 --- a/include/xrpl/protocol/PublicKey.h +++ b/include/xrpl/protocol/PublicKey.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_PROTOCOL_PUBLICKEY_H_INCLUDED #define RIPPLE_PROTOCOL_PUBLICKEY_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/include/xrpl/protocol/Quality.h b/include/xrpl/protocol/Quality.h index 06b8254df5e..1ee2cc9f686 100644 --- a/include/xrpl/protocol/Quality.h +++ b/include/xrpl/protocol/Quality.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_PROTOCOL_QUALITY_H_INCLUDED #define RIPPLE_PROTOCOL_QUALITY_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/include/xrpl/protocol/QualityFunction.h b/include/xrpl/protocol/QualityFunction.h index 5e08bdf8cd3..f7184881489 100644 --- a/include/xrpl/protocol/QualityFunction.h +++ b/include/xrpl/protocol/QualityFunction.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_PROTOCOL_QUALITYFUNCTION_H_INCLUDED #define RIPPLE_PROTOCOL_QUALITYFUNCTION_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/include/xrpl/protocol/RPCErr.h b/include/xrpl/protocol/RPCErr.h index e49e96b3df1..cb106b2f0da 100644 --- a/include/xrpl/protocol/RPCErr.h +++ b/include/xrpl/protocol/RPCErr.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_NET_RPCERR_H_INCLUDED #define RIPPLE_NET_RPCERR_H_INCLUDED -#include +#include namespace ripple { diff --git a/include/xrpl/protocol/Rate.h b/include/xrpl/protocol/Rate.h index 3524eabb627..b065acb2316 100644 --- a/include/xrpl/protocol/Rate.h +++ b/include/xrpl/protocol/Rate.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PROTOCOL_RATE_H_INCLUDED #define RIPPLE_PROTOCOL_RATE_H_INCLUDED -#include +#include #include #include #include diff --git a/include/xrpl/protocol/RippleLedgerHash.h b/include/xrpl/protocol/RippleLedgerHash.h index 2a7b5728342..19ba803b823 100644 --- a/include/xrpl/protocol/RippleLedgerHash.h +++ b/include/xrpl/protocol/RippleLedgerHash.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PROTOCOL_RIPPLELEDGERHASH_H_INCLUDED #define RIPPLE_PROTOCOL_RIPPLELEDGERHASH_H_INCLUDED -#include +#include namespace ripple { diff --git a/include/xrpl/protocol/Rules.h b/include/xrpl/protocol/Rules.h index f8ff8c00c0c..6b22d01afe0 100644 --- a/include/xrpl/protocol/Rules.h +++ b/include/xrpl/protocol/Rules.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_LEDGER_RULES_H_INCLUDED #define RIPPLE_LEDGER_RULES_H_INCLUDED -#include -#include -#include +#include +#include +#include #include diff --git a/include/xrpl/protocol/SField.h b/include/xrpl/protocol/SField.h index 727d531ff40..15aa2272d75 100644 --- a/include/xrpl/protocol/SField.h +++ b/include/xrpl/protocol/SField.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_PROTOCOL_SFIELD_H_INCLUDED #define RIPPLE_PROTOCOL_SFIELD_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/include/xrpl/protocol/SOTemplate.h b/include/xrpl/protocol/SOTemplate.h index 609c2d2c80b..c0fcfb64358 100644 --- a/include/xrpl/protocol/SOTemplate.h +++ b/include/xrpl/protocol/SOTemplate.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_PROTOCOL_SOTEMPLATE_H_INCLUDED #define RIPPLE_PROTOCOL_SOTEMPLATE_H_INCLUDED -#include -#include +#include +#include #include #include #include diff --git a/include/xrpl/protocol/STAccount.h b/include/xrpl/protocol/STAccount.h index c44327fe566..537a336e5db 100644 --- a/include/xrpl/protocol/STAccount.h +++ b/include/xrpl/protocol/STAccount.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_PROTOCOL_STACCOUNT_H_INCLUDED #define RIPPLE_PROTOCOL_STACCOUNT_H_INCLUDED -#include -#include -#include +#include +#include +#include #include diff --git a/include/xrpl/protocol/STAmount.h b/include/xrpl/protocol/STAmount.h index 1de1568ae03..3eed0860f54 100644 --- a/include/xrpl/protocol/STAmount.h +++ b/include/xrpl/protocol/STAmount.h @@ -20,16 +20,16 @@ #ifndef RIPPLE_PROTOCOL_STAMOUNT_H_INCLUDED #define RIPPLE_PROTOCOL_STAMOUNT_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/include/xrpl/protocol/STArray.h b/include/xrpl/protocol/STArray.h index 8c3833d3fc8..7fa2ecad834 100644 --- a/include/xrpl/protocol/STArray.h +++ b/include/xrpl/protocol/STArray.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_PROTOCOL_STARRAY_H_INCLUDED #define RIPPLE_PROTOCOL_STARRAY_H_INCLUDED -#include -#include +#include +#include namespace ripple { diff --git a/include/xrpl/protocol/STBase.h b/include/xrpl/protocol/STBase.h index ec8c34a9ddd..e13ef6c5b3e 100644 --- a/include/xrpl/protocol/STBase.h +++ b/include/xrpl/protocol/STBase.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_PROTOCOL_STBASE_H_INCLUDED #define RIPPLE_PROTOCOL_STBASE_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/protocol/STBitString.h b/include/xrpl/protocol/STBitString.h index decdfa64861..7dc92303e72 100644 --- a/include/xrpl/protocol/STBitString.h +++ b/include/xrpl/protocol/STBitString.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_PROTOCOL_STBITSTRING_H_INCLUDED #define RIPPLE_PROTOCOL_STBITSTRING_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/include/xrpl/protocol/STBlob.h b/include/xrpl/protocol/STBlob.h index 3b2731be7f0..bdedbd92105 100644 --- a/include/xrpl/protocol/STBlob.h +++ b/include/xrpl/protocol/STBlob.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_PROTOCOL_STBLOB_H_INCLUDED #define RIPPLE_PROTOCOL_STBLOB_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/include/xrpl/protocol/STCurrency.h b/include/xrpl/protocol/STCurrency.h index f855c24832e..3383137fb3a 100644 --- a/include/xrpl/protocol/STCurrency.h +++ b/include/xrpl/protocol/STCurrency.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_PROTOCOL_STCURRENCY_H_INCLUDED #define RIPPLE_PROTOCOL_STCURRENCY_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/include/xrpl/protocol/STExchange.h b/include/xrpl/protocol/STExchange.h index e22d75b08ee..e1a1215dbdd 100644 --- a/include/xrpl/protocol/STExchange.h +++ b/include/xrpl/protocol/STExchange.h @@ -20,14 +20,14 @@ #ifndef RIPPLE_PROTOCOL_STEXCHANGE_H_INCLUDED #define RIPPLE_PROTOCOL_STEXCHANGE_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/protocol/STInteger.h b/include/xrpl/protocol/STInteger.h index aaf0f8c904e..6bae2cc3152 100644 --- a/include/xrpl/protocol/STInteger.h +++ b/include/xrpl/protocol/STInteger.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_PROTOCOL_STINTEGER_H_INCLUDED #define RIPPLE_PROTOCOL_STINTEGER_H_INCLUDED -#include -#include +#include +#include namespace ripple { diff --git a/include/xrpl/protocol/STIssue.h b/include/xrpl/protocol/STIssue.h index 223798a8911..a0dfbd4faec 100644 --- a/include/xrpl/protocol/STIssue.h +++ b/include/xrpl/protocol/STIssue.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_PROTOCOL_STISSUE_H_INCLUDED #define RIPPLE_PROTOCOL_STISSUE_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/include/xrpl/protocol/STLedgerEntry.h b/include/xrpl/protocol/STLedgerEntry.h index 6fd50aa154e..6a57b32451a 100644 --- a/include/xrpl/protocol/STLedgerEntry.h +++ b/include/xrpl/protocol/STLedgerEntry.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_PROTOCOL_STLEDGERENTRY_H_INCLUDED #define RIPPLE_PROTOCOL_STLEDGERENTRY_H_INCLUDED -#include -#include +#include +#include namespace ripple { diff --git a/include/xrpl/protocol/STObject.h b/include/xrpl/protocol/STObject.h index 38678f67a55..5259994a976 100644 --- a/include/xrpl/protocol/STObject.h +++ b/include/xrpl/protocol/STObject.h @@ -20,20 +20,20 @@ #ifndef RIPPLE_PROTOCOL_STOBJECT_H_INCLUDED #define RIPPLE_PROTOCOL_STOBJECT_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/protocol/STParsedJSON.h b/include/xrpl/protocol/STParsedJSON.h index 11cba574027..d2052bf1f4c 100644 --- a/include/xrpl/protocol/STParsedJSON.h +++ b/include/xrpl/protocol/STParsedJSON.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PROTOCOL_STPARSEDJSON_H_INCLUDED #define RIPPLE_PROTOCOL_STPARSEDJSON_H_INCLUDED -#include +#include #include namespace ripple { diff --git a/include/xrpl/protocol/STPathSet.h b/include/xrpl/protocol/STPathSet.h index 8102bc76eb0..473086368fb 100644 --- a/include/xrpl/protocol/STPathSet.h +++ b/include/xrpl/protocol/STPathSet.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_PROTOCOL_STPATHSET_H_INCLUDED #define RIPPLE_PROTOCOL_STPATHSET_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/protocol/STTx.h b/include/xrpl/protocol/STTx.h index e166eb20dd4..08b9a1bad10 100644 --- a/include/xrpl/protocol/STTx.h +++ b/include/xrpl/protocol/STTx.h @@ -20,14 +20,14 @@ #ifndef RIPPLE_PROTOCOL_STTX_H_INCLUDED #define RIPPLE_PROTOCOL_STTX_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/include/xrpl/protocol/STValidation.h b/include/xrpl/protocol/STValidation.h index edd922e7bfa..6cae0971f51 100644 --- a/include/xrpl/protocol/STValidation.h +++ b/include/xrpl/protocol/STValidation.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_PROTOCOL_STVALIDATION_H_INCLUDED #define RIPPLE_PROTOCOL_STVALIDATION_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/protocol/STVector256.h b/include/xrpl/protocol/STVector256.h index bf4a1cbec44..e70297a40bf 100644 --- a/include/xrpl/protocol/STVector256.h +++ b/include/xrpl/protocol/STVector256.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_PROTOCOL_STVECTOR256_H_INCLUDED #define RIPPLE_PROTOCOL_STVECTOR256_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/include/xrpl/protocol/STXChainBridge.h b/include/xrpl/protocol/STXChainBridge.h index 537a1d160b2..38db1912c70 100644 --- a/include/xrpl/protocol/STXChainBridge.h +++ b/include/xrpl/protocol/STXChainBridge.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_PROTOCOL_STXCHAINBRIDGE_H_INCLUDED #define RIPPLE_PROTOCOL_STXCHAINBRIDGE_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/include/xrpl/protocol/SecretKey.h b/include/xrpl/protocol/SecretKey.h index 824ae9b1e0f..67dc9c4ca59 100644 --- a/include/xrpl/protocol/SecretKey.h +++ b/include/xrpl/protocol/SecretKey.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_PROTOCOL_SECRETKEY_H_INCLUDED #define RIPPLE_PROTOCOL_SECRETKEY_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/protocol/Seed.h b/include/xrpl/protocol/Seed.h index 2ebc64970f0..1d0a736db8a 100644 --- a/include/xrpl/protocol/Seed.h +++ b/include/xrpl/protocol/Seed.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_PROTOCOL_SEED_H_INCLUDED #define RIPPLE_PROTOCOL_SEED_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include diff --git a/include/xrpl/protocol/Serializer.h b/include/xrpl/protocol/Serializer.h index e3ef00eaf65..b85e8eb013d 100644 --- a/include/xrpl/protocol/Serializer.h +++ b/include/xrpl/protocol/Serializer.h @@ -20,15 +20,15 @@ #ifndef RIPPLE_PROTOCOL_SERIALIZER_H_INCLUDED #define RIPPLE_PROTOCOL_SERIALIZER_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/protocol/Sign.h b/include/xrpl/protocol/Sign.h index 6af29530486..30fbb26244b 100644 --- a/include/xrpl/protocol/Sign.h +++ b/include/xrpl/protocol/Sign.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_PROTOCOL_SIGN_H_INCLUDED #define RIPPLE_PROTOCOL_SIGN_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include namespace ripple { diff --git a/include/xrpl/protocol/SystemParameters.h b/include/xrpl/protocol/SystemParameters.h index bc2f7136ff9..c99944193ae 100644 --- a/include/xrpl/protocol/SystemParameters.h +++ b/include/xrpl/protocol/SystemParameters.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_PROTOCOL_SYSTEMPARAMETERS_H_INCLUDED #define RIPPLE_PROTOCOL_SYSTEMPARAMETERS_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/include/xrpl/protocol/TER.h b/include/xrpl/protocol/TER.h index 41c23a2d6a8..335ef8de39a 100644 --- a/include/xrpl/protocol/TER.h +++ b/include/xrpl/protocol/TER.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_PROTOCOL_TER_H_INCLUDED #define RIPPLE_PROTOCOL_TER_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/include/xrpl/protocol/TxFormats.h b/include/xrpl/protocol/TxFormats.h index b5afa470f38..bd5dffd94e9 100644 --- a/include/xrpl/protocol/TxFormats.h +++ b/include/xrpl/protocol/TxFormats.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PROTOCOL_TXFORMATS_H_INCLUDED #define RIPPLE_PROTOCOL_TXFORMATS_H_INCLUDED -#include +#include namespace ripple { diff --git a/include/xrpl/protocol/TxMeta.h b/include/xrpl/protocol/TxMeta.h index 0a6578b1930..7932a4c55a3 100644 --- a/include/xrpl/protocol/TxMeta.h +++ b/include/xrpl/protocol/TxMeta.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_APP_TX_TRANSACTIONMETA_H_INCLUDED #define RIPPLE_APP_TX_TRANSACTIONMETA_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/include/xrpl/protocol/UintTypes.h b/include/xrpl/protocol/UintTypes.h index 6fb685551f8..a0a8069f669 100644 --- a/include/xrpl/protocol/UintTypes.h +++ b/include/xrpl/protocol/UintTypes.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_PROTOCOL_UINTTYPES_H_INCLUDED #define RIPPLE_PROTOCOL_UINTTYPES_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { namespace detail { diff --git a/include/xrpl/protocol/XChainAttestations.h b/include/xrpl/protocol/XChainAttestations.h index b99a0b59a4b..721950ca9c1 100644 --- a/include/xrpl/protocol/XChainAttestations.h +++ b/include/xrpl/protocol/XChainAttestations.h @@ -20,16 +20,16 @@ #ifndef RIPPLE_PROTOCOL_STXATTESTATIONS_H_INCLUDED #define RIPPLE_PROTOCOL_STXATTESTATIONS_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/include/xrpl/protocol/detail/STVar.h b/include/xrpl/protocol/detail/STVar.h index 73863edbbe0..bee48aa53f6 100644 --- a/include/xrpl/protocol/detail/STVar.h +++ b/include/xrpl/protocol/detail/STVar.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_PROTOCOL_STVAR_H_INCLUDED #define RIPPLE_PROTOCOL_STVAR_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/protocol/detail/b58_utils.h b/include/xrpl/protocol/detail/b58_utils.h index c3bb0c03750..f21b416042b 100644 --- a/include/xrpl/protocol/detail/b58_utils.h +++ b/include/xrpl/protocol/detail/b58_utils.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PROTOCOL_B58_UTILS_H_INCLUDED #define RIPPLE_PROTOCOL_B58_UTILS_H_INCLUDED -#include +#include #include #include diff --git a/include/xrpl/protocol/digest.h b/include/xrpl/protocol/digest.h index 6507057dcdc..f3fc2ea5c5d 100644 --- a/include/xrpl/protocol/digest.h +++ b/include/xrpl/protocol/digest.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_PROTOCOL_DIGEST_H_INCLUDED #define RIPPLE_PROTOCOL_DIGEST_H_INCLUDED -#include -#include +#include +#include #include #include #include diff --git a/include/xrpl/protocol/json_get_or_throw.h b/include/xrpl/protocol/json_get_or_throw.h index 86bd5924d3e..5277ee86484 100644 --- a/include/xrpl/protocol/json_get_or_throw.h +++ b/include/xrpl/protocol/json_get_or_throw.h @@ -1,11 +1,11 @@ #ifndef PROTOCOL_GET_OR_THROW_H_ #define PROTOCOL_GET_OR_THROW_H_ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/include/xrpl/protocol/jss.h b/include/xrpl/protocol/jss.h index b5f3d1fcb5d..a46e15f39ef 100644 --- a/include/xrpl/protocol/jss.h +++ b/include/xrpl/protocol/jss.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PROTOCOL_JSONFIELDS_H_INCLUDED #define RIPPLE_PROTOCOL_JSONFIELDS_H_INCLUDED -#include +#include namespace ripple { namespace jss { diff --git a/include/xrpl/protocol/messages.h b/include/xrpl/protocol/messages.h index e9c9cf60b21..640305185ad 100644 --- a/include/xrpl/protocol/messages.h +++ b/include/xrpl/protocol/messages.h @@ -31,6 +31,6 @@ #undef TYPE_BOOL #endif -#include +#include #endif diff --git a/include/xrpl/protocol/nft.h b/include/xrpl/protocol/nft.h index 2df8e0b89ce..839d872a63a 100644 --- a/include/xrpl/protocol/nft.h +++ b/include/xrpl/protocol/nft.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_PROTOCOL_NFT_H_INCLUDED #define RIPPLE_PROTOCOL_NFT_H_INCLUDED -#include -#include -#include +#include +#include +#include #include diff --git a/include/xrpl/protocol/nftPageMask.h b/include/xrpl/protocol/nftPageMask.h index a4890b460cd..1f8c39aa138 100644 --- a/include/xrpl/protocol/nftPageMask.h +++ b/include/xrpl/protocol/nftPageMask.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PROTOCOL_NFT_PAGE_MASK_H_INCLUDED #define RIPPLE_PROTOCOL_NFT_PAGE_MASK_H_INCLUDED -#include +#include #include namespace ripple { diff --git a/include/xrpl/protocol/serialize.h b/include/xrpl/protocol/serialize.h index 93c59acfd0a..6d171c5e86b 100644 --- a/include/xrpl/protocol/serialize.h +++ b/include/xrpl/protocol/serialize.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_PROTOCOL_SERIALIZE_H_INCLUDED #define RIPPLE_PROTOCOL_SERIALIZE_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/include/xrpl/protocol/st.h b/include/xrpl/protocol/st.h index 7d43ef75f15..7b0e3a3b2df 100644 --- a/include/xrpl/protocol/st.h +++ b/include/xrpl/protocol/st.h @@ -20,20 +20,20 @@ #ifndef RIPPLE_PROTOCOL_ST_H_INCLUDED #define RIPPLE_PROTOCOL_ST_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #endif diff --git a/include/xrpl/protocol/tokens.h b/include/xrpl/protocol/tokens.h index f51c3f96f95..f0c4e79d43a 100644 --- a/include/xrpl/protocol/tokens.h +++ b/include/xrpl/protocol/tokens.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_PROTOCOL_TOKENS_H_INCLUDED #define RIPPLE_PROTOCOL_TOKENS_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include diff --git a/include/xrpl/resource/Consumer.h b/include/xrpl/resource/Consumer.h index 34fb02ee68f..00e4ad2c5f5 100644 --- a/include/xrpl/resource/Consumer.h +++ b/include/xrpl/resource/Consumer.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_RESOURCE_CONSUMER_H_INCLUDED #define RIPPLE_RESOURCE_CONSUMER_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { namespace Resource { diff --git a/include/xrpl/resource/Fees.h b/include/xrpl/resource/Fees.h index d3fd5f72c49..d3750ec8282 100644 --- a/include/xrpl/resource/Fees.h +++ b/include/xrpl/resource/Fees.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_RESOURCE_FEES_H_INCLUDED #define RIPPLE_RESOURCE_FEES_H_INCLUDED -#include +#include namespace ripple { namespace Resource { diff --git a/include/xrpl/resource/Gossip.h b/include/xrpl/resource/Gossip.h index 742fad640af..6e2a86ecd7c 100644 --- a/include/xrpl/resource/Gossip.h +++ b/include/xrpl/resource/Gossip.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_RESOURCE_GOSSIP_H_INCLUDED #define RIPPLE_RESOURCE_GOSSIP_H_INCLUDED -#include +#include namespace ripple { namespace Resource { diff --git a/include/xrpl/resource/ResourceManager.h b/include/xrpl/resource/ResourceManager.h index 10e20a82f06..b33b141ee05 100644 --- a/include/xrpl/resource/ResourceManager.h +++ b/include/xrpl/resource/ResourceManager.h @@ -20,13 +20,13 @@ #ifndef RIPPLE_RESOURCE_MANAGER_H_INCLUDED #define RIPPLE_RESOURCE_MANAGER_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/include/xrpl/resource/detail/Entry.h b/include/xrpl/resource/detail/Entry.h index 126f2546456..d4f32080d9d 100644 --- a/include/xrpl/resource/detail/Entry.h +++ b/include/xrpl/resource/detail/Entry.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_RESOURCE_ENTRY_H_INCLUDED #define RIPPLE_RESOURCE_ENTRY_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/include/xrpl/resource/detail/Import.h b/include/xrpl/resource/detail/Import.h index 4eae3fafea0..52315644969 100644 --- a/include/xrpl/resource/detail/Import.h +++ b/include/xrpl/resource/detail/Import.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_RESOURCE_IMPORT_H_INCLUDED #define RIPPLE_RESOURCE_IMPORT_H_INCLUDED -#include -#include +#include +#include namespace ripple { namespace Resource { diff --git a/include/xrpl/resource/detail/Key.h b/include/xrpl/resource/detail/Key.h index 929c13eebf6..3df2dce039d 100644 --- a/include/xrpl/resource/detail/Key.h +++ b/include/xrpl/resource/detail/Key.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_RESOURCE_KEY_H_INCLUDED #define RIPPLE_RESOURCE_KEY_H_INCLUDED -#include -#include +#include +#include #include namespace ripple { diff --git a/include/xrpl/resource/detail/Logic.h b/include/xrpl/resource/detail/Logic.h index 07d89403b6a..a57e529e0a2 100644 --- a/include/xrpl/resource/detail/Logic.h +++ b/include/xrpl/resource/detail/Logic.h @@ -20,17 +20,17 @@ #ifndef RIPPLE_RESOURCE_LOGIC_H_INCLUDED #define RIPPLE_RESOURCE_LOGIC_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/include/xrpl/server/Handoff.h b/include/xrpl/server/Handoff.h index 2b80d6179d6..f57c9ef57ec 100644 --- a/include/xrpl/server/Handoff.h +++ b/include/xrpl/server/Handoff.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_SERVER_HANDOFF_H_INCLUDED #define RIPPLE_SERVER_HANDOFF_H_INCLUDED -#include +#include #include #include #include diff --git a/include/xrpl/server/Port.h b/include/xrpl/server/Port.h index 9dccfdf9c08..4ab56efb459 100644 --- a/include/xrpl/server/Port.h +++ b/include/xrpl/server/Port.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_SERVER_PORT_H_INCLUDED #define RIPPLE_SERVER_PORT_H_INCLUDED -#include -#include +#include +#include #include #include #include diff --git a/include/xrpl/server/Server.h b/include/xrpl/server/Server.h index a149e34fbfb..e8157c03c6c 100644 --- a/include/xrpl/server/Server.h +++ b/include/xrpl/server/Server.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_SERVER_SERVER_H_INCLUDED #define RIPPLE_SERVER_SERVER_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include namespace ripple { diff --git a/include/xrpl/server/Session.h b/include/xrpl/server/Session.h index 3b22c06b00b..25cf1ad747d 100644 --- a/include/xrpl/server/Session.h +++ b/include/xrpl/server/Session.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_SERVER_SESSION_H_INCLUDED #define RIPPLE_SERVER_SESSION_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/server/SimpleWriter.h b/include/xrpl/server/SimpleWriter.h index 03582c00114..0e3f63b0d9d 100644 --- a/include/xrpl/server/SimpleWriter.h +++ b/include/xrpl/server/SimpleWriter.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_SERVER_SIMPLEWRITER_H_INCLUDED #define RIPPLE_SERVER_SIMPLEWRITER_H_INCLUDED -#include +#include #include #include #include diff --git a/include/xrpl/server/WSSession.h b/include/xrpl/server/WSSession.h index 812099108a5..d739afcefb7 100644 --- a/include/xrpl/server/WSSession.h +++ b/include/xrpl/server/WSSession.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_SERVER_WSSESSION_H_INCLUDED #define RIPPLE_SERVER_WSSESSION_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include diff --git a/include/xrpl/server/detail/BaseHTTPPeer.h b/include/xrpl/server/detail/BaseHTTPPeer.h index a6bbd18e1aa..171eb7134e1 100644 --- a/include/xrpl/server/detail/BaseHTTPPeer.h +++ b/include/xrpl/server/detail/BaseHTTPPeer.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_SERVER_BASEHTTPPEER_H_INCLUDED #define RIPPLE_SERVER_BASEHTTPPEER_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/server/detail/BasePeer.h b/include/xrpl/server/detail/BasePeer.h index bc5375b87f7..a90eaabf6e4 100644 --- a/include/xrpl/server/detail/BasePeer.h +++ b/include/xrpl/server/detail/BasePeer.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_SERVER_BASEPEER_H_INCLUDED #define RIPPLE_SERVER_BASEPEER_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/server/detail/BaseWSPeer.h b/include/xrpl/server/detail/BaseWSPeer.h index fd1722df003..4c4049a8b9b 100644 --- a/include/xrpl/server/detail/BaseWSPeer.h +++ b/include/xrpl/server/detail/BaseWSPeer.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_SERVER_BASEWSPEER_H_INCLUDED #define RIPPLE_SERVER_BASEWSPEER_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/server/detail/Door.h b/include/xrpl/server/detail/Door.h index 94f39719569..20bdf421e38 100644 --- a/include/xrpl/server/detail/Door.h +++ b/include/xrpl/server/detail/Door.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_SERVER_DOOR_H_INCLUDED #define RIPPLE_SERVER_DOOR_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/include/xrpl/server/detail/JSONRPCUtil.h b/include/xrpl/server/detail/JSONRPCUtil.h index d6b67e123c4..7eb00096263 100644 --- a/include/xrpl/server/detail/JSONRPCUtil.h +++ b/include/xrpl/server/detail/JSONRPCUtil.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_SERVER_JSONRPCUTIL_H_INCLUDED #define RIPPLE_SERVER_JSONRPCUTIL_H_INCLUDED -#include -#include +#include +#include namespace ripple { diff --git a/include/xrpl/server/detail/PlainHTTPPeer.h b/include/xrpl/server/detail/PlainHTTPPeer.h index 4c593ce9cb6..d4b24c01313 100644 --- a/include/xrpl/server/detail/PlainHTTPPeer.h +++ b/include/xrpl/server/detail/PlainHTTPPeer.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_SERVER_PLAINHTTPPEER_H_INCLUDED #define RIPPLE_SERVER_PLAINHTTPPEER_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include diff --git a/include/xrpl/server/detail/PlainWSPeer.h b/include/xrpl/server/detail/PlainWSPeer.h index 504b38baac7..8bcddee7e77 100644 --- a/include/xrpl/server/detail/PlainWSPeer.h +++ b/include/xrpl/server/detail/PlainWSPeer.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_SERVER_PLAINWSPEER_H_INCLUDED #define RIPPLE_SERVER_PLAINWSPEER_H_INCLUDED -#include +#include #include #include diff --git a/include/xrpl/server/detail/SSLHTTPPeer.h b/include/xrpl/server/detail/SSLHTTPPeer.h index 8b5b4e38c4e..db6af46b5b3 100644 --- a/include/xrpl/server/detail/SSLHTTPPeer.h +++ b/include/xrpl/server/detail/SSLHTTPPeer.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_SERVER_SSLHTTPPEER_H_INCLUDED #define RIPPLE_SERVER_SSLHTTPPEER_H_INCLUDED -#include -#include +#include +#include #include #include #include diff --git a/include/xrpl/server/detail/SSLWSPeer.h b/include/xrpl/server/detail/SSLWSPeer.h index 28c3184fce6..9c88b275397 100644 --- a/include/xrpl/server/detail/SSLWSPeer.h +++ b/include/xrpl/server/detail/SSLWSPeer.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_SERVER_SSLWSPEER_H_INCLUDED #define RIPPLE_SERVER_SSLWSPEER_H_INCLUDED -#include -#include +#include +#include #include #include #include diff --git a/include/xrpl/server/detail/ServerImpl.h b/include/xrpl/server/detail/ServerImpl.h index a3abf78914e..00a9a263846 100644 --- a/include/xrpl/server/detail/ServerImpl.h +++ b/include/xrpl/server/detail/ServerImpl.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_SERVER_SERVERIMPL_H_INCLUDED #define RIPPLE_SERVER_SERVERIMPL_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/libxrpl/basics/Archive.cpp b/src/libxrpl/basics/Archive.cpp index 73e14a93606..e5672bd953f 100644 --- a/src/libxrpl/basics/Archive.cpp +++ b/src/libxrpl/basics/Archive.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include diff --git a/src/libxrpl/basics/BasicConfig.cpp b/src/libxrpl/basics/BasicConfig.cpp index f557d2e6d46..932eea346f6 100644 --- a/src/libxrpl/basics/BasicConfig.cpp +++ b/src/libxrpl/basics/BasicConfig.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include diff --git a/src/libxrpl/basics/CountedObject.cpp b/src/libxrpl/basics/CountedObject.cpp index 5b25091632d..c18152938a9 100644 --- a/src/libxrpl/basics/CountedObject.cpp +++ b/src/libxrpl/basics/CountedObject.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include #include diff --git a/src/libxrpl/basics/FileUtilities.cpp b/src/libxrpl/basics/FileUtilities.cpp index be60a3e5c3d..e1331433553 100644 --- a/src/libxrpl/basics/FileUtilities.cpp +++ b/src/libxrpl/basics/FileUtilities.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/libxrpl/basics/IOUAmount.cpp b/src/libxrpl/basics/IOUAmount.cpp index e3c3411057b..a24e1b917f7 100644 --- a/src/libxrpl/basics/IOUAmount.cpp +++ b/src/libxrpl/basics/IOUAmount.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include #include diff --git a/src/libxrpl/basics/Log.cpp b/src/libxrpl/basics/Log.cpp index c023bc16485..3d5963cc266 100644 --- a/src/libxrpl/basics/Log.cpp +++ b/src/libxrpl/basics/Log.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/src/libxrpl/basics/Number.cpp b/src/libxrpl/basics/Number.cpp index 9b3247536f9..14260b653a2 100644 --- a/src/libxrpl/basics/Number.cpp +++ b/src/libxrpl/basics/Number.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include #include #include diff --git a/src/libxrpl/basics/ResolverAsio.cpp b/src/libxrpl/basics/ResolverAsio.cpp index f75a390304b..53530da9d8f 100644 --- a/src/libxrpl/basics/ResolverAsio.cpp +++ b/src/libxrpl/basics/ResolverAsio.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/src/libxrpl/basics/StringUtilities.cpp b/src/libxrpl/basics/StringUtilities.cpp index 67344b48013..cd9bdfbd030 100644 --- a/src/libxrpl/basics/StringUtilities.cpp +++ b/src/libxrpl/basics/StringUtilities.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/libxrpl/basics/UptimeClock.cpp b/src/libxrpl/basics/UptimeClock.cpp index 2dacaef46bf..4394d02f783 100644 --- a/src/libxrpl/basics/UptimeClock.cpp +++ b/src/libxrpl/basics/UptimeClock.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/libxrpl/basics/base64.cpp b/src/libxrpl/basics/base64.cpp index 4291a99556b..a8b4e352992 100644 --- a/src/libxrpl/basics/base64.cpp +++ b/src/libxrpl/basics/base64.cpp @@ -54,7 +54,7 @@ */ -#include +#include #include #include diff --git a/src/libxrpl/basics/contract.cpp b/src/libxrpl/basics/contract.cpp index 3a50db38010..fbda83c7a63 100644 --- a/src/libxrpl/basics/contract.cpp +++ b/src/libxrpl/basics/contract.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include diff --git a/src/libxrpl/basics/make_SSLContext.cpp b/src/libxrpl/basics/make_SSLContext.cpp index 7d72d9e08b4..4a9ea321d54 100644 --- a/src/libxrpl/basics/make_SSLContext.cpp +++ b/src/libxrpl/basics/make_SSLContext.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include diff --git a/src/libxrpl/basics/mulDiv.cpp b/src/libxrpl/basics/mulDiv.cpp index 6dd01c71fe7..7f9ffa45267 100644 --- a/src/libxrpl/basics/mulDiv.cpp +++ b/src/libxrpl/basics/mulDiv.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include #include diff --git a/src/libxrpl/basics/partitioned_unordered_map.cpp b/src/libxrpl/basics/partitioned_unordered_map.cpp index 3ced32eddff..a6d02cd2c6f 100644 --- a/src/libxrpl/basics/partitioned_unordered_map.cpp +++ b/src/libxrpl/basics/partitioned_unordered_map.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include +#include -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/libxrpl/beast/clock/basic_seconds_clock.cpp b/src/libxrpl/beast/clock/basic_seconds_clock.cpp index 7c55a3f8bc0..f5af8bd16ec 100644 --- a/src/libxrpl/beast/clock/basic_seconds_clock.cpp +++ b/src/libxrpl/beast/clock/basic_seconds_clock.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include #include diff --git a/src/libxrpl/beast/core/CurrentThreadName.cpp b/src/libxrpl/beast/core/CurrentThreadName.cpp index 80d275a1fff..71b5d21fec3 100644 --- a/src/libxrpl/beast/core/CurrentThreadName.cpp +++ b/src/libxrpl/beast/core/CurrentThreadName.cpp @@ -21,7 +21,7 @@ */ //============================================================================== -#include +#include #include //------------------------------------------------------------------------------ diff --git a/src/libxrpl/beast/core/SemanticVersion.cpp b/src/libxrpl/beast/core/SemanticVersion.cpp index 9d127a09513..b33ed2f48f4 100644 --- a/src/libxrpl/beast/core/SemanticVersion.cpp +++ b/src/libxrpl/beast/core/SemanticVersion.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include diff --git a/src/libxrpl/beast/insight/Collector.cpp b/src/libxrpl/beast/insight/Collector.cpp index e0f0e6ec644..4fdf6de984d 100644 --- a/src/libxrpl/beast/insight/Collector.cpp +++ b/src/libxrpl/beast/insight/Collector.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace beast { namespace insight { diff --git a/src/libxrpl/beast/insight/Groups.cpp b/src/libxrpl/beast/insight/Groups.cpp index 7877034b97a..fcf7e65787e 100644 --- a/src/libxrpl/beast/insight/Groups.cpp +++ b/src/libxrpl/beast/insight/Groups.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/libxrpl/beast/insight/Hook.cpp b/src/libxrpl/beast/insight/Hook.cpp index 53ae6475aad..62538846349 100644 --- a/src/libxrpl/beast/insight/Hook.cpp +++ b/src/libxrpl/beast/insight/Hook.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace beast { namespace insight { diff --git a/src/libxrpl/beast/insight/Metric.cpp b/src/libxrpl/beast/insight/Metric.cpp index aa38e2f8166..64a4082fcec 100644 --- a/src/libxrpl/beast/insight/Metric.cpp +++ b/src/libxrpl/beast/insight/Metric.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace beast { namespace insight { diff --git a/src/libxrpl/beast/insight/NullCollector.cpp b/src/libxrpl/beast/insight/NullCollector.cpp index b859de552a2..637cd06ec3b 100644 --- a/src/libxrpl/beast/insight/NullCollector.cpp +++ b/src/libxrpl/beast/insight/NullCollector.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace beast { namespace insight { diff --git a/src/libxrpl/beast/insight/StatsDCollector.cpp b/src/libxrpl/beast/insight/StatsDCollector.cpp index 6949a7f86e7..76ae15b82d5 100644 --- a/src/libxrpl/beast/insight/StatsDCollector.cpp +++ b/src/libxrpl/beast/insight/StatsDCollector.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/libxrpl/beast/net/IPAddressConversion.cpp b/src/libxrpl/beast/net/IPAddressConversion.cpp index 6353c50dfba..2ab84c37015 100644 --- a/src/libxrpl/beast/net/IPAddressConversion.cpp +++ b/src/libxrpl/beast/net/IPAddressConversion.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace beast { namespace IP { diff --git a/src/libxrpl/beast/net/IPAddressV4.cpp b/src/libxrpl/beast/net/IPAddressV4.cpp index 7e428c4228e..83541479878 100644 --- a/src/libxrpl/beast/net/IPAddressV4.cpp +++ b/src/libxrpl/beast/net/IPAddressV4.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include #include diff --git a/src/libxrpl/beast/net/IPAddressV6.cpp b/src/libxrpl/beast/net/IPAddressV6.cpp index 07dd2baaee5..f90a6d066b0 100644 --- a/src/libxrpl/beast/net/IPAddressV6.cpp +++ b/src/libxrpl/beast/net/IPAddressV6.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace beast { namespace IP { diff --git a/src/libxrpl/beast/net/IPEndpoint.cpp b/src/libxrpl/beast/net/IPEndpoint.cpp index 4ad71262c27..490777111bd 100644 --- a/src/libxrpl/beast/net/IPEndpoint.cpp +++ b/src/libxrpl/beast/net/IPEndpoint.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include namespace beast { diff --git a/src/libxrpl/beast/utility/src/beast_Journal.cpp b/src/libxrpl/beast/utility/src/beast_Journal.cpp index 7c332bf6b52..261e1f6ccab 100644 --- a/src/libxrpl/beast/utility/src/beast_Journal.cpp +++ b/src/libxrpl/beast/utility/src/beast_Journal.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include namespace beast { diff --git a/src/libxrpl/beast/utility/src/beast_PropertyStream.cpp b/src/libxrpl/beast/utility/src/beast_PropertyStream.cpp index ecd707e9554..56e862ca8c0 100644 --- a/src/libxrpl/beast/utility/src/beast_PropertyStream.cpp +++ b/src/libxrpl/beast/utility/src/beast_PropertyStream.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include #include #include diff --git a/src/libxrpl/crypto/RFC1751.cpp b/src/libxrpl/crypto/RFC1751.cpp index 6b6b2c31fb1..1c6f28287b0 100644 --- a/src/libxrpl/crypto/RFC1751.cpp +++ b/src/libxrpl/crypto/RFC1751.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include #include #include diff --git a/src/libxrpl/crypto/csprng.cpp b/src/libxrpl/crypto/csprng.cpp index 04b3b3fc385..480d561eacf 100644 --- a/src/libxrpl/crypto/csprng.cpp +++ b/src/libxrpl/crypto/csprng.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include #include diff --git a/src/libxrpl/crypto/secure_erase.cpp b/src/libxrpl/crypto/secure_erase.cpp index 8299ed7a6c9..93f189d519c 100644 --- a/src/libxrpl/crypto/secure_erase.cpp +++ b/src/libxrpl/crypto/secure_erase.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include namespace ripple { diff --git a/src/libxrpl/json/JsonPropertyStream.cpp b/src/libxrpl/json/JsonPropertyStream.cpp index 3083deeeee2..19387013b58 100644 --- a/src/libxrpl/json/JsonPropertyStream.cpp +++ b/src/libxrpl/json/JsonPropertyStream.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { diff --git a/src/libxrpl/json/Object.cpp b/src/libxrpl/json/Object.cpp index a855fc31a2c..179b0e31ef2 100644 --- a/src/libxrpl/json/Object.cpp +++ b/src/libxrpl/json/Object.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include namespace Json { diff --git a/src/libxrpl/json/Output.cpp b/src/libxrpl/json/Output.cpp index b32e9ad5a67..c24c75b32dd 100644 --- a/src/libxrpl/json/Output.cpp +++ b/src/libxrpl/json/Output.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace Json { diff --git a/src/libxrpl/json/Writer.cpp b/src/libxrpl/json/Writer.cpp index 44d106aa336..ba7336209e6 100644 --- a/src/libxrpl/json/Writer.cpp +++ b/src/libxrpl/json/Writer.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include diff --git a/src/libxrpl/json/json_reader.cpp b/src/libxrpl/json/json_reader.cpp index 001049bcdbc..42488b3ec87 100644 --- a/src/libxrpl/json/json_reader.cpp +++ b/src/libxrpl/json/json_reader.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include diff --git a/src/libxrpl/json/json_value.cpp b/src/libxrpl/json/json_value.cpp index 024ad2c88a0..155c3e1e044 100644 --- a/src/libxrpl/json/json_value.cpp +++ b/src/libxrpl/json/json_value.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace Json { diff --git a/src/libxrpl/json/json_valueiterator.cpp b/src/libxrpl/json/json_valueiterator.cpp index 355bfad23cd..c1a1bcc56a0 100644 --- a/src/libxrpl/json/json_valueiterator.cpp +++ b/src/libxrpl/json/json_valueiterator.cpp @@ -19,7 +19,7 @@ // included by json_value.cpp -#include +#include namespace Json { diff --git a/src/libxrpl/json/json_writer.cpp b/src/libxrpl/json/json_writer.cpp index 4d696ab55bc..5459042cddb 100644 --- a/src/libxrpl/json/json_writer.cpp +++ b/src/libxrpl/json/json_writer.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include #include #include diff --git a/src/libxrpl/json/to_string.cpp b/src/libxrpl/json/to_string.cpp index b965417721e..7bf58241201 100644 --- a/src/libxrpl/json/to_string.cpp +++ b/src/libxrpl/json/to_string.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace Json { diff --git a/src/libxrpl/protocol/AMMCore.cpp b/src/libxrpl/protocol/AMMCore.cpp index b774ee4ee3b..7ac27041e76 100644 --- a/src/libxrpl/protocol/AMMCore.cpp +++ b/src/libxrpl/protocol/AMMCore.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/AccountID.cpp b/src/libxrpl/protocol/AccountID.cpp index c615807cf84..5f0fa631851 100644 --- a/src/libxrpl/protocol/AccountID.cpp +++ b/src/libxrpl/protocol/AccountID.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/libxrpl/protocol/Book.cpp b/src/libxrpl/protocol/Book.cpp index 3ad22675d1b..c096dba2b4e 100644 --- a/src/libxrpl/protocol/Book.cpp +++ b/src/libxrpl/protocol/Book.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/BuildInfo.cpp b/src/libxrpl/protocol/BuildInfo.cpp index 8a83011e906..9139f29e83c 100644 --- a/src/libxrpl/protocol/BuildInfo.cpp +++ b/src/libxrpl/protocol/BuildInfo.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/libxrpl/protocol/ErrorCodes.cpp b/src/libxrpl/protocol/ErrorCodes.cpp index 3af48891c78..28024fab093 100644 --- a/src/libxrpl/protocol/ErrorCodes.cpp +++ b/src/libxrpl/protocol/ErrorCodes.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include #include #include diff --git a/src/libxrpl/protocol/Feature.cpp b/src/libxrpl/protocol/Feature.cpp index 4434a7fbdc3..992d51ca974 100644 --- a/src/libxrpl/protocol/Feature.cpp +++ b/src/libxrpl/protocol/Feature.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include +#include -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/src/libxrpl/protocol/Indexes.cpp b/src/libxrpl/protocol/Indexes.cpp index 0ee52aab297..30d97416cfa 100644 --- a/src/libxrpl/protocol/Indexes.cpp +++ b/src/libxrpl/protocol/Indexes.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/libxrpl/protocol/InnerObjectFormats.cpp b/src/libxrpl/protocol/InnerObjectFormats.cpp index edebc57477e..6d7b855d199 100644 --- a/src/libxrpl/protocol/InnerObjectFormats.cpp +++ b/src/libxrpl/protocol/InnerObjectFormats.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/Issue.cpp b/src/libxrpl/protocol/Issue.cpp index 623ce24bb15..70d2c013d7b 100644 --- a/src/libxrpl/protocol/Issue.cpp +++ b/src/libxrpl/protocol/Issue.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include +#include -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/Keylet.cpp b/src/libxrpl/protocol/Keylet.cpp index 2488e8b45b6..23847811d3b 100644 --- a/src/libxrpl/protocol/Keylet.cpp +++ b/src/libxrpl/protocol/Keylet.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/LedgerFormats.cpp b/src/libxrpl/protocol/LedgerFormats.cpp index 4f117a5d60d..9401c00278b 100644 --- a/src/libxrpl/protocol/LedgerFormats.cpp +++ b/src/libxrpl/protocol/LedgerFormats.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include namespace ripple { diff --git a/src/libxrpl/protocol/LedgerHeader.cpp b/src/libxrpl/protocol/LedgerHeader.cpp index 6d13db224fd..284c4dc0557 100644 --- a/src/libxrpl/protocol/LedgerHeader.cpp +++ b/src/libxrpl/protocol/LedgerHeader.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/NFTSyntheticSerializer.cpp b/src/libxrpl/protocol/NFTSyntheticSerializer.cpp index e34397ada6a..03c9e79e265 100644 --- a/src/libxrpl/protocol/NFTSyntheticSerializer.cpp +++ b/src/libxrpl/protocol/NFTSyntheticSerializer.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/NFTokenID.cpp b/src/libxrpl/protocol/NFTokenID.cpp index ea6ab984c19..72fb8b87bbe 100644 --- a/src/libxrpl/protocol/NFTokenID.cpp +++ b/src/libxrpl/protocol/NFTokenID.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/NFTokenOfferID.cpp b/src/libxrpl/protocol/NFTokenOfferID.cpp index 51408bfb21a..3d761e6b939 100644 --- a/src/libxrpl/protocol/NFTokenOfferID.cpp +++ b/src/libxrpl/protocol/NFTokenOfferID.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/PublicKey.cpp b/src/libxrpl/protocol/PublicKey.cpp index 22cb351e61c..fdab288cea0 100644 --- a/src/libxrpl/protocol/PublicKey.cpp +++ b/src/libxrpl/protocol/PublicKey.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/src/libxrpl/protocol/Quality.cpp b/src/libxrpl/protocol/Quality.cpp index 2cb60f738d8..38b641328b0 100644 --- a/src/libxrpl/protocol/Quality.cpp +++ b/src/libxrpl/protocol/Quality.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include #include diff --git a/src/libxrpl/protocol/QualityFunction.cpp b/src/libxrpl/protocol/QualityFunction.cpp index 29270928480..64e5a36989c 100644 --- a/src/libxrpl/protocol/QualityFunction.cpp +++ b/src/libxrpl/protocol/QualityFunction.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include +#include -#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/RPCErr.cpp b/src/libxrpl/protocol/RPCErr.cpp index ec0474fe8b0..e9ca3c3c1e6 100644 --- a/src/libxrpl/protocol/RPCErr.cpp +++ b/src/libxrpl/protocol/RPCErr.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/Rate2.cpp b/src/libxrpl/protocol/Rate2.cpp index 340b6719bca..d85a49a5958 100644 --- a/src/libxrpl/protocol/Rate2.cpp +++ b/src/libxrpl/protocol/Rate2.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/Rules.cpp b/src/libxrpl/protocol/Rules.cpp index e65a9678f65..f47e966e138 100644 --- a/src/libxrpl/protocol/Rules.cpp +++ b/src/libxrpl/protocol/Rules.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include #include diff --git a/src/libxrpl/protocol/SField.cpp b/src/libxrpl/protocol/SField.cpp index 6d034db75ef..d56f3983352 100644 --- a/src/libxrpl/protocol/SField.cpp +++ b/src/libxrpl/protocol/SField.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include #include #include diff --git a/src/libxrpl/protocol/SOTemplate.cpp b/src/libxrpl/protocol/SOTemplate.cpp index 8457b759126..d75261c0a64 100644 --- a/src/libxrpl/protocol/SOTemplate.cpp +++ b/src/libxrpl/protocol/SOTemplate.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/STAccount.cpp b/src/libxrpl/protocol/STAccount.cpp index 5881ae5b264..8ae43f76863 100644 --- a/src/libxrpl/protocol/STAccount.cpp +++ b/src/libxrpl/protocol/STAccount.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include diff --git a/src/libxrpl/protocol/STAmount.cpp b/src/libxrpl/protocol/STAmount.cpp index a02dc9e89e1..236603d6cb8 100644 --- a/src/libxrpl/protocol/STAmount.cpp +++ b/src/libxrpl/protocol/STAmount.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/libxrpl/protocol/STArray.cpp b/src/libxrpl/protocol/STArray.cpp index 7ee3da1ff1a..0dea9c7665e 100644 --- a/src/libxrpl/protocol/STArray.cpp +++ b/src/libxrpl/protocol/STArray.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/STBase.cpp b/src/libxrpl/protocol/STBase.cpp index b49b65bf25d..b7e9c94ca24 100644 --- a/src/libxrpl/protocol/STBase.cpp +++ b/src/libxrpl/protocol/STBase.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include #include #include diff --git a/src/libxrpl/protocol/STBlob.cpp b/src/libxrpl/protocol/STBlob.cpp index 871c535e9dd..63e7b4bf3da 100644 --- a/src/libxrpl/protocol/STBlob.cpp +++ b/src/libxrpl/protocol/STBlob.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/STCurrency.cpp b/src/libxrpl/protocol/STCurrency.cpp index d2bc1b3bea7..c8fc650135a 100644 --- a/src/libxrpl/protocol/STCurrency.cpp +++ b/src/libxrpl/protocol/STCurrency.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include +#include +#include -#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/STInteger.cpp b/src/libxrpl/protocol/STInteger.cpp index 2b154e369e4..7b7420006f9 100644 --- a/src/libxrpl/protocol/STInteger.cpp +++ b/src/libxrpl/protocol/STInteger.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/libxrpl/protocol/STIssue.cpp b/src/libxrpl/protocol/STIssue.cpp index 356af438659..9dcee6498ab 100644 --- a/src/libxrpl/protocol/STIssue.cpp +++ b/src/libxrpl/protocol/STIssue.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include +#include -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/libxrpl/protocol/STLedgerEntry.cpp b/src/libxrpl/protocol/STLedgerEntry.cpp index 10ec5627aa3..68d1455cb1d 100644 --- a/src/libxrpl/protocol/STLedgerEntry.cpp +++ b/src/libxrpl/protocol/STLedgerEntry.cpp @@ -17,16 +17,16 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/libxrpl/protocol/STObject.cpp b/src/libxrpl/protocol/STObject.cpp index dbcb47e8794..a369974c2d6 100644 --- a/src/libxrpl/protocol/STObject.cpp +++ b/src/libxrpl/protocol/STObject.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/STParsedJSON.cpp b/src/libxrpl/protocol/STParsedJSON.cpp index 6727fe7388c..dec5e87eaee 100644 --- a/src/libxrpl/protocol/STParsedJSON.cpp +++ b/src/libxrpl/protocol/STParsedJSON.cpp @@ -17,29 +17,29 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/libxrpl/protocol/STPathSet.cpp b/src/libxrpl/protocol/STPathSet.cpp index cc1e367ba45..b658465272e 100644 --- a/src/libxrpl/protocol/STPathSet.cpp +++ b/src/libxrpl/protocol/STPathSet.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/STTx.cpp b/src/libxrpl/protocol/STTx.cpp index 51fb11ad761..149186d43ce 100644 --- a/src/libxrpl/protocol/STTx.cpp +++ b/src/libxrpl/protocol/STTx.cpp @@ -17,22 +17,22 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/libxrpl/protocol/STValidation.cpp b/src/libxrpl/protocol/STValidation.cpp index e62a81733bd..ca5ceb0d9ce 100644 --- a/src/libxrpl/protocol/STValidation.cpp +++ b/src/libxrpl/protocol/STValidation.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/STVar.cpp b/src/libxrpl/protocol/STVar.cpp index adda165901f..c8466259f32 100644 --- a/src/libxrpl/protocol/STVar.cpp +++ b/src/libxrpl/protocol/STVar.cpp @@ -17,23 +17,23 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace detail { diff --git a/src/libxrpl/protocol/STVector256.cpp b/src/libxrpl/protocol/STVector256.cpp index 0ef1295b16a..2d8bc4ee225 100644 --- a/src/libxrpl/protocol/STVector256.cpp +++ b/src/libxrpl/protocol/STVector256.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/STXChainBridge.cpp b/src/libxrpl/protocol/STXChainBridge.cpp index 8ff19ca7e3b..2347e63379a 100644 --- a/src/libxrpl/protocol/STXChainBridge.cpp +++ b/src/libxrpl/protocol/STXChainBridge.cpp @@ -17,19 +17,19 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/libxrpl/protocol/SecretKey.cpp b/src/libxrpl/protocol/SecretKey.cpp index e83068610c9..474c37ac802 100644 --- a/src/libxrpl/protocol/SecretKey.cpp +++ b/src/libxrpl/protocol/SecretKey.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/libxrpl/protocol/Seed.cpp b/src/libxrpl/protocol/Seed.cpp index 49da20a429d..453b4593bfb 100644 --- a/src/libxrpl/protocol/Seed.cpp +++ b/src/libxrpl/protocol/Seed.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/libxrpl/protocol/Serializer.cpp b/src/libxrpl/protocol/Serializer.cpp index 42f79cfc518..b99375f80dd 100644 --- a/src/libxrpl/protocol/Serializer.cpp +++ b/src/libxrpl/protocol/Serializer.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/libxrpl/protocol/Sign.cpp b/src/libxrpl/protocol/Sign.cpp index b6313827f91..32645c3762c 100644 --- a/src/libxrpl/protocol/Sign.cpp +++ b/src/libxrpl/protocol/Sign.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/TER.cpp b/src/libxrpl/protocol/TER.cpp index 93bc60a98ba..f452b05464e 100644 --- a/src/libxrpl/protocol/TER.cpp +++ b/src/libxrpl/protocol/TER.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include #include diff --git a/src/libxrpl/protocol/TxFormats.cpp b/src/libxrpl/protocol/TxFormats.cpp index 324c0e30790..71c333dc497 100644 --- a/src/libxrpl/protocol/TxFormats.cpp +++ b/src/libxrpl/protocol/TxFormats.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include +#include -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/TxMeta.cpp b/src/libxrpl/protocol/TxMeta.cpp index 20fa61de2a8..253d00e8414 100644 --- a/src/libxrpl/protocol/TxMeta.cpp +++ b/src/libxrpl/protocol/TxMeta.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/libxrpl/protocol/UintTypes.cpp b/src/libxrpl/protocol/UintTypes.cpp index 821e81238b0..c57bcc153a3 100644 --- a/src/libxrpl/protocol/UintTypes.cpp +++ b/src/libxrpl/protocol/UintTypes.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/libxrpl/protocol/XChainAttestations.cpp b/src/libxrpl/protocol/XChainAttestations.cpp index 591b20ad5a0..f87f1c3e681 100644 --- a/src/libxrpl/protocol/XChainAttestations.cpp +++ b/src/libxrpl/protocol/XChainAttestations.cpp @@ -17,23 +17,23 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/libxrpl/protocol/digest.cpp b/src/libxrpl/protocol/digest.cpp index 444a71fb863..237e7aa49f0 100644 --- a/src/libxrpl/protocol/digest.cpp +++ b/src/libxrpl/protocol/digest.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include #include #include diff --git a/src/libxrpl/protocol/tokens.cpp b/src/libxrpl/protocol/tokens.cpp index 8445eec38ca..bec16945654 100644 --- a/src/libxrpl/protocol/tokens.cpp +++ b/src/libxrpl/protocol/tokens.cpp @@ -25,11 +25,11 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php. */ -#include +#include -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/libxrpl/resource/Charge.cpp b/src/libxrpl/resource/Charge.cpp index 21cf2af3ef6..deec6b34eb6 100644 --- a/src/libxrpl/resource/Charge.cpp +++ b/src/libxrpl/resource/Charge.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include namespace ripple { diff --git a/src/libxrpl/resource/Consumer.cpp b/src/libxrpl/resource/Consumer.cpp index 34edbbfcc71..b8652546841 100644 --- a/src/libxrpl/resource/Consumer.cpp +++ b/src/libxrpl/resource/Consumer.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include #include namespace ripple { diff --git a/src/libxrpl/resource/Fees.cpp b/src/libxrpl/resource/Fees.cpp index 0752e49ca48..13ae38bc6ad 100644 --- a/src/libxrpl/resource/Fees.cpp +++ b/src/libxrpl/resource/Fees.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { namespace Resource { diff --git a/src/libxrpl/resource/ResourceManager.cpp b/src/libxrpl/resource/ResourceManager.cpp index ae4eaac23fd..d73ca090024 100644 --- a/src/libxrpl/resource/ResourceManager.cpp +++ b/src/libxrpl/resource/ResourceManager.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/libxrpl/server/JSONRPCUtil.cpp b/src/libxrpl/server/JSONRPCUtil.cpp index 12d12829ca9..ce173b1e9eb 100644 --- a/src/libxrpl/server/JSONRPCUtil.cpp +++ b/src/libxrpl/server/JSONRPCUtil.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/libxrpl/server/Port.cpp b/src/libxrpl/server/Port.cpp index 1b869f6a5da..0554c8082a0 100644 --- a/src/libxrpl/server/Port.cpp +++ b/src/libxrpl/server/Port.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/src/test/app/AMMCalc_test.cpp b/src/test/app/AMMCalc_test.cpp index e230ed4d3c5..058cdfd1d2d 100644 --- a/src/test/app/AMMCalc_test.cpp +++ b/src/test/app/AMMCalc_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include #include diff --git a/src/test/app/AMMExtended_test.cpp b/src/test/app/AMMExtended_test.cpp index 27fb2ce14f5..96053b93b44 100644 --- a/src/test/app/AMMExtended_test.cpp +++ b/src/test/app/AMMExtended_test.cpp @@ -16,25 +16,25 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/test/app/AMM_test.cpp b/src/test/app/AMM_test.cpp index a3c4ae9800c..ceddc019504 100644 --- a/src/test/app/AMM_test.cpp +++ b/src/test/app/AMM_test.cpp @@ -16,23 +16,23 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/test/app/AccountDelete_test.cpp b/src/test/app/AccountDelete_test.cpp index fbd631f444a..5fbb0ba38b1 100644 --- a/src/test/app/AccountDelete_test.cpp +++ b/src/test/app/AccountDelete_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/AccountTxPaging_test.cpp b/src/test/app/AccountTxPaging_test.cpp index d3969e279b7..680e006a74f 100644 --- a/src/test/app/AccountTxPaging_test.cpp +++ b/src/test/app/AccountTxPaging_test.cpp @@ -16,15 +16,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include -#include -#include #include +#include +#include +#include +#include -#include -#include #include +#include +#include namespace ripple { diff --git a/src/test/app/AmendmentTable_test.cpp b/src/test/app/AmendmentTable_test.cpp index 238e05ba523..2f95fc0280b 100644 --- a/src/test/app/AmendmentTable_test.cpp +++ b/src/test/app/AmendmentTable_test.cpp @@ -17,21 +17,21 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/app/Check_test.cpp b/src/test/app/Check_test.cpp index 8f0c0ec46b8..31b45abf43a 100644 --- a/src/test/app/Check_test.cpp +++ b/src/test/app/Check_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/Clawback_test.cpp b/src/test/app/Clawback_test.cpp index 630e4836d8e..a6909bb2f62 100644 --- a/src/test/app/Clawback_test.cpp +++ b/src/test/app/Clawback_test.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/app/CrossingLimits_test.cpp b/src/test/app/CrossingLimits_test.cpp index 09cca1e82af..6f6a7eb3e7f 100644 --- a/src/test/app/CrossingLimits_test.cpp +++ b/src/test/app/CrossingLimits_test.cpp @@ -15,9 +15,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/DID_test.cpp b/src/test/app/DID_test.cpp index 82e77a20264..20734518887 100644 --- a/src/test/app/DID_test.cpp +++ b/src/test/app/DID_test.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include #include #include diff --git a/src/test/app/DNS_test.cpp b/src/test/app/DNS_test.cpp index 6ae4bc8d64a..7a39c5f0790 100644 --- a/src/test/app/DNS_test.cpp +++ b/src/test/app/DNS_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include #include #include diff --git a/src/test/app/DeliverMin_test.cpp b/src/test/app/DeliverMin_test.cpp index 316d95ba740..3c62a47a4a4 100644 --- a/src/test/app/DeliverMin_test.cpp +++ b/src/test/app/DeliverMin_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/DepositAuth_test.cpp b/src/test/app/DepositAuth_test.cpp index f10633c5e46..9a11785b38c 100644 --- a/src/test/app/DepositAuth_test.cpp +++ b/src/test/app/DepositAuth_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/app/Discrepancy_test.cpp b/src/test/app/Discrepancy_test.cpp index c89432f9115..1eaa1ad86dd 100644 --- a/src/test/app/Discrepancy_test.cpp +++ b/src/test/app/Discrepancy_test.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include #include #include #include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/app/Escrow_test.cpp b/src/test/app/Escrow_test.cpp index 083764fd371..813f26da736 100644 --- a/src/test/app/Escrow_test.cpp +++ b/src/test/app/Escrow_test.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/test/app/FeeVote_test.cpp b/src/test/app/FeeVote_test.cpp index ad38aefb20a..289ce2a713e 100644 --- a/src/test/app/FeeVote_test.cpp +++ b/src/test/app/FeeVote_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/Flow_test.cpp b/src/test/app/Flow_test.cpp index bb7b96f1072..9d1257d16bf 100644 --- a/src/test/app/Flow_test.cpp +++ b/src/test/app/Flow_test.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/Freeze_test.cpp b/src/test/app/Freeze_test.cpp index cb4653c086d..0c54f0e1f39 100644 --- a/src/test/app/Freeze_test.cpp +++ b/src/test/app/Freeze_test.cpp @@ -16,12 +16,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/app/HashRouter_test.cpp b/src/test/app/HashRouter_test.cpp index 96d14e824cf..1234bc5b9cb 100644 --- a/src/test/app/HashRouter_test.cpp +++ b/src/test/app/HashRouter_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/LedgerHistory_test.cpp b/src/test/app/LedgerHistory_test.cpp index 880cbea5980..e1a837a9cb2 100644 --- a/src/test/app/LedgerHistory_test.cpp +++ b/src/test/app/LedgerHistory_test.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include -#include -#include namespace ripple { namespace test { diff --git a/src/test/app/LedgerLoad_test.cpp b/src/test/app/LedgerLoad_test.cpp index 599215c2435..5b6df353d81 100644 --- a/src/test/app/LedgerLoad_test.cpp +++ b/src/test/app/LedgerLoad_test.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/test/app/LedgerMaster_test.cpp b/src/test/app/LedgerMaster_test.cpp index 87639c42fcd..d53d27b3185 100644 --- a/src/test/app/LedgerMaster_test.cpp +++ b/src/test/app/LedgerMaster_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include #include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/LedgerReplay_test.cpp b/src/test/app/LedgerReplay_test.cpp index aee24cd7d57..0b555a712cf 100644 --- a/src/test/app/LedgerReplay_test.cpp +++ b/src/test/app/LedgerReplay_test.cpp @@ -17,19 +17,19 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/test/app/LoadFeeTrack_test.cpp b/src/test/app/LoadFeeTrack_test.cpp index f8e73cebd16..fa7489bf1bb 100644 --- a/src/test/app/LoadFeeTrack_test.cpp +++ b/src/test/app/LoadFeeTrack_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/app/Manifest_test.cpp b/src/test/app/Manifest_test.cpp index b72623309e9..bf7b14c0d28 100644 --- a/src/test/app/Manifest_test.cpp +++ b/src/test/app/Manifest_test.cpp @@ -17,20 +17,20 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include -#include namespace ripple { namespace test { diff --git a/src/test/app/MultiSign_test.cpp b/src/test/app/MultiSign_test.cpp index 0e151b38d0a..77d85d9011b 100644 --- a/src/test/app/MultiSign_test.cpp +++ b/src/test/app/MultiSign_test.cpp @@ -15,10 +15,10 @@ */ //============================================================================== -#include -#include -#include #include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/NFTokenBurn_test.cpp b/src/test/app/NFTokenBurn_test.cpp index abd9ed56e83..8219889b4be 100644 --- a/src/test/app/NFTokenBurn_test.cpp +++ b/src/test/app/NFTokenBurn_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include #include +#include +#include +#include #include diff --git a/src/test/app/NFTokenDir_test.cpp b/src/test/app/NFTokenDir_test.cpp index 8e6a9fe5209..23e4c671526 100644 --- a/src/test/app/NFTokenDir_test.cpp +++ b/src/test/app/NFTokenDir_test.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include #include +#include +#include +#include +#include #include diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index 69432c85d17..9c0e09d6711 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include #include +#include +#include +#include +#include #include diff --git a/src/test/app/NetworkID_test.cpp b/src/test/app/NetworkID_test.cpp index 8d1b891345d..2f02a1fd7d2 100644 --- a/src/test/app/NetworkID_test.cpp +++ b/src/test/app/NetworkID_test.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include #include #include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/OfferStream_test.cpp b/src/test/app/OfferStream_test.cpp index ce25481cde8..bf712503687 100644 --- a/src/test/app/OfferStream_test.cpp +++ b/src/test/app/OfferStream_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { diff --git a/src/test/app/Offer_test.cpp b/src/test/app/Offer_test.cpp index 3956adfbe0d..2b4245a1ae4 100644 --- a/src/test/app/Offer_test.cpp +++ b/src/test/app/Offer_test.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include #include #include #include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/Oracle_test.cpp b/src/test/app/Oracle_test.cpp index 16a72de70fd..c2f3c271265 100644 --- a/src/test/app/Oracle_test.cpp +++ b/src/test/app/Oracle_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/app/OversizeMeta_test.cpp b/src/test/app/OversizeMeta_test.cpp index 554033eb531..0a7f42e1801 100644 --- a/src/test/app/OversizeMeta_test.cpp +++ b/src/test/app/OversizeMeta_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/Path_test.cpp b/src/test/app/Path_test.cpp index 0f9916cbcff..1db15388ff0 100644 --- a/src/test/app/Path_test.cpp +++ b/src/test/app/Path_test.cpp @@ -17,25 +17,25 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include -#include -#include #include namespace ripple { diff --git a/src/test/app/PayChan_test.cpp b/src/test/app/PayChan_test.cpp index a479e43b170..a8eae4a25ec 100644 --- a/src/test/app/PayChan_test.cpp +++ b/src/test/app/PayChan_test.cpp @@ -17,16 +17,16 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/PayStrand_test.cpp b/src/test/app/PayStrand_test.cpp index ae17b8e0d43..f00a7361292 100644 --- a/src/test/app/PayStrand_test.cpp +++ b/src/test/app/PayStrand_test.cpp @@ -15,20 +15,20 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/PseudoTx_test.cpp b/src/test/app/PseudoTx_test.cpp index 78ca7cc05b1..238041a17bc 100644 --- a/src/test/app/PseudoTx_test.cpp +++ b/src/test/app/PseudoTx_test.cpp @@ -15,11 +15,11 @@ */ //============================================================================== -#include -#include -#include -#include #include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/test/app/RCLCensorshipDetector_test.cpp b/src/test/app/RCLCensorshipDetector_test.cpp index 12bb3bbba3f..b5440b90903 100644 --- a/src/test/app/RCLCensorshipDetector_test.cpp +++ b/src/test/app/RCLCensorshipDetector_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include diff --git a/src/test/app/RCLValidations_test.cpp b/src/test/app/RCLValidations_test.cpp index 0380795a8ae..540d98bc1f1 100644 --- a/src/test/app/RCLValidations_test.cpp +++ b/src/test/app/RCLValidations_test.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/ReducedOffer_test.cpp b/src/test/app/ReducedOffer_test.cpp index 186162d5023..a070051e435 100644 --- a/src/test/app/ReducedOffer_test.cpp +++ b/src/test/app/ReducedOffer_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include #include +#include +#include +#include #include diff --git a/src/test/app/Regression_test.cpp b/src/test/app/Regression_test.cpp index f743a30f079..f54a88ace00 100644 --- a/src/test/app/Regression_test.cpp +++ b/src/test/app/Regression_test.cpp @@ -15,13 +15,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/SHAMapStore_test.cpp b/src/test/app/SHAMapStore_test.cpp index 8a47b186957..376cb4eb7ba 100644 --- a/src/test/app/SHAMapStore_test.cpp +++ b/src/test/app/SHAMapStore_test.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/SetAuth_test.cpp b/src/test/app/SetAuth_test.cpp index 8066ef0dacf..adb909314d3 100644 --- a/src/test/app/SetAuth_test.cpp +++ b/src/test/app/SetAuth_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/SetRegularKey_test.cpp b/src/test/app/SetRegularKey_test.cpp index 799b7797b85..024d8de137b 100644 --- a/src/test/app/SetRegularKey_test.cpp +++ b/src/test/app/SetRegularKey_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { diff --git a/src/test/app/SetTrust_test.cpp b/src/test/app/SetTrust_test.cpp index cab0132ae1c..57e18d712f8 100644 --- a/src/test/app/SetTrust_test.cpp +++ b/src/test/app/SetTrust_test.cpp @@ -16,9 +16,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { diff --git a/src/test/app/Taker_test.cpp b/src/test/app/Taker_test.cpp index 0b69b25f24b..89e44b2b98b 100644 --- a/src/test/app/Taker_test.cpp +++ b/src/test/app/Taker_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include #include namespace ripple { diff --git a/src/test/app/TheoreticalQuality_test.cpp b/src/test/app/TheoreticalQuality_test.cpp index ae537a45657..917d23377bf 100644 --- a/src/test/app/TheoreticalQuality_test.cpp +++ b/src/test/app/TheoreticalQuality_test.cpp @@ -17,20 +17,20 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/Ticket_test.cpp b/src/test/app/Ticket_test.cpp index b50059711ec..9467390502c 100644 --- a/src/test/app/Ticket_test.cpp +++ b/src/test/app/Ticket_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include #include +#include +#include +#include namespace ripple { diff --git a/src/test/app/Transaction_ordering_test.cpp b/src/test/app/Transaction_ordering_test.cpp index 0353df90663..928fcdb8389 100644 --- a/src/test/app/Transaction_ordering_test.cpp +++ b/src/test/app/Transaction_ordering_test.cpp @@ -15,9 +15,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/app/TrustAndBalance_test.cpp b/src/test/app/TrustAndBalance_test.cpp index 5b0c1d6480e..bf7c8629b69 100644 --- a/src/test/app/TrustAndBalance_test.cpp +++ b/src/test/app/TrustAndBalance_test.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include #include #include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/app/TxQ_test.cpp b/src/test/app/TxQ_test.cpp index 086bb787d68..e7b70203c91 100644 --- a/src/test/app/TxQ_test.cpp +++ b/src/test/app/TxQ_test.cpp @@ -17,19 +17,19 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/app/ValidatorKeys_test.cpp b/src/test/app/ValidatorKeys_test.cpp index 99bd6188261..9281ec4bd77 100644 --- a/src/test/app/ValidatorKeys_test.cpp +++ b/src/test/app/ValidatorKeys_test.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include #include diff --git a/src/test/app/ValidatorList_test.cpp b/src/test/app/ValidatorList_test.cpp index 638c2060d32..05989c0f601 100644 --- a/src/test/app/ValidatorList_test.cpp +++ b/src/test/app/ValidatorList_test.cpp @@ -17,19 +17,19 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/test/app/ValidatorSite_test.cpp b/src/test/app/ValidatorSite_test.cpp index 00512d157ec..4bc7f2f270d 100644 --- a/src/test/app/ValidatorSite_test.cpp +++ b/src/test/app/ValidatorSite_test.cpp @@ -17,25 +17,25 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include #include #include -#include -#include -#include namespace ripple { namespace test { diff --git a/src/test/app/XChain_test.cpp b/src/test/app/XChain_test.cpp index a0837782a9c..4f24d17601e 100644 --- a/src/test/app/XChain_test.cpp +++ b/src/test/app/XChain_test.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/test/app/tx/apply_test.cpp b/src/test/app/tx/apply_test.cpp index 61a512805a4..df76e839a71 100644 --- a/src/test/app/tx/apply_test.cpp +++ b/src/test/app/tx/apply_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include #include +#include +#include +#include namespace ripple { diff --git a/src/test/basics/Buffer_test.cpp b/src/test/basics/Buffer_test.cpp index 45d2147a054..da8bcc8f12c 100644 --- a/src/test/basics/Buffer_test.cpp +++ b/src/test/basics/Buffer_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include diff --git a/src/test/basics/DetectCrash_test.cpp b/src/test/basics/DetectCrash_test.cpp index 70f0bdb83be..1ae761f34a4 100644 --- a/src/test/basics/DetectCrash_test.cpp +++ b/src/test/basics/DetectCrash_test.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include diff --git a/src/test/basics/Expected_test.cpp b/src/test/basics/Expected_test.cpp index b89b9f6d309..d60809aee1f 100644 --- a/src/test/basics/Expected_test.cpp +++ b/src/test/basics/Expected_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include #if BOOST_VERSION >= 107500 #include // Not part of boost before version 1.75 #endif // BOOST_VERSION diff --git a/src/test/basics/FeeUnits_test.cpp b/src/test/basics/FeeUnits_test.cpp index 3ded5812947..6608a072621 100644 --- a/src/test/basics/FeeUnits_test.cpp +++ b/src/test/basics/FeeUnits_test.cpp @@ -16,9 +16,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include -#include +#include +#include +#include #include namespace ripple { diff --git a/src/test/basics/FileUtilities_test.cpp b/src/test/basics/FileUtilities_test.cpp index 2a9710f8e95..2b84998da7c 100644 --- a/src/test/basics/FileUtilities_test.cpp +++ b/src/test/basics/FileUtilities_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include #include +#include +#include +#include namespace ripple { diff --git a/src/test/basics/IOUAmount_test.cpp b/src/test/basics/IOUAmount_test.cpp index a5f7d0456ad..6e7c662635f 100644 --- a/src/test/basics/IOUAmount_test.cpp +++ b/src/test/basics/IOUAmount_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { diff --git a/src/test/basics/KeyCache_test.cpp b/src/test/basics/KeyCache_test.cpp index 7f3f13e272d..eab0e87d0a7 100644 --- a/src/test/basics/KeyCache_test.cpp +++ b/src/test/basics/KeyCache_test.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/basics/Number_test.cpp b/src/test/basics/Number_test.cpp index 8c12ff7c5e4..cf626354e0f 100644 --- a/src/test/basics/Number_test.cpp +++ b/src/test/basics/Number_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/test/basics/PerfLog_test.cpp b/src/test/basics/PerfLog_test.cpp index f0a6645195b..756988cbdac 100644 --- a/src/test/basics/PerfLog_test.cpp +++ b/src/test/basics/PerfLog_test.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/test/basics/RangeSet_test.cpp b/src/test/basics/RangeSet_test.cpp index ccf76fad0d4..e0136ab8907 100644 --- a/src/test/basics/RangeSet_test.cpp +++ b/src/test/basics/RangeSet_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { class RangeSet_test : public beast::unit_test::suite diff --git a/src/test/basics/Slice_test.cpp b/src/test/basics/Slice_test.cpp index fb88315bd98..a169de98539 100644 --- a/src/test/basics/Slice_test.cpp +++ b/src/test/basics/Slice_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include diff --git a/src/test/basics/StringUtilities_test.cpp b/src/test/basics/StringUtilities_test.cpp index 6146a3dcd41..cf916c62651 100644 --- a/src/test/basics/StringUtilities_test.cpp +++ b/src/test/basics/StringUtilities_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/basics/TaggedCache_test.cpp b/src/test/basics/TaggedCache_test.cpp index 6a5b4429996..6fbba1a4795 100644 --- a/src/test/basics/TaggedCache_test.cpp +++ b/src/test/basics/TaggedCache_test.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/basics/XRPAmount_test.cpp b/src/test/basics/XRPAmount_test.cpp index 37c827180de..c4c96dbfbde 100644 --- a/src/test/basics/XRPAmount_test.cpp +++ b/src/test/basics/XRPAmount_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { diff --git a/src/test/basics/base58_test.cpp b/src/test/basics/base58_test.cpp index 6f3d495d7a9..f204cdd0e3a 100644 --- a/src/test/basics/base58_test.cpp +++ b/src/test/basics/base58_test.cpp @@ -19,9 +19,9 @@ #ifndef _MSC_VER -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/test/basics/base64_test.cpp b/src/test/basics/base64_test.cpp index d9622a8c28a..b6d67c7c069 100644 --- a/src/test/basics/base64_test.cpp +++ b/src/test/basics/base64_test.cpp @@ -26,8 +26,8 @@ // Official repository: https://github.com/boostorg/beast // -#include -#include +#include +#include namespace ripple { diff --git a/src/test/basics/base_uint_test.cpp b/src/test/basics/base_uint_test.cpp index 9b1f7696dd5..43000a1128c 100644 --- a/src/test/basics/base_uint_test.cpp +++ b/src/test/basics/base_uint_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/test/basics/contract_test.cpp b/src/test/basics/contract_test.cpp index 58844ba97f8..99f118794ee 100644 --- a/src/test/basics/contract_test.cpp +++ b/src/test/basics/contract_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include namespace ripple { diff --git a/src/test/basics/hardened_hash_test.cpp b/src/test/basics/hardened_hash_test.cpp index 9296b7faf02..343894e52b0 100644 --- a/src/test/basics/hardened_hash_test.cpp +++ b/src/test/basics/hardened_hash_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include #include diff --git a/src/test/basics/join_test.cpp b/src/test/basics/join_test.cpp index 730fcb69343..1b094828243 100644 --- a/src/test/basics/join_test.cpp +++ b/src/test/basics/join_test.cpp @@ -19,8 +19,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include -#include -#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/basics/mulDiv_test.cpp b/src/test/basics/mulDiv_test.cpp index f51b91fecf4..47332fd45ba 100644 --- a/src/test/basics/mulDiv_test.cpp +++ b/src/test/basics/mulDiv_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/basics/scope_test.cpp b/src/test/basics/scope_test.cpp index 414e67b5c7e..654f7e0a11b 100644 --- a/src/test/basics/scope_test.cpp +++ b/src/test/basics/scope_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/basics/tagged_integer_test.cpp b/src/test/basics/tagged_integer_test.cpp index dd9d9022dde..22cdc5ad53f 100644 --- a/src/test/basics/tagged_integer_test.cpp +++ b/src/test/basics/tagged_integer_test.cpp @@ -18,8 +18,8 @@ */ //============================================================================== -#include -#include +#include +#include #include namespace ripple { diff --git a/src/test/beast/IPEndpointCommon.h b/src/test/beast/IPEndpointCommon.h index bf8e7613fe5..aa2c1e597fb 100644 --- a/src/test/beast/IPEndpointCommon.h +++ b/src/test/beast/IPEndpointCommon.h @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace beast { namespace IP { diff --git a/src/test/beast/IPEndpoint_test.cpp b/src/test/beast/IPEndpoint_test.cpp index 1a29ddefa43..1ad49443dc3 100644 --- a/src/test/beast/IPEndpoint_test.cpp +++ b/src/test/beast/IPEndpoint_test.cpp @@ -20,13 +20,13 @@ // MODULES: ../impl/IPEndpoint.cpp ../impl/IPAddressV4.cpp // ../impl/IPAddressV6.cpp -#include -#include -#include +#include +#include +#include +#include #include #include #include -#include #include namespace beast { diff --git a/src/test/beast/LexicalCast_test.cpp b/src/test/beast/LexicalCast_test.cpp index 680dc6d69ac..22638f27e6e 100644 --- a/src/test/beast/LexicalCast_test.cpp +++ b/src/test/beast/LexicalCast_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include namespace beast { diff --git a/src/test/beast/SemanticVersion_test.cpp b/src/test/beast/SemanticVersion_test.cpp index 5026f0fbae7..2f24a0c8926 100644 --- a/src/test/beast/SemanticVersion_test.cpp +++ b/src/test/beast/SemanticVersion_test.cpp @@ -16,8 +16,8 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include +#include +#include namespace beast { class SemanticVersion_test : public unit_test::suite diff --git a/src/test/beast/aged_associative_container_test.cpp b/src/test/beast/aged_associative_container_test.cpp index be17240811d..e5736764e06 100644 --- a/src/test/beast/aged_associative_container_test.cpp +++ b/src/test/beast/aged_associative_container_test.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/test/beast/beast_CurrentThreadName_test.cpp b/src/test/beast/beast_CurrentThreadName_test.cpp index 6e46808f4b2..653b0a89618 100644 --- a/src/test/beast/beast_CurrentThreadName_test.cpp +++ b/src/test/beast/beast_CurrentThreadName_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include diff --git a/src/test/beast/beast_Journal_test.cpp b/src/test/beast/beast_Journal_test.cpp index 9d3567c277d..6f1652381a0 100644 --- a/src/test/beast/beast_Journal_test.cpp +++ b/src/test/beast/beast_Journal_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace beast { diff --git a/src/test/beast/beast_PropertyStream_test.cpp b/src/test/beast/beast_PropertyStream_test.cpp index 2c4d32ce459..e91f527d3c9 100644 --- a/src/test/beast/beast_PropertyStream_test.cpp +++ b/src/test/beast/beast_PropertyStream_test.cpp @@ -16,8 +16,8 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include +#include +#include namespace beast { class PropertyStream_test : public unit_test::suite diff --git a/src/test/beast/beast_Zero_test.cpp b/src/test/beast/beast_Zero_test.cpp index 42b07343741..b6071636255 100644 --- a/src/test/beast/beast_Zero_test.cpp +++ b/src/test/beast/beast_Zero_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include +#include -#include +#include namespace beast { diff --git a/src/test/beast/beast_abstract_clock_test.cpp b/src/test/beast/beast_abstract_clock_test.cpp index eba9a3d77b1..a026df26376 100644 --- a/src/test/beast/beast_abstract_clock_test.cpp +++ b/src/test/beast/beast_abstract_clock_test.cpp @@ -19,9 +19,9 @@ // MODULES: ../impl/chrono_io.cpp -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/src/test/beast/beast_basic_seconds_clock_test.cpp b/src/test/beast/beast_basic_seconds_clock_test.cpp index 5e55aab598b..f3926634dc4 100644 --- a/src/test/beast/beast_basic_seconds_clock_test.cpp +++ b/src/test/beast/beast_basic_seconds_clock_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include +#include -#include +#include namespace beast { diff --git a/src/test/beast/beast_io_latency_probe_test.cpp b/src/test/beast/beast_io_latency_probe_test.cpp index 32206ced7f7..96228194304 100644 --- a/src/test/beast/beast_io_latency_probe_test.cpp +++ b/src/test/beast/beast_io_latency_probe_test.cpp @@ -16,10 +16,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include +#include +#include -#include +#include #include #include diff --git a/src/test/beast/define_print.cpp b/src/test/beast/define_print.cpp index 3f527907a3f..0d36cd76982 100644 --- a/src/test/beast/define_print.cpp +++ b/src/test/beast/define_print.cpp @@ -5,9 +5,9 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#include -#include -#include +#include +#include +#include #include // Include this .cpp in your project to gain access to the printing suite diff --git a/src/test/conditions/PreimageSha256_test.cpp b/src/test/conditions/PreimageSha256_test.cpp index cf4bc8c7c1e..9a6840b11c3 100644 --- a/src/test/conditions/PreimageSha256_test.cpp +++ b/src/test/conditions/PreimageSha256_test.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/test/consensus/ByzantineFailureSim_test.cpp b/src/test/consensus/ByzantineFailureSim_test.cpp index a907b7c224e..ce59adbe9f0 100644 --- a/src/test/consensus/ByzantineFailureSim_test.cpp +++ b/src/test/consensus/ByzantineFailureSim_test.cpp @@ -16,9 +16,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include #include +#include +#include #include namespace ripple { diff --git a/src/test/consensus/Consensus_test.cpp b/src/test/consensus/Consensus_test.cpp index 1ef1a718d3c..88280994c10 100644 --- a/src/test/consensus/Consensus_test.cpp +++ b/src/test/consensus/Consensus_test.cpp @@ -16,12 +16,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include -#include -#include #include #include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/test/consensus/DistributedValidatorsSim_test.cpp b/src/test/consensus/DistributedValidatorsSim_test.cpp index ef1ae8b8722..3abac36b4f1 100644 --- a/src/test/consensus/DistributedValidatorsSim_test.cpp +++ b/src/test/consensus/DistributedValidatorsSim_test.cpp @@ -16,9 +16,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include #include +#include +#include #include #include diff --git a/src/test/consensus/LedgerTiming_test.cpp b/src/test/consensus/LedgerTiming_test.cpp index 98b0548bf11..95e27f5c854 100644 --- a/src/test/consensus/LedgerTiming_test.cpp +++ b/src/test/consensus/LedgerTiming_test.cpp @@ -16,8 +16,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/consensus/LedgerTrie_test.cpp b/src/test/consensus/LedgerTrie_test.cpp index 3feb3b09959..6f13db43be2 100644 --- a/src/test/consensus/LedgerTrie_test.cpp +++ b/src/test/consensus/LedgerTrie_test.cpp @@ -16,10 +16,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include -#include #include +#include +#include +#include #include namespace ripple { diff --git a/src/test/consensus/NegativeUNL_test.cpp b/src/test/consensus/NegativeUNL_test.cpp index 8cbb57444bd..200cd166031 100644 --- a/src/test/consensus/NegativeUNL_test.cpp +++ b/src/test/consensus/NegativeUNL_test.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/consensus/ScaleFreeSim_test.cpp b/src/test/consensus/ScaleFreeSim_test.cpp index 4fe911eacf4..3e3cec97618 100644 --- a/src/test/consensus/ScaleFreeSim_test.cpp +++ b/src/test/consensus/ScaleFreeSim_test.cpp @@ -16,10 +16,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include #include #include +#include +#include #include namespace ripple { diff --git a/src/test/consensus/Validations_test.cpp b/src/test/consensus/Validations_test.cpp index 7dc2086e55c..0279d6330cc 100644 --- a/src/test/consensus/Validations_test.cpp +++ b/src/test/consensus/Validations_test.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/test/core/ClosureCounter_test.cpp b/src/test/core/ClosureCounter_test.cpp index c4199a0b06e..83d2fdb6e4a 100644 --- a/src/test/core/ClosureCounter_test.cpp +++ b/src/test/core/ClosureCounter_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include #include #include diff --git a/src/test/core/Config_test.cpp b/src/test/core/Config_test.cpp index c991f3b11a2..3cf77fba2ef 100644 --- a/src/test/core/Config_test.cpp +++ b/src/test/core/Config_test.cpp @@ -17,16 +17,16 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include #include -#include -#include namespace ripple { namespace detail { diff --git a/src/test/core/Coroutine_test.cpp b/src/test/core/Coroutine_test.cpp index 6d1e5e33304..0fdc5a4f49a 100644 --- a/src/test/core/Coroutine_test.cpp +++ b/src/test/core/Coroutine_test.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include +#include +#include #include #include #include -#include namespace ripple { namespace test { diff --git a/src/test/core/CryptoPRNG_test.cpp b/src/test/core/CryptoPRNG_test.cpp index 11bf9b7a161..303a2176315 100644 --- a/src/test/core/CryptoPRNG_test.cpp +++ b/src/test/core/CryptoPRNG_test.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include +#include +#include +#include #include #include #include -#include namespace ripple { diff --git a/src/test/core/JobQueue_test.cpp b/src/test/core/JobQueue_test.cpp index cba0217675c..42338063db3 100644 --- a/src/test/core/JobQueue_test.cpp +++ b/src/test/core/JobQueue_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/core/SociDB_test.cpp b/src/test/core/SociDB_test.cpp index c0365ad9ae7..82d0cbe9035 100644 --- a/src/test/core/SociDB_test.cpp +++ b/src/test/core/SociDB_test.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include -#include namespace ripple { class SociDB_test final : public TestSuite diff --git a/src/test/core/Workers_test.cpp b/src/test/core/Workers_test.cpp index 155dd14f030..3fac4808f9f 100644 --- a/src/test/core/Workers_test.cpp +++ b/src/test/core/Workers_test.cpp @@ -17,11 +17,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/test/csf/BasicNetwork_test.cpp b/src/test/csf/BasicNetwork_test.cpp index f3b18216ac7..61660ae4c4e 100644 --- a/src/test/csf/BasicNetwork_test.cpp +++ b/src/test/csf/BasicNetwork_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include #include #include +#include +#include #include namespace ripple { diff --git a/src/test/csf/Digraph_test.cpp b/src/test/csf/Digraph_test.cpp index ac2063e49f2..80319445caf 100644 --- a/src/test/csf/Digraph_test.cpp +++ b/src/test/csf/Digraph_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include #include namespace ripple { diff --git a/src/test/csf/Histogram_test.cpp b/src/test/csf/Histogram_test.cpp index bf392ec8ac1..ea8b864780a 100644 --- a/src/test/csf/Histogram_test.cpp +++ b/src/test/csf/Histogram_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/csf/Peer.h b/src/test/csf/Peer.h index 6d3008f7348..5eed78569f6 100644 --- a/src/test/csf/Peer.h +++ b/src/test/csf/Peer.h @@ -19,13 +19,6 @@ #ifndef RIPPLE_TEST_CSF_PEER_H_INCLUDED #define RIPPLE_TEST_CSF_PEER_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include #include #include #include @@ -33,6 +26,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/csf/PeerGroup.h b/src/test/csf/PeerGroup.h index 1f3421a4adb..b59bfa6763c 100644 --- a/src/test/csf/PeerGroup.h +++ b/src/test/csf/PeerGroup.h @@ -19,9 +19,9 @@ #ifndef RIPPLE_TEST_CSF_PEERGROUP_H_INCLUDED #define RIPPLE_TEST_CSF_PEERGROUP_H_INCLUDED -#include #include #include +#include #include namespace ripple { diff --git a/src/test/csf/Proposal.h b/src/test/csf/Proposal.h index d1cee16c1a7..1d70464bab5 100644 --- a/src/test/csf/Proposal.h +++ b/src/test/csf/Proposal.h @@ -19,10 +19,10 @@ #ifndef RIPPLE_TEST_CSF_PROPOSAL_H_INCLUDED #define RIPPLE_TEST_CSF_PROPOSAL_H_INCLUDED -#include #include #include #include +#include namespace ripple { namespace test { diff --git a/src/test/csf/Scheduler.h b/src/test/csf/Scheduler.h index 2dc24222b26..62dff86402b 100644 --- a/src/test/csf/Scheduler.h +++ b/src/test/csf/Scheduler.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_TEST_CSF_SCHEDULER_H_INCLUDED #define RIPPLE_TEST_CSF_SCHEDULER_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/src/test/csf/Scheduler_test.cpp b/src/test/csf/Scheduler_test.cpp index ac9fab2534b..931150bbeb2 100644 --- a/src/test/csf/Scheduler_test.cpp +++ b/src/test/csf/Scheduler_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include #include diff --git a/src/test/csf/SimTime.h b/src/test/csf/SimTime.h index 2e18a5f9ee5..930338108e1 100644 --- a/src/test/csf/SimTime.h +++ b/src/test/csf/SimTime.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TEST_CSF_SIMTIME_H_INCLUDED #define RIPPLE_TEST_CSF_SIMTIME_H_INCLUDED -#include +#include #include namespace ripple { diff --git a/src/test/csf/TrustGraph.h b/src/test/csf/TrustGraph.h index 31bb8534037..649f210646f 100644 --- a/src/test/csf/TrustGraph.h +++ b/src/test/csf/TrustGraph.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_TEST_CSF_UNL_H_INCLUDED #define RIPPLE_TEST_CSF_UNL_H_INCLUDED -#include #include +#include #include #include diff --git a/src/test/csf/Tx.h b/src/test/csf/Tx.h index 7f3645a59e6..b21481dcbf9 100644 --- a/src/test/csf/Tx.h +++ b/src/test/csf/Tx.h @@ -18,8 +18,8 @@ //============================================================================== #ifndef RIPPLE_TEST_CSF_TX_H_INCLUDED #define RIPPLE_TEST_CSF_TX_H_INCLUDED -#include -#include +#include +#include #include #include #include diff --git a/src/test/csf/Validation.h b/src/test/csf/Validation.h index aacb155fb1f..57c2bc66681 100644 --- a/src/test/csf/Validation.h +++ b/src/test/csf/Validation.h @@ -19,8 +19,8 @@ #ifndef RIPPLE_TEST_CSF_VALIDATION_H_INCLUDED #define RIPPLE_TEST_CSF_VALIDATION_H_INCLUDED -#include #include +#include #include #include diff --git a/src/test/csf/collectors.h b/src/test/csf/collectors.h index 352aa4cb8c2..511fb2c4b0f 100644 --- a/src/test/csf/collectors.h +++ b/src/test/csf/collectors.h @@ -19,10 +19,10 @@ #ifndef RIPPLE_TEST_CSF_COLLECTORS_H_INCLUDED #define RIPPLE_TEST_CSF_COLLECTORS_H_INCLUDED -#include #include #include #include +#include #include #include diff --git a/src/test/csf/events.h b/src/test/csf/events.h index cdda88cd094..37d1b4b0bd7 100644 --- a/src/test/csf/events.h +++ b/src/test/csf/events.h @@ -19,11 +19,11 @@ #ifndef RIPPLE_TEST_CSF_EVENTS_H_INCLUDED #define RIPPLE_TEST_CSF_EVENTS_H_INCLUDED -#include #include #include #include #include +#include namespace ripple { namespace test { diff --git a/src/test/csf/impl/ledgers.cpp b/src/test/csf/impl/ledgers.cpp index ccc767008a7..775ec2e58b1 100644 --- a/src/test/csf/impl/ledgers.cpp +++ b/src/test/csf/impl/ledgers.cpp @@ -16,8 +16,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include #include +#include #include diff --git a/src/test/csf/ledgers.h b/src/test/csf/ledgers.h index 987c5e706c6..1c8d4eb54c6 100644 --- a/src/test/csf/ledgers.h +++ b/src/test/csf/ledgers.h @@ -19,16 +19,16 @@ #ifndef RIPPLE_TEST_CSF_LEDGERS_H_INCLUDED #define RIPPLE_TEST_CSF_LEDGERS_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include #include -#include namespace ripple { namespace test { diff --git a/src/test/csf/timers.h b/src/test/csf/timers.h index b2a2b5a2da5..7e5d88c6696 100644 --- a/src/test/csf/timers.h +++ b/src/test/csf/timers.h @@ -19,10 +19,10 @@ #ifndef RIPPLE_TEST_CSF_TIMERS_H_INCLUDED #define RIPPLE_TEST_CSF_TIMERS_H_INCLUDED -#include -#include #include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/json/Object_test.cpp b/src/test/json/Object_test.cpp index bfdb6427059..4a64d6538a3 100644 --- a/src/test/json/Object_test.cpp +++ b/src/test/json/Object_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace Json { diff --git a/src/test/json/Output_test.cpp b/src/test/json/Output_test.cpp index 670f9c191f0..ddc5f08992b 100644 --- a/src/test/json/Output_test.cpp +++ b/src/test/json/Output_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace Json { diff --git a/src/test/json/TestOutputSuite.h b/src/test/json/TestOutputSuite.h index 0634f42a796..a4f36dac4ee 100644 --- a/src/test/json/TestOutputSuite.h +++ b/src/test/json/TestOutputSuite.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_RPC_TESTOUTPUTSUITE_H_INCLUDED #define RIPPLE_RPC_TESTOUTPUTSUITE_H_INCLUDED -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/json/Writer_test.cpp b/src/test/json/Writer_test.cpp index 99450ffeec5..97d4297c926 100644 --- a/src/test/json/Writer_test.cpp +++ b/src/test/json/Writer_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include #include +#include +#include +#include namespace Json { diff --git a/src/test/json/json_value_test.cpp b/src/test/json/json_value_test.cpp index 543a91a8a06..dacc22cc014 100644 --- a/src/test/json/json_value_test.cpp +++ b/src/test/json/json_value_test.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/test/jtx.h b/src/test/jtx.h index e6651fc1f0d..a3255ef3af9 100644 --- a/src/test/jtx.h +++ b/src/test/jtx.h @@ -22,7 +22,6 @@ // Convenience header that includes everything -#include #include #include #include @@ -66,5 +65,6 @@ #include #include #include +#include #endif diff --git a/src/test/jtx/AMM.h b/src/test/jtx/AMM.h index bb1032e006d..77b9c8c9ec6 100644 --- a/src/test/jtx/AMM.h +++ b/src/test/jtx/AMM.h @@ -20,15 +20,15 @@ #ifndef RIPPLE_TEST_JTX_AMM_H_INCLUDED #define RIPPLE_TEST_JTX_AMM_H_INCLUDED -#include -#include -#include -#include #include #include #include #include #include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/AMMTest.h b/src/test/jtx/AMMTest.h index 5de805a10a7..0481dc98a49 100644 --- a/src/test/jtx/AMMTest.h +++ b/src/test/jtx/AMMTest.h @@ -19,11 +19,11 @@ #ifndef RIPPLE_TEST_JTX_AMMTEST_H_INCLUDED #define RIPPLE_TEST_JTX_AMMTEST_H_INCLUDED -#include -#include #include #include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/AbstractClient.h b/src/test/jtx/AbstractClient.h index 672ce422f0e..b447b9dedb1 100644 --- a/src/test/jtx/AbstractClient.h +++ b/src/test/jtx/AbstractClient.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TEST_ABSTRACTCLIENT_H_INCLUDED #define RIPPLE_TEST_ABSTRACTCLIENT_H_INCLUDED -#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/Account.h b/src/test/jtx/Account.h index cca92e76fe0..bcf117d9357 100644 --- a/src/test/jtx/Account.h +++ b/src/test/jtx/Account.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_TEST_JTX_ACCOUNT_H_INCLUDED #define RIPPLE_TEST_JTX_ACCOUNT_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/test/jtx/CaptureLogs.h b/src/test/jtx/CaptureLogs.h index 9a64396ab7f..62bf25bda90 100644 --- a/src/test/jtx/CaptureLogs.h +++ b/src/test/jtx/CaptureLogs.h @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/CheckMessageLogs.h b/src/test/jtx/CheckMessageLogs.h index 66f5f7e106c..dc3253278cd 100644 --- a/src/test/jtx/CheckMessageLogs.h +++ b/src/test/jtx/CheckMessageLogs.h @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/Env.h b/src/test/jtx/Env.h index 0f21bff9fb6..2c5f2f37062 100644 --- a/src/test/jtx/Env.h +++ b/src/test/jtx/Env.h @@ -20,25 +20,6 @@ #ifndef RIPPLE_TEST_JTX_ENV_H_INCLUDED #define RIPPLE_TEST_JTX_ENV_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include @@ -48,6 +29,25 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/test/jtx/Env_test.cpp b/src/test/jtx/Env_test.cpp index 5c08469e0b8..691f96c2591 100644 --- a/src/test/jtx/Env_test.cpp +++ b/src/test/jtx/Env_test.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/test/jtx/JSONRPCClient.h b/src/test/jtx/JSONRPCClient.h index bfd3154579e..bbffc726694 100644 --- a/src/test/jtx/JSONRPCClient.h +++ b/src/test/jtx/JSONRPCClient.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_TEST_HTTPCLIENT_H_INCLUDED #define RIPPLE_TEST_HTTPCLIENT_H_INCLUDED -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/JTx.h b/src/test/jtx/JTx.h index 2eeb6ccf8f4..a5a4a9eb1b9 100644 --- a/src/test/jtx/JTx.h +++ b/src/test/jtx/JTx.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_TEST_JTX_JTX_H_INCLUDED #define RIPPLE_TEST_JTX_JTX_H_INCLUDED -#include -#include -#include -#include #include #include +#include +#include +#include +#include #include #include diff --git a/src/test/jtx/ManualTimeKeeper.h b/src/test/jtx/ManualTimeKeeper.h index f3adb29b5f0..86477bf99f6 100644 --- a/src/test/jtx/ManualTimeKeeper.h +++ b/src/test/jtx/ManualTimeKeeper.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TEST_MANUALTIMEKEEPER_H_INCLUDED #define RIPPLE_TEST_MANUALTIMEKEEPER_H_INCLUDED -#include +#include #include namespace ripple { diff --git a/src/test/jtx/Oracle.h b/src/test/jtx/Oracle.h index ac46b32d092..32ec0b2e859 100644 --- a/src/test/jtx/Oracle.h +++ b/src/test/jtx/Oracle.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_TEST_JTX_ORACLE_H_INCLUDED #define RIPPLE_TEST_JTX_ORACLE_H_INCLUDED -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/PathSet.h b/src/test/jtx/PathSet.h index f578ceb190d..0f4c4ddd3dd 100644 --- a/src/test/jtx/PathSet.h +++ b/src/test/jtx/PathSet.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_LEDGER_TESTS_PATHSET_H_INCLUDED #define RIPPLE_LEDGER_TESTS_PATHSET_H_INCLUDED -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/TestHelpers.h b/src/test/jtx/TestHelpers.h index b065cec470a..800662aa05b 100644 --- a/src/test/jtx/TestHelpers.h +++ b/src/test/jtx/TestHelpers.h @@ -19,13 +19,13 @@ #ifndef RIPPLE_TEST_JTX_TESTHELPERS_H_INCLUDED #define RIPPLE_TEST_JTX_TESTHELPERS_H_INCLUDED -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include #include diff --git a/src/test/jtx/TestSuite.h b/src/test/jtx/TestSuite.h index 9bd8d50ab57..22b8fb7e53b 100644 --- a/src/test/jtx/TestSuite.h +++ b/src/test/jtx/TestSuite.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_BASICS_TESTSUITE_H_INCLUDED #define RIPPLE_BASICS_TESTSUITE_H_INCLUDED -#include +#include #include namespace ripple { diff --git a/src/test/jtx/TrustedPublisherServer.h b/src/test/jtx/TrustedPublisherServer.h index db57b2d94c6..a10b9999ad2 100644 --- a/src/test/jtx/TrustedPublisherServer.h +++ b/src/test/jtx/TrustedPublisherServer.h @@ -19,12 +19,13 @@ #ifndef RIPPLE_TEST_TRUSTED_PUBLISHER_SERVER_H_INCLUDED #define RIPPLE_TEST_TRUSTED_PUBLISHER_SERVER_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -33,7 +34,6 @@ #include #include #include -#include #include #include diff --git a/src/test/jtx/WSClient.h b/src/test/jtx/WSClient.h index 8961522a038..d0356dbcbf7 100644 --- a/src/test/jtx/WSClient.h +++ b/src/test/jtx/WSClient.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_TEST_WSCLIENT_H_INCLUDED #define RIPPLE_TEST_WSCLIENT_H_INCLUDED -#include #include +#include #include #include diff --git a/src/test/jtx/WSClient_test.cpp b/src/test/jtx/WSClient_test.cpp index 85440003ba4..18dadb0bf9a 100644 --- a/src/test/jtx/WSClient_test.cpp +++ b/src/test/jtx/WSClient_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include #include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/amount.h b/src/test/jtx/amount.h index f8a8f67c75e..c8e0d0c3701 100644 --- a/src/test/jtx/amount.h +++ b/src/test/jtx/amount.h @@ -20,16 +20,16 @@ #ifndef RIPPLE_TEST_JTX_AMOUNT_H_INCLUDED #define RIPPLE_TEST_JTX_AMOUNT_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include #include #include #include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/test/jtx/attester.h b/src/test/jtx/attester.h index 7741991b752..327fb2e4873 100644 --- a/src/test/jtx/attester.h +++ b/src/test/jtx/attester.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_TEST_JTX_ATTESTER_H_INCLUDED #define RIPPLE_TEST_JTX_ATTESTER_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/src/test/jtx/delivermin.h b/src/test/jtx/delivermin.h index 579b66e97ff..46e633dab20 100644 --- a/src/test/jtx/delivermin.h +++ b/src/test/jtx/delivermin.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_TEST_JTX_DELIVERMIN_H_INCLUDED #define RIPPLE_TEST_JTX_DELIVERMIN_H_INCLUDED -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/envconfig.h b/src/test/jtx/envconfig.h index 02c99c52f09..259b61b6caf 100644 --- a/src/test/jtx/envconfig.h +++ b/src/test/jtx/envconfig.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TEST_JTX_ENVCONFIG_H_INCLUDED #define RIPPLE_TEST_JTX_ENVCONFIG_H_INCLUDED -#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/fee.h b/src/test/jtx/fee.h index 58813409edd..c671e0b2a1e 100644 --- a/src/test/jtx/fee.h +++ b/src/test/jtx/fee.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_TEST_JTX_FEE_H_INCLUDED #define RIPPLE_TEST_JTX_FEE_H_INCLUDED -#include -#include #include #include +#include +#include #include diff --git a/src/test/jtx/flags.h b/src/test/jtx/flags.h index 27b6ea95611..c8887cdee4b 100644 --- a/src/test/jtx/flags.h +++ b/src/test/jtx/flags.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_TEST_JTX_FLAGS_H_INCLUDED #define RIPPLE_TEST_JTX_FLAGS_H_INCLUDED -#include -#include -#include #include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/AMM.cpp b/src/test/jtx/impl/AMM.cpp index a36384f4a29..c083b6df35c 100644 --- a/src/test/jtx/impl/AMM.cpp +++ b/src/test/jtx/impl/AMM.cpp @@ -19,12 +19,12 @@ #include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/AMMTest.cpp b/src/test/jtx/impl/AMMTest.cpp index 187cb3cee05..575e2e1d889 100644 --- a/src/test/jtx/impl/AMMTest.cpp +++ b/src/test/jtx/impl/AMMTest.cpp @@ -19,13 +19,13 @@ #include -#include -#include -#include -#include #include #include #include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/Account.cpp b/src/test/jtx/impl/Account.cpp index a17186d4ffb..9d41456ef75 100644 --- a/src/test/jtx/impl/Account.cpp +++ b/src/test/jtx/impl/Account.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include #include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/Env.cpp b/src/test/jtx/impl/Env.cpp index 884caf9162e..6f0f9e3fc73 100644 --- a/src/test/jtx/impl/Env.cpp +++ b/src/test/jtx/impl/Env.cpp @@ -17,27 +17,6 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include @@ -49,6 +28,27 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/JSONRPCClient.cpp b/src/test/jtx/impl/JSONRPCClient.cpp index 1e3664c60ec..20f2149e4a0 100644 --- a/src/test/jtx/impl/JSONRPCClient.cpp +++ b/src/test/jtx/impl/JSONRPCClient.cpp @@ -16,10 +16,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include @@ -27,7 +28,6 @@ #include #include #include -#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/Oracle.cpp b/src/test/jtx/impl/Oracle.cpp index 34249a61228..df9483cbaae 100644 --- a/src/test/jtx/impl/Oracle.cpp +++ b/src/test/jtx/impl/Oracle.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include #include #include diff --git a/src/test/jtx/impl/TestHelpers.cpp b/src/test/jtx/impl/TestHelpers.cpp index 41d9db7c7e5..b8105b1a631 100644 --- a/src/test/jtx/impl/TestHelpers.cpp +++ b/src/test/jtx/impl/TestHelpers.cpp @@ -19,9 +19,9 @@ #include -#include #include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/WSClient.cpp b/src/test/jtx/impl/WSClient.cpp index e9b27168108..185d0ea5dba 100644 --- a/src/test/jtx/impl/WSClient.cpp +++ b/src/test/jtx/impl/WSClient.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include #include #include @@ -32,7 +32,7 @@ #include -#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/acctdelete.cpp b/src/test/jtx/impl/acctdelete.cpp index a62ab6a48bb..d7f8f10e04d 100644 --- a/src/test/jtx/impl/acctdelete.cpp +++ b/src/test/jtx/impl/acctdelete.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/amount.cpp b/src/test/jtx/impl/amount.cpp index 86f51d135d7..01fa5369592 100644 --- a/src/test/jtx/impl/amount.cpp +++ b/src/test/jtx/impl/amount.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include +#include +#include +#include #include #include #include -#include -#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/attester.cpp b/src/test/jtx/impl/attester.cpp index dd00f536af8..66be9da83b3 100644 --- a/src/test/jtx/impl/attester.cpp +++ b/src/test/jtx/impl/attester.cpp @@ -19,11 +19,11 @@ #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/check.cpp b/src/test/jtx/impl/check.cpp index d862130bc70..21af6c9cc3f 100644 --- a/src/test/jtx/impl/check.cpp +++ b/src/test/jtx/impl/check.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/delivermin.cpp b/src/test/jtx/impl/delivermin.cpp index 464c31e0118..6e4838c7c0a 100644 --- a/src/test/jtx/impl/delivermin.cpp +++ b/src/test/jtx/impl/delivermin.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/deposit.cpp b/src/test/jtx/impl/deposit.cpp index 803705c8cb5..09f0cb704b0 100644 --- a/src/test/jtx/impl/deposit.cpp +++ b/src/test/jtx/impl/deposit.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/did.cpp b/src/test/jtx/impl/did.cpp index 94dfcc32754..a9a6e974ef4 100644 --- a/src/test/jtx/impl/did.cpp +++ b/src/test/jtx/impl/did.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/envconfig.cpp b/src/test/jtx/impl/envconfig.cpp index cbca244be6d..c9788a6d70f 100644 --- a/src/test/jtx/impl/envconfig.cpp +++ b/src/test/jtx/impl/envconfig.cpp @@ -19,8 +19,8 @@ #include -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/fee.cpp b/src/test/jtx/impl/fee.cpp index dea666cd3e8..e390136a3c0 100644 --- a/src/test/jtx/impl/fee.cpp +++ b/src/test/jtx/impl/fee.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/flags.cpp b/src/test/jtx/impl/flags.cpp index c80e329fdc8..992e1a88bb2 100644 --- a/src/test/jtx/impl/flags.cpp +++ b/src/test/jtx/impl/flags.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/jtx_json.cpp b/src/test/jtx/impl/jtx_json.cpp index d5fb7bfae91..c9cf6636cf9 100644 --- a/src/test/jtx/impl/jtx_json.cpp +++ b/src/test/jtx/impl/jtx_json.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include #include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/last_ledger_sequence.cpp b/src/test/jtx/impl/last_ledger_sequence.cpp index b0d7bd5c5eb..57742bab2a1 100644 --- a/src/test/jtx/impl/last_ledger_sequence.cpp +++ b/src/test/jtx/impl/last_ledger_sequence.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/memo.cpp b/src/test/jtx/impl/memo.cpp index 174a132eb3d..6469748b4f9 100644 --- a/src/test/jtx/impl/memo.cpp +++ b/src/test/jtx/impl/memo.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/multisign.cpp b/src/test/jtx/impl/multisign.cpp index 1e1f5141798..42c3bfc78bf 100644 --- a/src/test/jtx/impl/multisign.cpp +++ b/src/test/jtx/impl/multisign.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/offer.cpp b/src/test/jtx/impl/offer.cpp index 6e9a1b4f2ff..55a1af4beab 100644 --- a/src/test/jtx/impl/offer.cpp +++ b/src/test/jtx/impl/offer.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/paths.cpp b/src/test/jtx/impl/paths.cpp index 5de9761a110..393e36e9d61 100644 --- a/src/test/jtx/impl/paths.cpp +++ b/src/test/jtx/impl/paths.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/pay.cpp b/src/test/jtx/impl/pay.cpp index 35df2ec191c..2a627223fdd 100644 --- a/src/test/jtx/impl/pay.cpp +++ b/src/test/jtx/impl/pay.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/quality2.cpp b/src/test/jtx/impl/quality2.cpp index e1837035e2d..dd10b3c6117 100644 --- a/src/test/jtx/impl/quality2.cpp +++ b/src/test/jtx/impl/quality2.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/rate.cpp b/src/test/jtx/impl/rate.cpp index cf4cd3211a8..f95170537f3 100644 --- a/src/test/jtx/impl/rate.cpp +++ b/src/test/jtx/impl/rate.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include #include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/regkey.cpp b/src/test/jtx/impl/regkey.cpp index 917fb440624..9fc260d2d03 100644 --- a/src/test/jtx/impl/regkey.cpp +++ b/src/test/jtx/impl/regkey.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/sendmax.cpp b/src/test/jtx/impl/sendmax.cpp index a292e2a98ef..9514b923166 100644 --- a/src/test/jtx/impl/sendmax.cpp +++ b/src/test/jtx/impl/sendmax.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/seq.cpp b/src/test/jtx/impl/seq.cpp index ca57e79227d..3a3de002db6 100644 --- a/src/test/jtx/impl/seq.cpp +++ b/src/test/jtx/impl/seq.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/tag.cpp b/src/test/jtx/impl/tag.cpp index 33ec2c3b89b..be456a1e0e8 100644 --- a/src/test/jtx/impl/tag.cpp +++ b/src/test/jtx/impl/tag.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/ticket.cpp b/src/test/jtx/impl/ticket.cpp index 951c62ab72e..69bcab4d9f1 100644 --- a/src/test/jtx/impl/ticket.cpp +++ b/src/test/jtx/impl/ticket.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/token.cpp b/src/test/jtx/impl/token.cpp index 12b738ca42f..5faf56185b9 100644 --- a/src/test/jtx/impl/token.cpp +++ b/src/test/jtx/impl/token.cpp @@ -20,9 +20,9 @@ #include #include -#include -#include -#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/trust.cpp b/src/test/jtx/impl/trust.cpp index 4ceb10a2365..641a0f79f28 100644 --- a/src/test/jtx/impl/trust.cpp +++ b/src/test/jtx/impl/trust.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include #include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/txflags.cpp b/src/test/jtx/impl/txflags.cpp index 5c78be8bae6..7bc59876a99 100644 --- a/src/test/jtx/impl/txflags.cpp +++ b/src/test/jtx/impl/txflags.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/utility.cpp b/src/test/jtx/impl/utility.cpp index 196fd9258d7..c10fb918540 100644 --- a/src/test/jtx/impl/utility.cpp +++ b/src/test/jtx/impl/utility.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/impl/xchain_bridge.cpp b/src/test/jtx/impl/xchain_bridge.cpp index 0b81ccdcd91..43b0e7c2f96 100644 --- a/src/test/jtx/impl/xchain_bridge.cpp +++ b/src/test/jtx/impl/xchain_bridge.cpp @@ -19,17 +19,17 @@ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/jtx_json.h b/src/test/jtx/jtx_json.h index 59cc09537e2..837d6524766 100644 --- a/src/test/jtx/jtx_json.h +++ b/src/test/jtx/jtx_json.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_TEST_JTX_JSON_H_INCLUDED #define RIPPLE_TEST_JTX_JSON_H_INCLUDED -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/multisign.h b/src/test/jtx/multisign.h index 0617ea2fcbb..3946ea14b26 100644 --- a/src/test/jtx/multisign.h +++ b/src/test/jtx/multisign.h @@ -20,13 +20,13 @@ #ifndef RIPPLE_TEST_JTX_MULTISIGN_H_INCLUDED #define RIPPLE_TEST_JTX_MULTISIGN_H_INCLUDED -#include -#include -#include #include #include #include #include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/offer.h b/src/test/jtx/offer.h index 35a46d19b6b..3951f4f934a 100644 --- a/src/test/jtx/offer.h +++ b/src/test/jtx/offer.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_TEST_JTX_OFFER_H_INCLUDED #define RIPPLE_TEST_JTX_OFFER_H_INCLUDED -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/owners.h b/src/test/jtx/owners.h index 9c802ec91dc..2299af2d7f3 100644 --- a/src/test/jtx/owners.h +++ b/src/test/jtx/owners.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_TEST_JTX_OWNERS_H_INCLUDED #define RIPPLE_TEST_JTX_OWNERS_H_INCLUDED -#include -#include -#include -#include #include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/paths.h b/src/test/jtx/paths.h index 240582825f3..cc9caf3af72 100644 --- a/src/test/jtx/paths.h +++ b/src/test/jtx/paths.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_TEST_JTX_PATHS_H_INCLUDED #define RIPPLE_TEST_JTX_PATHS_H_INCLUDED -#include #include +#include #include namespace ripple { diff --git a/src/test/jtx/pay.h b/src/test/jtx/pay.h index f66075a3e80..6294b5b3082 100644 --- a/src/test/jtx/pay.h +++ b/src/test/jtx/pay.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_TEST_JTX_PAY_H_INCLUDED #define RIPPLE_TEST_JTX_PAY_H_INCLUDED -#include #include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/prop.h b/src/test/jtx/prop.h index 6724ebf8087..8dc5f21917d 100644 --- a/src/test/jtx/prop.h +++ b/src/test/jtx/prop.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_TEST_JTX_PROP_H_INCLUDED #define RIPPLE_TEST_JTX_PROP_H_INCLUDED -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/rate.h b/src/test/jtx/rate.h index 6427b4988e5..0f8186accfc 100644 --- a/src/test/jtx/rate.h +++ b/src/test/jtx/rate.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_TEST_JTX_RATE_H_INCLUDED #define RIPPLE_TEST_JTX_RATE_H_INCLUDED -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/regkey.h b/src/test/jtx/regkey.h index 94869d1d006..7d021e4f277 100644 --- a/src/test/jtx/regkey.h +++ b/src/test/jtx/regkey.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_TEST_JTX_REGKEY_H_INCLUDED #define RIPPLE_TEST_JTX_REGKEY_H_INCLUDED -#include #include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/require.h b/src/test/jtx/require.h index 64b1f36b5fa..271419e51b9 100644 --- a/src/test/jtx/require.h +++ b/src/test/jtx/require.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_TEST_JTX_REQUIRE_H_INCLUDED #define RIPPLE_TEST_JTX_REQUIRE_H_INCLUDED -#include #include +#include #include namespace ripple { diff --git a/src/test/jtx/sendmax.h b/src/test/jtx/sendmax.h index 41e09a4313b..495c61c33b8 100644 --- a/src/test/jtx/sendmax.h +++ b/src/test/jtx/sendmax.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_TEST_JTX_SENDMAX_H_INCLUDED #define RIPPLE_TEST_JTX_SENDMAX_H_INCLUDED -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/token.h b/src/test/jtx/token.h index 957e499cefa..9b4f81b7061 100644 --- a/src/test/jtx/token.h +++ b/src/test/jtx/token.h @@ -24,7 +24,7 @@ #include #include -#include +#include #include diff --git a/src/test/jtx/trust.h b/src/test/jtx/trust.h index 5b6dd78b3cd..f9fddf4871a 100644 --- a/src/test/jtx/trust.h +++ b/src/test/jtx/trust.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_TEST_JTX_TRUST_H_INCLUDED #define RIPPLE_TEST_JTX_TRUST_H_INCLUDED -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/utility.h b/src/test/jtx/utility.h index 42a2180eed2..6d34452cdf8 100644 --- a/src/test/jtx/utility.h +++ b/src/test/jtx/utility.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_TEST_JTX_UTILITY_H_INCLUDED #define RIPPLE_TEST_JTX_UTILITY_H_INCLUDED -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/jtx/xchain_bridge.h b/src/test/jtx/xchain_bridge.h index 8a398bc6f20..9968317c8de 100644 --- a/src/test/jtx/xchain_bridge.h +++ b/src/test/jtx/xchain_bridge.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_TEST_JTX_XCHAINBRIDGE_H_INCLUDED #define RIPPLE_TEST_JTX_XCHAINBRIDGE_H_INCLUDED -#include -#include -#include #include #include #include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/ledger/BookDirs_test.cpp b/src/test/ledger/BookDirs_test.cpp index c7dbea3d6d9..b50f4381f48 100644 --- a/src/test/ledger/BookDirs_test.cpp +++ b/src/test/ledger/BookDirs_test.cpp @@ -15,9 +15,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/ledger/Directory_test.cpp b/src/test/ledger/Directory_test.cpp index 42dcdab9bd1..1a14feff061 100644 --- a/src/test/ledger/Directory_test.cpp +++ b/src/test/ledger/Directory_test.cpp @@ -15,15 +15,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/ledger/Invariants_test.cpp b/src/test/ledger/Invariants_test.cpp index 898376bdaf7..1fd1543f18b 100644 --- a/src/test/ledger/Invariants_test.cpp +++ b/src/test/ledger/Invariants_test.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/ledger/PaymentSandbox_test.cpp b/src/test/ledger/PaymentSandbox_test.cpp index b5ad8c7712c..e3ede19b4b6 100644 --- a/src/test/ledger/PaymentSandbox_test.cpp +++ b/src/test/ledger/PaymentSandbox_test.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/ledger/PendingSaves_test.cpp b/src/test/ledger/PendingSaves_test.cpp index d826d2019fd..1bd42a64a60 100644 --- a/src/test/ledger/PendingSaves_test.cpp +++ b/src/test/ledger/PendingSaves_test.cpp @@ -15,8 +15,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/ledger/SkipList_test.cpp b/src/test/ledger/SkipList_test.cpp index 4fd117a4ca1..3e8987a806a 100644 --- a/src/test/ledger/SkipList_test.cpp +++ b/src/test/ledger/SkipList_test.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include #include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/ledger/View_test.cpp b/src/test/ledger/View_test.cpp index bbb1eec8fa5..29ceb54cc09 100644 --- a/src/test/ledger/View_test.cpp +++ b/src/test/ledger/View_test.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/test/net/DatabaseDownloader_test.cpp b/src/test/net/DatabaseDownloader_test.cpp index 31c8abfd12c..99e98dd3d01 100644 --- a/src/test/net/DatabaseDownloader_test.cpp +++ b/src/test/net/DatabaseDownloader_test.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include #include #include #include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/nodestore/Backend_test.cpp b/src/test/nodestore/Backend_test.cpp index 8c8432bb5b8..dc1fe8c7fe2 100644 --- a/src/test/nodestore/Backend_test.cpp +++ b/src/test/nodestore/Backend_test.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/nodestore/Basics_test.cpp b/src/test/nodestore/Basics_test.cpp index 92f2ae15aaf..aa423e7dc03 100644 --- a/src/test/nodestore/Basics_test.cpp +++ b/src/test/nodestore/Basics_test.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include #include +#include +#include +#include +#include namespace ripple { namespace NodeStore { diff --git a/src/test/nodestore/DatabaseShard_test.cpp b/src/test/nodestore/DatabaseShard_test.cpp index 5c074b14938..e185c43d157 100644 --- a/src/test/nodestore/DatabaseShard_test.cpp +++ b/src/test/nodestore/DatabaseShard_test.cpp @@ -17,24 +17,24 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/test/nodestore/Database_test.cpp b/src/test/nodestore/Database_test.cpp index 0cf2afb21a7..6774857dfc6 100644 --- a/src/test/nodestore/Database_test.cpp +++ b/src/test/nodestore/Database_test.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include #include #include #include #include #include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/nodestore/TestBase.h b/src/test/nodestore/TestBase.h index 9ccf2e1698d..98608c5fb11 100644 --- a/src/test/nodestore/TestBase.h +++ b/src/test/nodestore/TestBase.h @@ -20,14 +20,14 @@ #ifndef RIPPLE_NODESTORE_BASE_H_INCLUDED #define RIPPLE_NODESTORE_BASE_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/test/nodestore/Timing_test.cpp b/src/test/nodestore/Timing_test.cpp index 61cfb0994dc..73789c02449 100644 --- a/src/test/nodestore/Timing_test.cpp +++ b/src/test/nodestore/Timing_test.cpp @@ -17,16 +17,18 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -36,8 +38,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/src/test/nodestore/import_test.cpp b/src/test/nodestore/import_test.cpp index 4a9ee9f0ac3..e13fe9c0c8d 100644 --- a/src/test/nodestore/import_test.cpp +++ b/src/test/nodestore/import_test.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -34,7 +34,7 @@ #include #include -#include +#include /* diff --git a/src/test/nodestore/varint_test.cpp b/src/test/nodestore/varint_test.cpp index a84506b7eac..da7ae9d2858 100644 --- a/src/test/nodestore/varint_test.cpp +++ b/src/test/nodestore/varint_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include diff --git a/src/test/overlay/ProtocolVersion_test.cpp b/src/test/overlay/ProtocolVersion_test.cpp index a5a26fe74ec..dfc0ee70b8e 100644 --- a/src/test/overlay/ProtocolVersion_test.cpp +++ b/src/test/overlay/ProtocolVersion_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { diff --git a/src/test/overlay/cluster_test.cpp b/src/test/overlay/cluster_test.cpp index afbc12a20ee..d22674d28c6 100644 --- a/src/test/overlay/cluster_test.cpp +++ b/src/test/overlay/cluster_test.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include #include #include +#include +#include +#include +#include namespace ripple { namespace tests { diff --git a/src/test/overlay/compression_test.cpp b/src/test/overlay/compression_test.cpp index 81f21258e30..19669efc23f 100644 --- a/src/test/overlay/compression_test.cpp +++ b/src/test/overlay/compression_test.cpp @@ -17,34 +17,34 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/overlay/handshake_test.cpp b/src/test/overlay/handshake_test.cpp index 25bf20add12..93038e522a4 100644 --- a/src/test/overlay/handshake_test.cpp +++ b/src/test/overlay/handshake_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { diff --git a/src/test/overlay/reduce_relay_test.cpp b/src/test/overlay/reduce_relay_test.cpp index 025e3295f2a..4d9086dab10 100644 --- a/src/test/overlay/reduce_relay_test.cpp +++ b/src/test/overlay/reduce_relay_test.cpp @@ -16,15 +16,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/test/overlay/short_read_test.cpp b/src/test/overlay/short_read_test.cpp index 434b4100852..6dd4f8c00b8 100644 --- a/src/test/overlay/short_read_test.cpp +++ b/src/test/overlay/short_read_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include #include +#include +#include +#include #include #include diff --git a/src/test/overlay/tx_reduce_relay_test.cpp b/src/test/overlay/tx_reduce_relay_test.cpp index 7b26ad0962f..074976e8586 100644 --- a/src/test/overlay/tx_reduce_relay_test.cpp +++ b/src/test/overlay/tx_reduce_relay_test.cpp @@ -16,12 +16,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/peerfinder/Livecache_test.cpp b/src/test/peerfinder/Livecache_test.cpp index b6d193f21f5..7fb9f02f42a 100644 --- a/src/test/peerfinder/Livecache_test.cpp +++ b/src/test/peerfinder/Livecache_test.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include namespace ripple { namespace PeerFinder { diff --git a/src/test/peerfinder/PeerFinder_test.cpp b/src/test/peerfinder/PeerFinder_test.cpp index feabe69b647..a1cb8d7408d 100644 --- a/src/test/peerfinder/PeerFinder_test.cpp +++ b/src/test/peerfinder/PeerFinder_test.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace PeerFinder { diff --git a/src/test/protocol/ApiVersion_test.cpp b/src/test/protocol/ApiVersion_test.cpp index 81ff0184e1e..7d634dc569d 100644 --- a/src/test/protocol/ApiVersion_test.cpp +++ b/src/test/protocol/ApiVersion_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/test/protocol/BuildInfo_test.cpp b/src/test/protocol/BuildInfo_test.cpp index 82ad4d67963..2c40681603c 100644 --- a/src/test/protocol/BuildInfo_test.cpp +++ b/src/test/protocol/BuildInfo_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { diff --git a/src/test/protocol/Hooks_test.cpp b/src/test/protocol/Hooks_test.cpp index 1f71abb3af7..fb61d10a739 100644 --- a/src/test/protocol/Hooks_test.cpp +++ b/src/test/protocol/Hooks_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include #include +#include +#include +#include #include namespace ripple { diff --git a/src/test/protocol/InnerObjectFormats_test.cpp b/src/test/protocol/InnerObjectFormats_test.cpp index 009ceef2563..cfc8d123c22 100644 --- a/src/test/protocol/InnerObjectFormats_test.cpp +++ b/src/test/protocol/InnerObjectFormats_test.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include // Json::Reader -#include // RPC::containsError -#include -#include // STParsedJSONObject #include +#include +#include +#include // Json::Reader +#include // RPC::containsError +#include +#include // STParsedJSONObject namespace ripple { diff --git a/src/test/protocol/Issue_test.cpp b/src/test/protocol/Issue_test.cpp index 44eb6e0c0e3..7ec1507e04b 100644 --- a/src/test/protocol/Issue_test.cpp +++ b/src/test/protocol/Issue_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/src/test/protocol/Memo_test.cpp b/src/test/protocol/Memo_test.cpp index e119ee76eec..bd63e7003ad 100644 --- a/src/test/protocol/Memo_test.cpp +++ b/src/test/protocol/Memo_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { diff --git a/src/test/protocol/MultiApiJson_test.cpp b/src/test/protocol/MultiApiJson_test.cpp index a7b0e7e9aec..2c0b410f899 100644 --- a/src/test/protocol/MultiApiJson_test.cpp +++ b/src/test/protocol/MultiApiJson_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include diff --git a/src/test/protocol/PublicKey_test.cpp b/src/test/protocol/PublicKey_test.cpp index 040d752f481..7fa798d1483 100644 --- a/src/test/protocol/PublicKey_test.cpp +++ b/src/test/protocol/PublicKey_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include #include namespace ripple { diff --git a/src/test/protocol/Quality_test.cpp b/src/test/protocol/Quality_test.cpp index a36591b0247..741a341d980 100644 --- a/src/test/protocol/Quality_test.cpp +++ b/src/test/protocol/Quality_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include namespace ripple { diff --git a/src/test/protocol/STAccount_test.cpp b/src/test/protocol/STAccount_test.cpp index f8f79752a5a..034e0e9e087 100644 --- a/src/test/protocol/STAccount_test.cpp +++ b/src/test/protocol/STAccount_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { diff --git a/src/test/protocol/STAmount_test.cpp b/src/test/protocol/STAmount_test.cpp index bd3e96694fd..e48d0500ba6 100644 --- a/src/test/protocol/STAmount_test.cpp +++ b/src/test/protocol/STAmount_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/protocol/STObject_test.cpp b/src/test/protocol/STObject_test.cpp index 34d1cc82fac..39a5b9c2f65 100644 --- a/src/test/protocol/STObject_test.cpp +++ b/src/test/protocol/STObject_test.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/test/protocol/STTx_test.cpp b/src/test/protocol/STTx_test.cpp index f41c283e3ab..e0f6796af33 100644 --- a/src/test/protocol/STTx_test.cpp +++ b/src/test/protocol/STTx_test.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/test/protocol/STValidation_test.cpp b/src/test/protocol/STValidation_test.cpp index 3435db22ca7..8efb5847488 100644 --- a/src/test/protocol/STValidation_test.cpp +++ b/src/test/protocol/STValidation_test.cpp @@ -17,16 +17,16 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/test/protocol/SecretKey_test.cpp b/src/test/protocol/SecretKey_test.cpp index 08a19124508..bce89bce734 100644 --- a/src/test/protocol/SecretKey_test.cpp +++ b/src/test/protocol/SecretKey_test.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/test/protocol/Seed_test.cpp b/src/test/protocol/Seed_test.cpp index 86cf449e1ca..3619e84541e 100644 --- a/src/test/protocol/Seed_test.cpp +++ b/src/test/protocol/Seed_test.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/test/protocol/SeqProxy_test.cpp b/src/test/protocol/SeqProxy_test.cpp index 99a29dfe000..5e44bca5b40 100644 --- a/src/test/protocol/SeqProxy_test.cpp +++ b/src/test/protocol/SeqProxy_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include diff --git a/src/test/protocol/TER_test.cpp b/src/test/protocol/TER_test.cpp index 3cf21db2c0a..a43fd8758ad 100644 --- a/src/test/protocol/TER_test.cpp +++ b/src/test/protocol/TER_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include diff --git a/src/test/protocol/types_test.cpp b/src/test/protocol/types_test.cpp index 2ae7d15ef5c..ac4314df640 100644 --- a/src/test/protocol/types_test.cpp +++ b/src/test/protocol/types_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { diff --git a/src/test/resource/Logic_test.cpp b/src/test/resource/Logic_test.cpp index 25379370f4d..b445890c326 100644 --- a/src/test/resource/Logic_test.cpp +++ b/src/test/resource/Logic_test.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/test/rpc/AMMInfo_test.cpp b/src/test/rpc/AMMInfo_test.cpp index 664a0c04cd5..e4523bb0473 100644 --- a/src/test/rpc/AMMInfo_test.cpp +++ b/src/test/rpc/AMMInfo_test.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include #include #include #include +#include +#include #include diff --git a/src/test/rpc/AccountCurrencies_test.cpp b/src/test/rpc/AccountCurrencies_test.cpp index c3e46a3e66c..472dc02c438 100644 --- a/src/test/rpc/AccountCurrencies_test.cpp +++ b/src/test/rpc/AccountCurrencies_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { diff --git a/src/test/rpc/AccountInfo_test.cpp b/src/test/rpc/AccountInfo_test.cpp index ff23a5e53c1..8c69dce13d1 100644 --- a/src/test/rpc/AccountInfo_test.cpp +++ b/src/test/rpc/AccountInfo_test.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include #include +#include +#include -#include -#include -#include #include #include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/rpc/AccountLinesRPC_test.cpp b/src/test/rpc/AccountLinesRPC_test.cpp index 04688156d12..3c25dbe7810 100644 --- a/src/test/rpc/AccountLinesRPC_test.cpp +++ b/src/test/rpc/AccountLinesRPC_test.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include #include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/rpc/AccountObjects_test.cpp b/src/test/rpc/AccountObjects_test.cpp index 17217f2c880..18291bf2b95 100644 --- a/src/test/rpc/AccountObjects_test.cpp +++ b/src/test/rpc/AccountObjects_test.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include #include #include #include +#include +#include +#include +#include #include diff --git a/src/test/rpc/AccountOffers_test.cpp b/src/test/rpc/AccountOffers_test.cpp index d94442ea8e5..d53fb9ecb0b 100644 --- a/src/test/rpc/AccountOffers_test.cpp +++ b/src/test/rpc/AccountOffers_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/rpc/AccountSet_test.cpp b/src/test/rpc/AccountSet_test.cpp index 3fa214c5b4e..e5475e3f530 100644 --- a/src/test/rpc/AccountSet_test.cpp +++ b/src/test/rpc/AccountSet_test.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/rpc/AccountTx_test.cpp b/src/test/rpc/AccountTx_test.cpp index 6601996925e..54ca3f1f418 100644 --- a/src/test/rpc/AccountTx_test.cpp +++ b/src/test/rpc/AccountTx_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include #include +#include +#include +#include #include diff --git a/src/test/rpc/AmendmentBlocked_test.cpp b/src/test/rpc/AmendmentBlocked_test.cpp index a90bcdcd0c4..196ce0e463d 100644 --- a/src/test/rpc/AmendmentBlocked_test.cpp +++ b/src/test/rpc/AmendmentBlocked_test.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include #include #include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/rpc/Book_test.cpp b/src/test/rpc/Book_test.cpp index fcc0017f539..6bcc0c20809 100644 --- a/src/test/rpc/Book_test.cpp +++ b/src/test/rpc/Book_test.cpp @@ -15,12 +15,12 @@ */ //============================================================================== -#include -#include -#include -#include #include #include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/rpc/DeliveredAmount_test.cpp b/src/test/rpc/DeliveredAmount_test.cpp index c17bd0c025d..9ed858e2a33 100644 --- a/src/test/rpc/DeliveredAmount_test.cpp +++ b/src/test/rpc/DeliveredAmount_test.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include #include #include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/rpc/DepositAuthorized_test.cpp b/src/test/rpc/DepositAuthorized_test.cpp index 128d91f739d..ebabe1fbe3f 100644 --- a/src/test/rpc/DepositAuthorized_test.cpp +++ b/src/test/rpc/DepositAuthorized_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { namespace test { diff --git a/src/test/rpc/Feature_test.cpp b/src/test/rpc/Feature_test.cpp index 010a61fbfcc..488255542f2 100644 --- a/src/test/rpc/Feature_test.cpp +++ b/src/test/rpc/Feature_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include #include +#include +#include +#include namespace ripple { diff --git a/src/test/rpc/GRPCTestClientBase.h b/src/test/rpc/GRPCTestClientBase.h index a5c613f55e2..f8b74ed6d5c 100644 --- a/src/test/rpc/GRPCTestClientBase.h +++ b/src/test/rpc/GRPCTestClientBase.h @@ -20,9 +20,9 @@ #ifndef RIPPLED_GRPCTESTCLIENTBASE_H #define RIPPLED_GRPCTESTCLIENTBASE_H -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/rpc/GatewayBalances_test.cpp b/src/test/rpc/GatewayBalances_test.cpp index 4c6ec9aaf1b..4e847c8dbdd 100644 --- a/src/test/rpc/GatewayBalances_test.cpp +++ b/src/test/rpc/GatewayBalances_test.cpp @@ -15,12 +15,12 @@ */ //============================================================================== -#include -#include -#include -#include #include #include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/rpc/GetAggregatePrice_test.cpp b/src/test/rpc/GetAggregatePrice_test.cpp index 1fb263bbc55..aad3c9be99f 100644 --- a/src/test/rpc/GetAggregatePrice_test.cpp +++ b/src/test/rpc/GetAggregatePrice_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include #include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/rpc/GetCounts_test.cpp b/src/test/rpc/GetCounts_test.cpp index 52b645ed717..132ed93d7be 100644 --- a/src/test/rpc/GetCounts_test.cpp +++ b/src/test/rpc/GetCounts_test.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include #include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/rpc/Handler_test.cpp b/src/test/rpc/Handler_test.cpp index 5160a68aac2..2c3bfd30d4c 100644 --- a/src/test/rpc/Handler_test.cpp +++ b/src/test/rpc/Handler_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include #include #include diff --git a/src/test/rpc/JSONRPC_test.cpp b/src/test/rpc/JSONRPC_test.cpp index 8fd453ee9f6..b2b9e7a55b8 100644 --- a/src/test/rpc/JSONRPC_test.cpp +++ b/src/test/rpc/JSONRPC_test.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/rpc/KeyGeneration_test.cpp b/src/test/rpc/KeyGeneration_test.cpp index 28f9afd3b7f..e136bb04beb 100644 --- a/src/test/rpc/KeyGeneration_test.cpp +++ b/src/test/rpc/KeyGeneration_test.cpp @@ -16,13 +16,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/rpc/LedgerClosed_test.cpp b/src/test/rpc/LedgerClosed_test.cpp index 2f81031f85c..c3f7f900e3c 100644 --- a/src/test/rpc/LedgerClosed_test.cpp +++ b/src/test/rpc/LedgerClosed_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { diff --git a/src/test/rpc/LedgerData_test.cpp b/src/test/rpc/LedgerData_test.cpp index f0811ba34c4..34dfb3e011b 100644 --- a/src/test/rpc/LedgerData_test.cpp +++ b/src/test/rpc/LedgerData_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { diff --git a/src/test/rpc/LedgerHeader_test.cpp b/src/test/rpc/LedgerHeader_test.cpp index d6c0652d5a2..d8fe738b888 100644 --- a/src/test/rpc/LedgerHeader_test.cpp +++ b/src/test/rpc/LedgerHeader_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include #include #include +#include namespace ripple { diff --git a/src/test/rpc/LedgerRPC_test.cpp b/src/test/rpc/LedgerRPC_test.cpp index 79f244c4711..70e4ffbe8dc 100644 --- a/src/test/rpc/LedgerRPC_test.cpp +++ b/src/test/rpc/LedgerRPC_test.cpp @@ -17,19 +17,19 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/rpc/LedgerRequestRPC_test.cpp b/src/test/rpc/LedgerRequestRPC_test.cpp index 6c59e72c4b8..8922cd38386 100644 --- a/src/test/rpc/LedgerRequestRPC_test.cpp +++ b/src/test/rpc/LedgerRequestRPC_test.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include #include diff --git a/src/test/rpc/ManifestRPC_test.cpp b/src/test/rpc/ManifestRPC_test.cpp index 3c32f4d7ba7..fcf47a5745d 100644 --- a/src/test/rpc/ManifestRPC_test.cpp +++ b/src/test/rpc/ManifestRPC_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include #include +#include +#include +#include #include diff --git a/src/test/rpc/NoRippleCheck_test.cpp b/src/test/rpc/NoRippleCheck_test.cpp index 3d34f55c90d..58f10c66dc1 100644 --- a/src/test/rpc/NoRippleCheck_test.cpp +++ b/src/test/rpc/NoRippleCheck_test.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/rpc/NoRipple_test.cpp b/src/test/rpc/NoRipple_test.cpp index 8da80e6483c..aa5e6e1efef 100644 --- a/src/test/rpc/NoRipple_test.cpp +++ b/src/test/rpc/NoRipple_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include #include +#include +#include +#include namespace ripple { diff --git a/src/test/rpc/NodeToShardRPC_test.cpp b/src/test/rpc/NodeToShardRPC_test.cpp index 7736d776995..ec1ff367c1e 100644 --- a/src/test/rpc/NodeToShardRPC_test.cpp +++ b/src/test/rpc/NodeToShardRPC_test.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/rpc/OwnerInfo_test.cpp b/src/test/rpc/OwnerInfo_test.cpp index c510c35afc8..606f2274b88 100644 --- a/src/test/rpc/OwnerInfo_test.cpp +++ b/src/test/rpc/OwnerInfo_test.cpp @@ -18,10 +18,10 @@ //============================================================================== #include -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/test/rpc/Peers_test.cpp b/src/test/rpc/Peers_test.cpp index 43fa601e1c0..ab9b17b2593 100644 --- a/src/test/rpc/Peers_test.cpp +++ b/src/test/rpc/Peers_test.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include #include #include +#include +#include +#include #include namespace ripple { diff --git a/src/test/rpc/RPCCall_test.cpp b/src/test/rpc/RPCCall_test.cpp index 09096ba76af..f3aaf468a9e 100644 --- a/src/test/rpc/RPCCall_test.cpp +++ b/src/test/rpc/RPCCall_test.cpp @@ -15,13 +15,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include #include diff --git a/src/test/rpc/RPCOverload_test.cpp b/src/test/rpc/RPCOverload_test.cpp index 088a8179043..c3328fb0b28 100644 --- a/src/test/rpc/RPCOverload_test.cpp +++ b/src/test/rpc/RPCOverload_test.cpp @@ -15,12 +15,12 @@ */ //============================================================================== -#include -#include -#include #include #include #include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/rpc/ReportingETL_test.cpp b/src/test/rpc/ReportingETL_test.cpp index 078a51d7bcd..8a030938832 100644 --- a/src/test/rpc/ReportingETL_test.cpp +++ b/src/test/rpc/ReportingETL_test.cpp @@ -18,15 +18,15 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include -#include #include #include #include #include +#include namespace ripple { namespace test { diff --git a/src/test/rpc/RobustTransaction_test.cpp b/src/test/rpc/RobustTransaction_test.cpp index 37b16c58d7f..b0506224f79 100644 --- a/src/test/rpc/RobustTransaction_test.cpp +++ b/src/test/rpc/RobustTransaction_test.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include #include #include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/rpc/Roles_test.cpp b/src/test/rpc/Roles_test.cpp index 079fd2f9f26..8cef5dcbc61 100644 --- a/src/test/rpc/Roles_test.cpp +++ b/src/test/rpc/Roles_test.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include #include #include +#include +#include +#include #include diff --git a/src/test/rpc/ServerInfo_test.cpp b/src/test/rpc/ServerInfo_test.cpp index ece98e99a7e..a2eaa63eb42 100644 --- a/src/test/rpc/ServerInfo_test.cpp +++ b/src/test/rpc/ServerInfo_test.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include #include +#include +#include +#include +#include #include diff --git a/src/test/rpc/ShardArchiveHandler_test.cpp b/src/test/rpc/ShardArchiveHandler_test.cpp index ee0bec1eadf..82f12fe49a9 100644 --- a/src/test/rpc/ShardArchiveHandler_test.cpp +++ b/src/test/rpc/ShardArchiveHandler_test.cpp @@ -17,19 +17,19 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/rpc/Status_test.cpp b/src/test/rpc/Status_test.cpp index ab94191e1de..1ae8b23c66c 100644 --- a/src/test/rpc/Status_test.cpp +++ b/src/test/rpc/Status_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include #include namespace ripple { diff --git a/src/test/rpc/Subscribe_test.cpp b/src/test/rpc/Subscribe_test.cpp index 24ceb54bb94..f1cb2f9a135 100644 --- a/src/test/rpc/Subscribe_test.cpp +++ b/src/test/rpc/Subscribe_test.cpp @@ -15,17 +15,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/test/rpc/TransactionEntry_test.cpp b/src/test/rpc/TransactionEntry_test.cpp index 431c812d625..09423ed25d5 100644 --- a/src/test/rpc/TransactionEntry_test.cpp +++ b/src/test/rpc/TransactionEntry_test.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include #include #include +#include +#include +#include +#include #include diff --git a/src/test/rpc/TransactionHistory_test.cpp b/src/test/rpc/TransactionHistory_test.cpp index 862eaaee507..63151bdaeb6 100644 --- a/src/test/rpc/TransactionHistory_test.cpp +++ b/src/test/rpc/TransactionHistory_test.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include #include #include #include +#include +#include +#include namespace ripple { diff --git a/src/test/rpc/Transaction_test.cpp b/src/test/rpc/Transaction_test.cpp index ac02dd11cda..72a7681ce97 100644 --- a/src/test/rpc/Transaction_test.cpp +++ b/src/test/rpc/Transaction_test.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include #include #include #include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/test/rpc/ValidatorInfo_test.cpp b/src/test/rpc/ValidatorInfo_test.cpp index f45d6867596..603a0ad9d23 100644 --- a/src/test/rpc/ValidatorInfo_test.cpp +++ b/src/test/rpc/ValidatorInfo_test.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include #include +#include +#include +#include #include #include diff --git a/src/test/rpc/ValidatorRPC_test.cpp b/src/test/rpc/ValidatorRPC_test.cpp index c9b11cdb992..2bd4b69c37b 100644 --- a/src/test/rpc/ValidatorRPC_test.cpp +++ b/src/test/rpc/ValidatorRPC_test.cpp @@ -17,16 +17,16 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/test/rpc/Version_test.cpp b/src/test/rpc/Version_test.cpp index 34e55b2be93..b66e502b9f3 100644 --- a/src/test/rpc/Version_test.cpp +++ b/src/test/rpc/Version_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include #include +#include +#include namespace ripple { diff --git a/src/test/server/ServerStatus_test.cpp b/src/test/server/ServerStatus_test.cpp index 249b0fd4512..8aa7bf19f30 100644 --- a/src/test/server/ServerStatus_test.cpp +++ b/src/test/server/ServerStatus_test.cpp @@ -17,13 +17,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -33,10 +37,6 @@ #include #include #include -#include -#include -#include -#include namespace ripple { namespace test { diff --git a/src/test/server/Server_test.cpp b/src/test/server/Server_test.cpp index b5eb71f361c..c7d7dc3b911 100644 --- a/src/test/server/Server_test.cpp +++ b/src/test/server/Server_test.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/test/shamap/FetchPack_test.cpp b/src/test/shamap/FetchPack_test.cpp index f15f3163e55..ac2d16ecc99 100644 --- a/src/test/shamap/FetchPack_test.cpp +++ b/src/test/shamap/FetchPack_test.cpp @@ -17,19 +17,19 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace tests { diff --git a/src/test/shamap/SHAMapSync_test.cpp b/src/test/shamap/SHAMapSync_test.cpp index 70e578b5fb5..627e97e152c 100644 --- a/src/test/shamap/SHAMapSync_test.cpp +++ b/src/test/shamap/SHAMapSync_test.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include namespace ripple { namespace tests { diff --git a/src/test/shamap/SHAMap_test.cpp b/src/test/shamap/SHAMap_test.cpp index 83bbc13253e..c8c877935f5 100644 --- a/src/test/shamap/SHAMap_test.cpp +++ b/src/test/shamap/SHAMap_test.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include namespace ripple { namespace tests { diff --git a/src/test/shamap/common.h b/src/test/shamap/common.h index d89acb988d7..2280c77d4a1 100644 --- a/src/test/shamap/common.h +++ b/src/test/shamap/common.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_SHAMAP_TESTS_COMMON_H_INCLUDED #define RIPPLE_SHAMAP_TESTS_COMMON_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { namespace tests { diff --git a/src/test/unit_test/FileDirGuard.h b/src/test/unit_test/FileDirGuard.h index 3c79fb11b8e..246ac262378 100644 --- a/src/test/unit_test/FileDirGuard.h +++ b/src/test/unit_test/FileDirGuard.h @@ -20,9 +20,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef TEST_UNIT_TEST_DIRGUARD_H #define TEST_UNIT_TEST_DIRGUARD_H -#include -#include #include +#include +#include namespace ripple { namespace test { diff --git a/src/test/unit_test/SuiteJournal.h b/src/test/unit_test/SuiteJournal.h index 0e80e83cd7e..211bec0e4d3 100644 --- a/src/test/unit_test/SuiteJournal.h +++ b/src/test/unit_test/SuiteJournal.h @@ -20,8 +20,8 @@ #ifndef TEST_UNIT_TEST_SUITE_JOURNAL_H #define TEST_UNIT_TEST_SUITE_JOURNAL_H -#include -#include +#include +#include namespace ripple { namespace test { diff --git a/src/test/unit_test/multi_runner.cpp b/src/test/unit_test/multi_runner.cpp index cd84c3c999f..60487cadfb8 100644 --- a/src/test/unit_test/multi_runner.cpp +++ b/src/test/unit_test/multi_runner.cpp @@ -19,7 +19,7 @@ #include -#include +#include #include diff --git a/src/test/unit_test/multi_runner.h b/src/test/unit_test/multi_runner.h index c003a99f998..a4435dd1af7 100644 --- a/src/test/unit_test/multi_runner.h +++ b/src/test/unit_test/multi_runner.h @@ -20,8 +20,8 @@ #ifndef TEST_UNIT_TEST_MULTI_RUNNER_H #define TEST_UNIT_TEST_MULTI_RUNNER_H -#include -#include +#include +#include #include #include diff --git a/src/xrpld/app/consensus/RCLCensorshipDetector.h b/src/xrpld/app/consensus/RCLCensorshipDetector.h index f661a80362b..12a768ca4c8 100644 --- a/src/xrpld/app/consensus/RCLCensorshipDetector.h +++ b/src/xrpld/app/consensus/RCLCensorshipDetector.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_APP_CONSENSUS_RCLCENSORSHIPDETECTOR_H_INCLUDED #define RIPPLE_APP_CONSENSUS_RCLCENSORSHIPDETECTOR_H_INCLUDED -#include -#include +#include +#include #include #include #include diff --git a/src/xrpld/app/consensus/RCLConsensus.cpp b/src/xrpld/app/consensus/RCLConsensus.cpp index c0ebe06dd7e..7b061e10b31 100644 --- a/src/xrpld/app/consensus/RCLConsensus.cpp +++ b/src/xrpld/app/consensus/RCLConsensus.cpp @@ -17,32 +17,32 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/consensus/RCLConsensus.h b/src/xrpld/app/consensus/RCLConsensus.h index f8c01e93caa..893e5cf0847 100644 --- a/src/xrpld/app/consensus/RCLConsensus.h +++ b/src/xrpld/app/consensus/RCLConsensus.h @@ -20,21 +20,21 @@ #ifndef RIPPLE_APP_CONSENSUS_RCLCONSENSUS_H_INCLUDED #define RIPPLE_APP_CONSENSUS_RCLCONSENSUS_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/consensus/RCLCxLedger.h b/src/xrpld/app/consensus/RCLCxLedger.h index b30bef135c0..ed7ad9faeb7 100644 --- a/src/xrpld/app/consensus/RCLCxLedger.h +++ b/src/xrpld/app/consensus/RCLCxLedger.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_APP_CONSENSUS_RCLCXLEDGER_H_INCLUDED #define RIPPLE_APP_CONSENSUS_RCLCXLEDGER_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/consensus/RCLCxPeerPos.cpp b/src/xrpld/app/consensus/RCLCxPeerPos.cpp index ee5a45b943f..74747853a2d 100644 --- a/src/xrpld/app/consensus/RCLCxPeerPos.cpp +++ b/src/xrpld/app/consensus/RCLCxPeerPos.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/consensus/RCLCxPeerPos.h b/src/xrpld/app/consensus/RCLCxPeerPos.h index e82a85d422b..4236e2ab128 100644 --- a/src/xrpld/app/consensus/RCLCxPeerPos.h +++ b/src/xrpld/app/consensus/RCLCxPeerPos.h @@ -20,14 +20,14 @@ #ifndef RIPPLE_APP_CONSENSUS_RCLCXPEERPOS_H_INCLUDED #define RIPPLE_APP_CONSENSUS_RCLCXPEERPOS_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/consensus/RCLCxTx.h b/src/xrpld/app/consensus/RCLCxTx.h index c6abfdfee94..58e58ac3b7d 100644 --- a/src/xrpld/app/consensus/RCLCxTx.h +++ b/src/xrpld/app/consensus/RCLCxTx.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_APP_CONSENSUS_RCLCXTX_H_INCLUDED #define RIPPLE_APP_CONSENSUS_RCLCXTX_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/consensus/RCLValidations.cpp b/src/xrpld/app/consensus/RCLValidations.cpp index ab9391385dd..88e8d6c4e71 100644 --- a/src/xrpld/app/consensus/RCLValidations.cpp +++ b/src/xrpld/app/consensus/RCLValidations.cpp @@ -17,19 +17,19 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/consensus/RCLValidations.h b/src/xrpld/app/consensus/RCLValidations.h index 93628fe1695..c0d08280fed 100644 --- a/src/xrpld/app/consensus/RCLValidations.h +++ b/src/xrpld/app/consensus/RCLValidations.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_APP_CONSENSUSS_VALIDATIONS_H_INCLUDED #define RIPPLE_APP_CONSENSUSS_VALIDATIONS_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/ledger/AbstractFetchPackContainer.h b/src/xrpld/app/ledger/AbstractFetchPackContainer.h index 43552a757b5..2b27471c64a 100644 --- a/src/xrpld/app/ledger/AbstractFetchPackContainer.h +++ b/src/xrpld/app/ledger/AbstractFetchPackContainer.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_APP_LEDGER_ABSTRACTFETCHPACKCONTAINER_H_INCLUDED #define RIPPLE_APP_LEDGER_ABSTRACTFETCHPACKCONTAINER_H_INCLUDED -#include -#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/ledger/AcceptedLedger.cpp b/src/xrpld/app/ledger/AcceptedLedger.cpp index 4f308653dcf..37c943679da 100644 --- a/src/xrpld/app/ledger/AcceptedLedger.cpp +++ b/src/xrpld/app/ledger/AcceptedLedger.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/ledger/AcceptedLedger.h b/src/xrpld/app/ledger/AcceptedLedger.h index 0187fdfb679..65a782aef70 100644 --- a/src/xrpld/app/ledger/AcceptedLedger.h +++ b/src/xrpld/app/ledger/AcceptedLedger.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_APP_LEDGER_ACCEPTEDLEDGER_H_INCLUDED #define RIPPLE_APP_LEDGER_ACCEPTEDLEDGER_H_INCLUDED -#include -#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/AcceptedLedgerTx.cpp b/src/xrpld/app/ledger/AcceptedLedgerTx.cpp index 613a91e437a..e1ad68dff37 100644 --- a/src/xrpld/app/ledger/AcceptedLedgerTx.cpp +++ b/src/xrpld/app/ledger/AcceptedLedgerTx.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/AcceptedLedgerTx.h b/src/xrpld/app/ledger/AcceptedLedgerTx.h index 2995d447bba..725057aa02c 100644 --- a/src/xrpld/app/ledger/AcceptedLedgerTx.h +++ b/src/xrpld/app/ledger/AcceptedLedgerTx.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_APP_LEDGER_ACCEPTEDLEDGERTX_H_INCLUDED #define RIPPLE_APP_LEDGER_ACCEPTEDLEDGERTX_H_INCLUDED -#include -#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/ledger/AccountStateSF.cpp b/src/xrpld/app/ledger/AccountStateSF.cpp index 5c66469d5ab..c1f2ca26fc5 100644 --- a/src/xrpld/app/ledger/AccountStateSF.cpp +++ b/src/xrpld/app/ledger/AccountStateSF.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/AccountStateSF.h b/src/xrpld/app/ledger/AccountStateSF.h index 43822add593..16cc686e3de 100644 --- a/src/xrpld/app/ledger/AccountStateSF.h +++ b/src/xrpld/app/ledger/AccountStateSF.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_APP_LEDGER_ACCOUNTSTATESF_H_INCLUDED #define RIPPLE_APP_LEDGER_ACCOUNTSTATESF_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/BookListeners.cpp b/src/xrpld/app/ledger/BookListeners.cpp index 3c7e013e1dd..2379807a91a 100644 --- a/src/xrpld/app/ledger/BookListeners.cpp +++ b/src/xrpld/app/ledger/BookListeners.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/BookListeners.h b/src/xrpld/app/ledger/BookListeners.h index 605cf6dc6af..6ac52de28ee 100644 --- a/src/xrpld/app/ledger/BookListeners.h +++ b/src/xrpld/app/ledger/BookListeners.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_APP_LEDGER_BOOKLISTENERS_H_INCLUDED #define RIPPLE_APP_LEDGER_BOOKLISTENERS_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/src/xrpld/app/ledger/BuildLedger.h b/src/xrpld/app/ledger/BuildLedger.h index acefee24e70..409fa3529c4 100644 --- a/src/xrpld/app/ledger/BuildLedger.h +++ b/src/xrpld/app/ledger/BuildLedger.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_APP_LEDGER_BUILD_LEDGER_H_INCLUDED #define RIPPLE_APP_LEDGER_BUILD_LEDGER_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/ledger/ConsensusTransSetSF.cpp b/src/xrpld/app/ledger/ConsensusTransSetSF.cpp index 476c757515f..4aed7d94bf3 100644 --- a/src/xrpld/app/ledger/ConsensusTransSetSF.cpp +++ b/src/xrpld/app/ledger/ConsensusTransSetSF.cpp @@ -17,16 +17,16 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/ConsensusTransSetSF.h b/src/xrpld/app/ledger/ConsensusTransSetSF.h index ad5b2a23a48..857f2b8eae2 100644 --- a/src/xrpld/app/ledger/ConsensusTransSetSF.h +++ b/src/xrpld/app/ledger/ConsensusTransSetSF.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_APP_LEDGER_CONSENSUSTRANSSETSF_H_INCLUDED #define RIPPLE_APP_LEDGER_CONSENSUSTRANSSETSF_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/InboundLedger.h b/src/xrpld/app/ledger/InboundLedger.h index 357a6fcad1e..62b6925d59c 100644 --- a/src/xrpld/app/ledger/InboundLedger.h +++ b/src/xrpld/app/ledger/InboundLedger.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_APP_LEDGER_INBOUNDLEDGER_H_INCLUDED #define RIPPLE_APP_LEDGER_INBOUNDLEDGER_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/ledger/InboundLedgers.h b/src/xrpld/app/ledger/InboundLedgers.h index b12760153e2..8d3deb9c2df 100644 --- a/src/xrpld/app/ledger/InboundLedgers.h +++ b/src/xrpld/app/ledger/InboundLedgers.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_APP_LEDGER_INBOUNDLEDGERS_H_INCLUDED #define RIPPLE_APP_LEDGER_INBOUNDLEDGERS_H_INCLUDED -#include -#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/ledger/InboundTransactions.h b/src/xrpld/app/ledger/InboundTransactions.h index f5b44f38616..368375c07c5 100644 --- a/src/xrpld/app/ledger/InboundTransactions.h +++ b/src/xrpld/app/ledger/InboundTransactions.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_APP_LEDGER_INBOUNDTRANSACTIONS_H_INCLUDED #define RIPPLE_APP_LEDGER_INBOUNDTRANSACTIONS_H_INCLUDED -#include -#include -#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/ledger/Ledger.cpp b/src/xrpld/app/ledger/Ledger.cpp index 7cd6f89cad3..afed8f4870b 100644 --- a/src/xrpld/app/ledger/Ledger.cpp +++ b/src/xrpld/app/ledger/Ledger.cpp @@ -17,45 +17,45 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include -#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/Ledger.h b/src/xrpld/app/ledger/Ledger.h index 051b322e27a..1591fae1472 100644 --- a/src/xrpld/app/ledger/Ledger.h +++ b/src/xrpld/app/ledger/Ledger.h @@ -20,17 +20,17 @@ #ifndef RIPPLE_APP_LEDGER_LEDGER_H_INCLUDED #define RIPPLE_APP_LEDGER_LEDGER_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/ledger/LedgerCleaner.h b/src/xrpld/app/ledger/LedgerCleaner.h index 9f82a851f21..251e8d51281 100644 --- a/src/xrpld/app/ledger/LedgerCleaner.h +++ b/src/xrpld/app/ledger/LedgerCleaner.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_APP_LEDGER_LEDGERCLEANER_H_INCLUDED #define RIPPLE_APP_LEDGER_LEDGERCLEANER_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/ledger/LedgerHistory.cpp b/src/xrpld/app/ledger/LedgerHistory.cpp index ed2ccd07434..30139e2155f 100644 --- a/src/xrpld/app/ledger/LedgerHistory.cpp +++ b/src/xrpld/app/ledger/LedgerHistory.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/LedgerHistory.h b/src/xrpld/app/ledger/LedgerHistory.h index 092ad7d8371..9d414e4aad3 100644 --- a/src/xrpld/app/ledger/LedgerHistory.h +++ b/src/xrpld/app/ledger/LedgerHistory.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_APP_LEDGER_LEDGERHISTORY_H_INCLUDED #define RIPPLE_APP_LEDGER_LEDGERHISTORY_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/ledger/LedgerHolder.h b/src/xrpld/app/ledger/LedgerHolder.h index 93d67400e05..5636a8ca20d 100644 --- a/src/xrpld/app/ledger/LedgerHolder.h +++ b/src/xrpld/app/ledger/LedgerHolder.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_APP_LEDGER_LEDGERHOLDER_H_INCLUDED #define RIPPLE_APP_LEDGER_LEDGERHOLDER_H_INCLUDED -#include -#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/ledger/LedgerMaster.h b/src/xrpld/app/ledger/LedgerMaster.h index 980506c2267..7921773e3f0 100644 --- a/src/xrpld/app/ledger/LedgerMaster.h +++ b/src/xrpld/app/ledger/LedgerMaster.h @@ -20,23 +20,23 @@ #ifndef RIPPLE_APP_LEDGER_LEDGERMASTER_H_INCLUDED #define RIPPLE_APP_LEDGER_LEDGERMASTER_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/ledger/LedgerReplay.h b/src/xrpld/app/ledger/LedgerReplay.h index 0365dea1b7e..8e52c8d5d5d 100644 --- a/src/xrpld/app/ledger/LedgerReplay.h +++ b/src/xrpld/app/ledger/LedgerReplay.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_APP_LEDGER_LEDGERREPLAY_H_INCLUDED #define RIPPLE_APP_LEDGER_LEDGERREPLAY_H_INCLUDED -#include +#include #include #include #include diff --git a/src/xrpld/app/ledger/LedgerReplayTask.h b/src/xrpld/app/ledger/LedgerReplayTask.h index 4330f0b6247..54863e70956 100644 --- a/src/xrpld/app/ledger/LedgerReplayTask.h +++ b/src/xrpld/app/ledger/LedgerReplayTask.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_APP_LEDGER_LEDGERREPLAYTASK_H_INCLUDED #define RIPPLE_APP_LEDGER_LEDGERREPLAYTASK_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/ledger/LedgerReplayer.h b/src/xrpld/app/ledger/LedgerReplayer.h index b06dd2cc858..4ce4b20b221 100644 --- a/src/xrpld/app/ledger/LedgerReplayer.h +++ b/src/xrpld/app/ledger/LedgerReplayer.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_APP_LEDGER_LEDGERREPLAYER_H_INCLUDED #define RIPPLE_APP_LEDGER_LEDGERREPLAYER_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/ledger/LedgerToJson.h b/src/xrpld/app/ledger/LedgerToJson.h index 78947ca91d1..8f9316cbc66 100644 --- a/src/xrpld/app/ledger/LedgerToJson.h +++ b/src/xrpld/app/ledger/LedgerToJson.h @@ -20,16 +20,16 @@ #ifndef RIPPLE_APP_LEDGER_LEDGERTOJSON_H_INCLUDED #define RIPPLE_APP_LEDGER_LEDGERTOJSON_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/LocalTxs.h b/src/xrpld/app/ledger/LocalTxs.h index f427a5e0477..638e070f444 100644 --- a/src/xrpld/app/ledger/LocalTxs.h +++ b/src/xrpld/app/ledger/LocalTxs.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_APP_LEDGER_LOCALTXS_H_INCLUDED #define RIPPLE_APP_LEDGER_LOCALTXS_H_INCLUDED -#include -#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/ledger/OpenLedger.h b/src/xrpld/app/ledger/OpenLedger.h index e3cb2b10028..b218b1d6e11 100644 --- a/src/xrpld/app/ledger/OpenLedger.h +++ b/src/xrpld/app/ledger/OpenLedger.h @@ -20,14 +20,14 @@ #ifndef RIPPLE_APP_LEDGER_OPENLEDGER_H_INCLUDED #define RIPPLE_APP_LEDGER_OPENLEDGER_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/ledger/OrderBookDB.cpp b/src/xrpld/app/ledger/OrderBookDB.cpp index e1fc8a248f0..d0eddadbacb 100644 --- a/src/xrpld/app/ledger/OrderBookDB.cpp +++ b/src/xrpld/app/ledger/OrderBookDB.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/OrderBookDB.h b/src/xrpld/app/ledger/OrderBookDB.h index 45705a61572..ce0d9f0fafe 100644 --- a/src/xrpld/app/ledger/OrderBookDB.h +++ b/src/xrpld/app/ledger/OrderBookDB.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_APP_LEDGER_ORDERBOOKDB_H_INCLUDED #define RIPPLE_APP_LEDGER_ORDERBOOKDB_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/ledger/PendingSaves.h b/src/xrpld/app/ledger/PendingSaves.h index f031baf4a93..d296fcacc96 100644 --- a/src/xrpld/app/ledger/PendingSaves.h +++ b/src/xrpld/app/ledger/PendingSaves.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_APP_PENDINGSAVES_H_INCLUDED #define RIPPLE_APP_PENDINGSAVES_H_INCLUDED -#include +#include #include #include #include diff --git a/src/xrpld/app/ledger/TransactionMaster.h b/src/xrpld/app/ledger/TransactionMaster.h index 9bebac37d73..65f27af6021 100644 --- a/src/xrpld/app/ledger/TransactionMaster.h +++ b/src/xrpld/app/ledger/TransactionMaster.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_APP_LEDGER_TRANSACTIONMASTER_H_INCLUDED #define RIPPLE_APP_LEDGER_TRANSACTIONMASTER_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/TransactionStateSF.cpp b/src/xrpld/app/ledger/TransactionStateSF.cpp index f65de5f9997..fac28cd2aa8 100644 --- a/src/xrpld/app/ledger/TransactionStateSF.cpp +++ b/src/xrpld/app/ledger/TransactionStateSF.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/TransactionStateSF.h b/src/xrpld/app/ledger/TransactionStateSF.h index 6a5fa69ebd1..721f1870621 100644 --- a/src/xrpld/app/ledger/TransactionStateSF.h +++ b/src/xrpld/app/ledger/TransactionStateSF.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_APP_LEDGER_TRANSACTIONSTATESF_H_INCLUDED #define RIPPLE_APP_LEDGER_TRANSACTIONSTATESF_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/detail/BuildLedger.cpp b/src/xrpld/app/ledger/detail/BuildLedger.cpp index 363c110cd18..8c4a7a3f41d 100644 --- a/src/xrpld/app/ledger/detail/BuildLedger.cpp +++ b/src/xrpld/app/ledger/detail/BuildLedger.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/detail/InboundLedger.cpp b/src/xrpld/app/ledger/detail/InboundLedger.cpp index 53475988cbf..b98f24aed43 100644 --- a/src/xrpld/app/ledger/detail/InboundLedger.cpp +++ b/src/xrpld/app/ledger/detail/InboundLedger.cpp @@ -17,21 +17,21 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/ledger/detail/InboundLedgers.cpp b/src/xrpld/app/ledger/detail/InboundLedgers.cpp index 0bff434edbc..04964d2a921 100644 --- a/src/xrpld/app/ledger/detail/InboundLedgers.cpp +++ b/src/xrpld/app/ledger/detail/InboundLedgers.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/ledger/detail/InboundTransactions.cpp b/src/xrpld/app/ledger/detail/InboundTransactions.cpp index 7a863bce16b..83b074f317a 100644 --- a/src/xrpld/app/ledger/detail/InboundTransactions.cpp +++ b/src/xrpld/app/ledger/detail/InboundTransactions.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/ledger/detail/LedgerCleaner.cpp b/src/xrpld/app/ledger/detail/LedgerCleaner.cpp index e5ee6409d34..3021c691c53 100644 --- a/src/xrpld/app/ledger/detail/LedgerCleaner.cpp +++ b/src/xrpld/app/ledger/detail/LedgerCleaner.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp b/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp index 3c19c6ee156..e079fb3ee27 100644 --- a/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp +++ b/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.h b/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.h index 2f767cf27be..b0b2c76c245 100644 --- a/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.h +++ b/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_APP_LEDGER_LEDGERDELTAACQUIRE_H_INCLUDED #define RIPPLE_APP_LEDGER_LEDGERDELTAACQUIRE_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/ledger/detail/LedgerMaster.cpp b/src/xrpld/app/ledger/detail/LedgerMaster.cpp index 9388a3005ba..f03004fd14c 100644 --- a/src/xrpld/app/ledger/detail/LedgerMaster.cpp +++ b/src/xrpld/app/ledger/detail/LedgerMaster.cpp @@ -17,41 +17,41 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/ledger/detail/LedgerReplay.cpp b/src/xrpld/app/ledger/detail/LedgerReplay.cpp index 4a917cedf4a..40b4f9e412b 100644 --- a/src/xrpld/app/ledger/detail/LedgerReplay.cpp +++ b/src/xrpld/app/ledger/detail/LedgerReplay.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.cpp b/src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.cpp index c5301be7ea2..7b9d881d544 100644 --- a/src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.cpp +++ b/src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.h b/src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.h index 169bedea057..151a21b9563 100644 --- a/src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.h +++ b/src/xrpld/app/ledger/detail/LedgerReplayMsgHandler.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_APP_LEDGER_LEDGERREPLAYMSGHANDLER_H_INCLUDED #define RIPPLE_APP_LEDGER_LEDGERREPLAYMSGHANDLER_H_INCLUDED -#include -#include +#include +#include namespace ripple { class Application; diff --git a/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp b/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp index 46ce9815a6e..d7f29e33b3b 100644 --- a/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp +++ b/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/detail/LedgerReplayer.cpp b/src/xrpld/app/ledger/detail/LedgerReplayer.cpp index 903f72dd117..4aa0e4beb79 100644 --- a/src/xrpld/app/ledger/detail/LedgerReplayer.cpp +++ b/src/xrpld/app/ledger/detail/LedgerReplayer.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/detail/LedgerToJson.cpp b/src/xrpld/app/ledger/detail/LedgerToJson.cpp index 1310dd13a65..95b572e9736 100644 --- a/src/xrpld/app/ledger/detail/LedgerToJson.cpp +++ b/src/xrpld/app/ledger/detail/LedgerToJson.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/detail/LocalTxs.cpp b/src/xrpld/app/ledger/detail/LocalTxs.cpp index afee5e2d4d0..a6eb7721a3e 100644 --- a/src/xrpld/app/ledger/detail/LocalTxs.cpp +++ b/src/xrpld/app/ledger/detail/LocalTxs.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include /* This code prevents scenarios like the following: diff --git a/src/xrpld/app/ledger/detail/OpenLedger.cpp b/src/xrpld/app/ledger/detail/OpenLedger.cpp index 7eef84fc554..461d98ae4ac 100644 --- a/src/xrpld/app/ledger/detail/OpenLedger.cpp +++ b/src/xrpld/app/ledger/detail/OpenLedger.cpp @@ -17,16 +17,16 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/ledger/detail/SkipListAcquire.cpp b/src/xrpld/app/ledger/detail/SkipListAcquire.cpp index aa9b8564eb3..1d1de62b61b 100644 --- a/src/xrpld/app/ledger/detail/SkipListAcquire.cpp +++ b/src/xrpld/app/ledger/detail/SkipListAcquire.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/detail/SkipListAcquire.h b/src/xrpld/app/ledger/detail/SkipListAcquire.h index df24d68312c..03c8181df68 100644 --- a/src/xrpld/app/ledger/detail/SkipListAcquire.h +++ b/src/xrpld/app/ledger/detail/SkipListAcquire.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_APP_LEDGER_SKIPLISTACQUIRE_H_INCLUDED #define RIPPLE_APP_LEDGER_SKIPLISTACQUIRE_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/ledger/detail/TimeoutCounter.cpp b/src/xrpld/app/ledger/detail/TimeoutCounter.cpp index 9ea20c06384..9d677dbe5a1 100644 --- a/src/xrpld/app/ledger/detail/TimeoutCounter.cpp +++ b/src/xrpld/app/ledger/detail/TimeoutCounter.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/detail/TimeoutCounter.h b/src/xrpld/app/ledger/detail/TimeoutCounter.h index 88eda551acc..228e879d4de 100644 --- a/src/xrpld/app/ledger/detail/TimeoutCounter.h +++ b/src/xrpld/app/ledger/detail/TimeoutCounter.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_APP_LEDGER_TIMEOUTCOUNTER_H_INCLUDED #define RIPPLE_APP_LEDGER_TIMEOUTCOUNTER_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/ledger/detail/TransactionAcquire.cpp b/src/xrpld/app/ledger/detail/TransactionAcquire.cpp index 24a03a16ffb..b3561875e96 100644 --- a/src/xrpld/app/ledger/detail/TransactionAcquire.cpp +++ b/src/xrpld/app/ledger/detail/TransactionAcquire.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/ledger/detail/TransactionAcquire.h b/src/xrpld/app/ledger/detail/TransactionAcquire.h index 3863868fae0..230bce2fc94 100644 --- a/src/xrpld/app/ledger/detail/TransactionAcquire.h +++ b/src/xrpld/app/ledger/detail/TransactionAcquire.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_APP_LEDGER_TRANSACTIONACQUIRE_H_INCLUDED #define RIPPLE_APP_LEDGER_TRANSACTIONACQUIRE_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/ledger/detail/TransactionMaster.cpp b/src/xrpld/app/ledger/detail/TransactionMaster.cpp index c4205887740..e2e1213a37e 100644 --- a/src/xrpld/app/ledger/detail/TransactionMaster.cpp +++ b/src/xrpld/app/ledger/detail/TransactionMaster.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/main/Application.cpp b/src/xrpld/app/main/Application.cpp index 4f994cfe5ac..ff6cc0584ca 100644 --- a/src/xrpld/app/main/Application.cpp +++ b/src/xrpld/app/main/Application.cpp @@ -17,63 +17,63 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/main/Application.h b/src/xrpld/app/main/Application.h index 4a7d72aec25..57e6f1730e5 100644 --- a/src/xrpld/app/main/Application.h +++ b/src/xrpld/app/main/Application.h @@ -20,13 +20,13 @@ #ifndef RIPPLE_APP_MAIN_APPLICATION_H_INCLUDED #define RIPPLE_APP_MAIN_APPLICATION_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/main/BasicApp.cpp b/src/xrpld/app/main/BasicApp.cpp index 5993df62fa7..504309d0838 100644 --- a/src/xrpld/app/main/BasicApp.cpp +++ b/src/xrpld/app/main/BasicApp.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include BasicApp::BasicApp(std::size_t numberOfThreads) { diff --git a/src/xrpld/app/main/CollectorManager.cpp b/src/xrpld/app/main/CollectorManager.cpp index 6e6d0f47f24..ae7ff965f5c 100644 --- a/src/xrpld/app/main/CollectorManager.cpp +++ b/src/xrpld/app/main/CollectorManager.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include namespace ripple { diff --git a/src/xrpld/app/main/CollectorManager.h b/src/xrpld/app/main/CollectorManager.h index 46e113082d4..0bb3ae65c47 100644 --- a/src/xrpld/app/main/CollectorManager.h +++ b/src/xrpld/app/main/CollectorManager.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_APP_MAIN_COLLECTORMANAGER_H_INCLUDED #define RIPPLE_APP_MAIN_COLLECTORMANAGER_H_INCLUDED -#include -#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/main/GRPCServer.cpp b/src/xrpld/app/main/GRPCServer.cpp index a535a4a1a53..5d5a79db393 100644 --- a/src/xrpld/app/main/GRPCServer.cpp +++ b/src/xrpld/app/main/GRPCServer.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include -#include -#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/main/GRPCServer.h b/src/xrpld/app/main/GRPCServer.h index 79780e10137..39bfc0c9760 100644 --- a/src/xrpld/app/main/GRPCServer.h +++ b/src/xrpld/app/main/GRPCServer.h @@ -20,19 +20,19 @@ #ifndef RIPPLE_CORE_GRPCSERVER_H_INCLUDED #define RIPPLE_CORE_GRPCSERVER_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "org/xrpl/rpc/v1/xrp_ledger.grpc.pb.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include #include namespace ripple { diff --git a/src/xrpld/app/main/LoadManager.cpp b/src/xrpld/app/main/LoadManager.cpp index 5e87063f000..f5dd8719470 100644 --- a/src/xrpld/app/main/LoadManager.cpp +++ b/src/xrpld/app/main/LoadManager.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/main/LoadManager.h b/src/xrpld/app/main/LoadManager.h index 905006f5e41..f818068dcfa 100644 --- a/src/xrpld/app/main/LoadManager.h +++ b/src/xrpld/app/main/LoadManager.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_APP_MAIN_LOADMANAGER_H_INCLUDED #define RIPPLE_APP_MAIN_LOADMANAGER_H_INCLUDED -#include +#include #include #include #include diff --git a/src/xrpld/app/main/Main.cpp b/src/xrpld/app/main/Main.cpp index be4e354b6aa..059d9758d39 100644 --- a/src/xrpld/app/main/Main.cpp +++ b/src/xrpld/app/main/Main.cpp @@ -17,26 +17,26 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #ifdef ENABLE_TESTS -#include #include +#include #endif // ENABLE_TESTS #include diff --git a/src/xrpld/app/main/NodeIdentity.cpp b/src/xrpld/app/main/NodeIdentity.cpp index e66b9e8400f..e0b83d54c8d 100644 --- a/src/xrpld/app/main/NodeIdentity.cpp +++ b/src/xrpld/app/main/NodeIdentity.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/main/NodeIdentity.h b/src/xrpld/app/main/NodeIdentity.h index b82b3657aeb..b4da8651949 100644 --- a/src/xrpld/app/main/NodeIdentity.h +++ b/src/xrpld/app/main/NodeIdentity.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_APP_MAIN_NODEIDENTITY_H_INCLUDED #define RIPPLE_APP_MAIN_NODEIDENTITY_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/main/NodeStoreScheduler.cpp b/src/xrpld/app/main/NodeStoreScheduler.cpp index 0ac89096410..bf07e559fd3 100644 --- a/src/xrpld/app/main/NodeStoreScheduler.cpp +++ b/src/xrpld/app/main/NodeStoreScheduler.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include namespace ripple { diff --git a/src/xrpld/app/main/NodeStoreScheduler.h b/src/xrpld/app/main/NodeStoreScheduler.h index 5c68dc24f8d..b16142b2613 100644 --- a/src/xrpld/app/main/NodeStoreScheduler.h +++ b/src/xrpld/app/main/NodeStoreScheduler.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_APP_MAIN_NODESTORESCHEDULER_H_INCLUDED #define RIPPLE_APP_MAIN_NODESTORESCHEDULER_H_INCLUDED -#include -#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/misc/AMMHelpers.h b/src/xrpld/app/misc/AMMHelpers.h index 787bb2300a3..8bf5a5c5f12 100644 --- a/src/xrpld/app/misc/AMMHelpers.h +++ b/src/xrpld/app/misc/AMMHelpers.h @@ -20,18 +20,18 @@ #ifndef RIPPLE_APP_MISC_AMMHELPERS_H_INCLUDED #define RIPPLE_APP_MISC_AMMHELPERS_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/misc/AMMUtils.h b/src/xrpld/app/misc/AMMUtils.h index 9cd4b7d6fec..52fe819a28e 100644 --- a/src/xrpld/app/misc/AMMUtils.h +++ b/src/xrpld/app/misc/AMMUtils.h @@ -19,12 +19,12 @@ #ifndef RIPPLE_APP_MISC_AMMUTILS_H_INLCUDED #define RIPPLE_APP_MISC_AMMUTILS_H_INLCUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/misc/AmendmentTable.h b/src/xrpld/app/misc/AmendmentTable.h index fef13d50ddb..538d7299f3b 100644 --- a/src/xrpld/app/misc/AmendmentTable.h +++ b/src/xrpld/app/misc/AmendmentTable.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_APP_MISC_AMENDMENTTABLE_H_INCLUDED #define RIPPLE_APP_MISC_AMENDMENTTABLE_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/misc/CanonicalTXSet.cpp b/src/xrpld/app/misc/CanonicalTXSet.cpp index a9fcd17f056..bb89b598962 100644 --- a/src/xrpld/app/misc/CanonicalTXSet.cpp +++ b/src/xrpld/app/misc/CanonicalTXSet.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/xrpld/app/misc/CanonicalTXSet.h b/src/xrpld/app/misc/CanonicalTXSet.h index 3ca2179448f..b061ff10dd6 100644 --- a/src/xrpld/app/misc/CanonicalTXSet.h +++ b/src/xrpld/app/misc/CanonicalTXSet.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_APP_MISC_CANONICALTXSET_H_INCLUDED #define RIPPLE_APP_MISC_CANONICALTXSET_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/misc/DeliverMax.h b/src/xrpld/app/misc/DeliverMax.h index ddc20bdd7b4..3bc875ee4ba 100644 --- a/src/xrpld/app/misc/DeliverMax.h +++ b/src/xrpld/app/misc/DeliverMax.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_APP_MISC_DELIVERMAX_H_INCLUDED #define RIPPLE_APP_MISC_DELIVERMAX_H_INCLUDED -#include +#include #include #include diff --git a/src/xrpld/app/misc/FeeVote.h b/src/xrpld/app/misc/FeeVote.h index a90f82efb35..47769e21e4d 100644 --- a/src/xrpld/app/misc/FeeVote.h +++ b/src/xrpld/app/misc/FeeVote.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_APP_MISC_FEEVOTE_H_INCLUDED #define RIPPLE_APP_MISC_FEEVOTE_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/misc/FeeVoteImpl.cpp b/src/xrpld/app/misc/FeeVoteImpl.cpp index 0d60dc6b78e..af57314ef6d 100644 --- a/src/xrpld/app/misc/FeeVoteImpl.cpp +++ b/src/xrpld/app/misc/FeeVoteImpl.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/misc/HashRouter.cpp b/src/xrpld/app/misc/HashRouter.cpp index 8085d6892ab..c117d20fe2b 100644 --- a/src/xrpld/app/misc/HashRouter.cpp +++ b/src/xrpld/app/misc/HashRouter.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/xrpld/app/misc/HashRouter.h b/src/xrpld/app/misc/HashRouter.h index 8c546b2c51d..e9d040fc8bf 100644 --- a/src/xrpld/app/misc/HashRouter.h +++ b/src/xrpld/app/misc/HashRouter.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_APP_MISC_HASHROUTER_H_INCLUDED #define RIPPLE_APP_MISC_HASHROUTER_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/misc/LoadFeeTrack.h b/src/xrpld/app/misc/LoadFeeTrack.h index d670c0b7e11..6c37864e2fd 100644 --- a/src/xrpld/app/misc/LoadFeeTrack.h +++ b/src/xrpld/app/misc/LoadFeeTrack.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_CORE_LOADFEETRACK_H_INCLUDED #define RIPPLE_CORE_LOADFEETRACK_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/misc/Manifest.h b/src/xrpld/app/misc/Manifest.h index b1cb5d2f325..1b53fda77b5 100644 --- a/src/xrpld/app/misc/Manifest.h +++ b/src/xrpld/app/misc/Manifest.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_APP_MISC_MANIFEST_H_INCLUDED #define RIPPLE_APP_MISC_MANIFEST_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/misc/NegativeUNLVote.cpp b/src/xrpld/app/misc/NegativeUNLVote.cpp index 9b616be6ce1..45d72bcd2b3 100644 --- a/src/xrpld/app/misc/NegativeUNLVote.cpp +++ b/src/xrpld/app/misc/NegativeUNLVote.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/misc/NegativeUNLVote.h b/src/xrpld/app/misc/NegativeUNLVote.h index 6ba8b3bf26e..f0284f267a8 100644 --- a/src/xrpld/app/misc/NegativeUNLVote.h +++ b/src/xrpld/app/misc/NegativeUNLVote.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_APP_MISC_NEGATIVEUNLVOTE_H_INCLUDED #define RIPPLE_APP_MISC_NEGATIVEUNLVOTE_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/misc/NetworkOPs.cpp b/src/xrpld/app/misc/NetworkOPs.cpp index cd85bc9e4e1..9cf5d097099 100644 --- a/src/xrpld/app/misc/NetworkOPs.cpp +++ b/src/xrpld/app/misc/NetworkOPs.cpp @@ -17,57 +17,57 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/misc/NetworkOPs.h b/src/xrpld/app/misc/NetworkOPs.h index d53127ed3b6..d5f43a42972 100644 --- a/src/xrpld/app/misc/NetworkOPs.h +++ b/src/xrpld/app/misc/NetworkOPs.h @@ -20,13 +20,13 @@ #ifndef RIPPLE_APP_MISC_NETWORKOPS_H_INCLUDED #define RIPPLE_APP_MISC_NETWORKOPS_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/misc/SHAMapStore.h b/src/xrpld/app/misc/SHAMapStore.h index c42e5f5a52a..d8415713a76 100644 --- a/src/xrpld/app/misc/SHAMapStore.h +++ b/src/xrpld/app/misc/SHAMapStore.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_APP_MISC_SHAMAPSTORE_H_INCLUDED #define RIPPLE_APP_MISC_SHAMAPSTORE_H_INCLUDED -#include -#include -#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/misc/SHAMapStoreImp.cpp b/src/xrpld/app/misc/SHAMapStoreImp.cpp index d5cb07792dc..d32556a4b29 100644 --- a/src/xrpld/app/misc/SHAMapStoreImp.cpp +++ b/src/xrpld/app/misc/SHAMapStoreImp.cpp @@ -17,18 +17,18 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/misc/SHAMapStoreImp.h b/src/xrpld/app/misc/SHAMapStoreImp.h index 995ee0267bb..7d36f092be8 100644 --- a/src/xrpld/app/misc/SHAMapStoreImp.h +++ b/src/xrpld/app/misc/SHAMapStoreImp.h @@ -20,14 +20,14 @@ #ifndef RIPPLE_APP_MISC_SHAMAPSTOREIMP_H_INCLUDED #define RIPPLE_APP_MISC_SHAMAPSTOREIMP_H_INCLUDED -#include -#include -#include -#include -#include -#include - -#include +#include +#include +#include +#include +#include +#include + +#include #include #include #include diff --git a/src/xrpld/app/misc/Transaction.h b/src/xrpld/app/misc/Transaction.h index 36815ba0aa0..a2ef496dffd 100644 --- a/src/xrpld/app/misc/Transaction.h +++ b/src/xrpld/app/misc/Transaction.h @@ -20,14 +20,14 @@ #ifndef RIPPLE_APP_MISC_TRANSACTION_H_INCLUDED #define RIPPLE_APP_MISC_TRANSACTION_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/misc/TxQ.h b/src/xrpld/app/misc/TxQ.h index 7be29b49021..b962d96d50f 100644 --- a/src/xrpld/app/misc/TxQ.h +++ b/src/xrpld/app/misc/TxQ.h @@ -20,13 +20,13 @@ #ifndef RIPPLE_TXQ_H_INCLUDED #define RIPPLE_TXQ_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/misc/ValidatorKeys.h b/src/xrpld/app/misc/ValidatorKeys.h index a6b53841739..f5b9e5735a6 100644 --- a/src/xrpld/app/misc/ValidatorKeys.h +++ b/src/xrpld/app/misc/ValidatorKeys.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_APP_MISC_VALIDATOR_KEYS_H_INCLUDED #define RIPPLE_APP_MISC_VALIDATOR_KEYS_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/misc/ValidatorList.h b/src/xrpld/app/misc/ValidatorList.h index 4d792b36b0f..543eba2f6b7 100644 --- a/src/xrpld/app/misc/ValidatorList.h +++ b/src/xrpld/app/misc/ValidatorList.h @@ -20,14 +20,14 @@ #ifndef RIPPLE_APP_MISC_VALIDATORLIST_H_INCLUDED #define RIPPLE_APP_MISC_VALIDATORLIST_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/misc/ValidatorSite.h b/src/xrpld/app/misc/ValidatorSite.h index 57606066bf0..39bf895807f 100644 --- a/src/xrpld/app/misc/ValidatorSite.h +++ b/src/xrpld/app/misc/ValidatorSite.h @@ -20,13 +20,13 @@ #ifndef RIPPLE_APP_MISC_VALIDATORSITE_H_INCLUDED #define RIPPLE_APP_MISC_VALIDATORSITE_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/misc/detail/AMMHelpers.cpp b/src/xrpld/app/misc/detail/AMMHelpers.cpp index 5ad59ea1c28..f10b4c15eb0 100644 --- a/src/xrpld/app/misc/detail/AMMHelpers.cpp +++ b/src/xrpld/app/misc/detail/AMMHelpers.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/xrpld/app/misc/detail/AMMUtils.cpp b/src/xrpld/app/misc/detail/AMMUtils.cpp index 4f6f0fbd3b5..0014ab01118 100644 --- a/src/xrpld/app/misc/detail/AMMUtils.cpp +++ b/src/xrpld/app/misc/detail/AMMUtils.cpp @@ -16,12 +16,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/misc/detail/AccountTxPaging.cpp b/src/xrpld/app/misc/detail/AccountTxPaging.cpp index 433463e2826..898c41b40c4 100644 --- a/src/xrpld/app/misc/detail/AccountTxPaging.cpp +++ b/src/xrpld/app/misc/detail/AccountTxPaging.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/misc/detail/AccountTxPaging.h b/src/xrpld/app/misc/detail/AccountTxPaging.h index 6b8f235b5a8..23a5cbd9c23 100644 --- a/src/xrpld/app/misc/detail/AccountTxPaging.h +++ b/src/xrpld/app/misc/detail/AccountTxPaging.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_APP_MISC_IMPL_ACCOUNTTXPAGING_H_INCLUDED #define RIPPLE_APP_MISC_IMPL_ACCOUNTTXPAGING_H_INCLUDED -#include +#include #include #include #include diff --git a/src/xrpld/app/misc/detail/AmendmentTable.cpp b/src/xrpld/app/misc/detail/AmendmentTable.cpp index 8f9556e0714..62b80890821 100644 --- a/src/xrpld/app/misc/detail/AmendmentTable.cpp +++ b/src/xrpld/app/misc/detail/AmendmentTable.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/misc/detail/DeliverMax.cpp b/src/xrpld/app/misc/detail/DeliverMax.cpp index 810b750a355..58a23599728 100644 --- a/src/xrpld/app/misc/detail/DeliverMax.cpp +++ b/src/xrpld/app/misc/detail/DeliverMax.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include +#include -#include +#include namespace ripple { namespace RPC { diff --git a/src/xrpld/app/misc/detail/LoadFeeTrack.cpp b/src/xrpld/app/misc/detail/LoadFeeTrack.cpp index 86d145c856c..1267af594d0 100644 --- a/src/xrpld/app/misc/detail/LoadFeeTrack.cpp +++ b/src/xrpld/app/misc/detail/LoadFeeTrack.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/misc/detail/Manifest.cpp b/src/xrpld/app/misc/detail/Manifest.cpp index 2916d6d2f32..a17858ceb39 100644 --- a/src/xrpld/app/misc/detail/Manifest.cpp +++ b/src/xrpld/app/misc/detail/Manifest.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/misc/detail/Transaction.cpp b/src/xrpld/app/misc/detail/Transaction.cpp index e3ec41a25d4..e0c3f260fe5 100644 --- a/src/xrpld/app/misc/detail/Transaction.cpp +++ b/src/xrpld/app/misc/detail/Transaction.cpp @@ -17,21 +17,21 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/misc/detail/TxQ.cpp b/src/xrpld/app/misc/detail/TxQ.cpp index faaca0655cf..159a700cc3f 100644 --- a/src/xrpld/app/misc/detail/TxQ.cpp +++ b/src/xrpld/app/misc/detail/TxQ.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/misc/detail/ValidatorKeys.cpp b/src/xrpld/app/misc/detail/ValidatorKeys.cpp index 8da1992a2ef..2b36848c882 100644 --- a/src/xrpld/app/misc/detail/ValidatorKeys.cpp +++ b/src/xrpld/app/misc/detail/ValidatorKeys.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include +#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { ValidatorKeys::ValidatorKeys(Config const& config, beast::Journal j) diff --git a/src/xrpld/app/misc/detail/ValidatorList.cpp b/src/xrpld/app/misc/detail/ValidatorList.cpp index 13dcd7873db..a3854106a1c 100644 --- a/src/xrpld/app/misc/detail/ValidatorList.cpp +++ b/src/xrpld/app/misc/detail/ValidatorList.cpp @@ -17,20 +17,20 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/misc/detail/ValidatorSite.cpp b/src/xrpld/app/misc/detail/ValidatorSite.cpp index 013d7e96ffd..0c12816c1b8 100644 --- a/src/xrpld/app/misc/detail/ValidatorSite.cpp +++ b/src/xrpld/app/misc/detail/ValidatorSite.cpp @@ -17,16 +17,16 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/misc/detail/WorkBase.h b/src/xrpld/app/misc/detail/WorkBase.h index 4b2c88f71a1..d7795af8bf0 100644 --- a/src/xrpld/app/misc/detail/WorkBase.h +++ b/src/xrpld/app/misc/detail/WorkBase.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_APP_MISC_DETAIL_WORKBASE_H_INCLUDED #define RIPPLE_APP_MISC_DETAIL_WORKBASE_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/misc/detail/WorkFile.h b/src/xrpld/app/misc/detail/WorkFile.h index 2dc451feaca..266e5098cb6 100644 --- a/src/xrpld/app/misc/detail/WorkFile.h +++ b/src/xrpld/app/misc/detail/WorkFile.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_APP_MISC_DETAIL_WORKFILE_H_INCLUDED #define RIPPLE_APP_MISC_DETAIL_WORKFILE_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/misc/detail/WorkPlain.h b/src/xrpld/app/misc/detail/WorkPlain.h index e70d327c223..16bf424131f 100644 --- a/src/xrpld/app/misc/detail/WorkPlain.h +++ b/src/xrpld/app/misc/detail/WorkPlain.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_APP_MISC_DETAIL_WORKPLAIN_H_INCLUDED #define RIPPLE_APP_MISC_DETAIL_WORKPLAIN_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/misc/detail/WorkSSL.h b/src/xrpld/app/misc/detail/WorkSSL.h index c7e3de614c2..d48f0b5fdff 100644 --- a/src/xrpld/app/misc/detail/WorkSSL.h +++ b/src/xrpld/app/misc/detail/WorkSSL.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_APP_MISC_DETAIL_WORKSSL_H_INCLUDED #define RIPPLE_APP_MISC_DETAIL_WORKSSL_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/misc/detail/detail/WorkSSL.cpp b/src/xrpld/app/misc/detail/detail/WorkSSL.cpp index 78a269e67cc..0285f435026 100644 --- a/src/xrpld/app/misc/detail/detail/WorkSSL.cpp +++ b/src/xrpld/app/misc/detail/detail/WorkSSL.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { namespace detail { diff --git a/src/xrpld/app/paths/AMMContext.h b/src/xrpld/app/paths/AMMContext.h index 06835189bb7..f744b8a6c91 100644 --- a/src/xrpld/app/paths/AMMContext.h +++ b/src/xrpld/app/paths/AMMContext.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_APP_PATHS_AMMCONTEXT_H_INCLUDED #define RIPPLE_APP_PATHS_AMMCONTEXT_H_INCLUDED -#include +#include #include diff --git a/src/xrpld/app/paths/AMMLiquidity.h b/src/xrpld/app/paths/AMMLiquidity.h index 60155dbf13f..fe60d39262f 100644 --- a/src/xrpld/app/paths/AMMLiquidity.h +++ b/src/xrpld/app/paths/AMMLiquidity.h @@ -20,14 +20,14 @@ #ifndef RIPPLE_APP_TX_AMMLIQUIDITY_H_INCLUDED #define RIPPLE_APP_TX_AMMLIQUIDITY_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/paths/AMMOffer.h b/src/xrpld/app/paths/AMMOffer.h index e47a5613b09..e90a5b8611f 100644 --- a/src/xrpld/app/paths/AMMOffer.h +++ b/src/xrpld/app/paths/AMMOffer.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_APP_AMMOFFER_H_INCLUDED #define RIPPLE_APP_AMMOFFER_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/paths/AccountCurrencies.cpp b/src/xrpld/app/paths/AccountCurrencies.cpp index 18452725b67..8646b46939a 100644 --- a/src/xrpld/app/paths/AccountCurrencies.cpp +++ b/src/xrpld/app/paths/AccountCurrencies.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/xrpld/app/paths/AccountCurrencies.h b/src/xrpld/app/paths/AccountCurrencies.h index fa70ec2a081..26282e742c3 100644 --- a/src/xrpld/app/paths/AccountCurrencies.h +++ b/src/xrpld/app/paths/AccountCurrencies.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_APP_PATHS_ACCOUNTCURRENCIES_H_INCLUDED #define RIPPLE_APP_PATHS_ACCOUNTCURRENCIES_H_INCLUDED -#include -#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/paths/Credit.cpp b/src/xrpld/app/paths/Credit.cpp index b9b19d29f90..c11f628a11d 100644 --- a/src/xrpld/app/paths/Credit.cpp +++ b/src/xrpld/app/paths/Credit.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/paths/Credit.h b/src/xrpld/app/paths/Credit.h index dea9cbcde3e..1f9d5b04fe9 100644 --- a/src/xrpld/app/paths/Credit.h +++ b/src/xrpld/app/paths/Credit.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_APP_PATHS_CREDIT_H_INCLUDED #define RIPPLE_APP_PATHS_CREDIT_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/paths/Flow.cpp b/src/xrpld/app/paths/Flow.cpp index 83379d34e79..c21d40c33b5 100644 --- a/src/xrpld/app/paths/Flow.cpp +++ b/src/xrpld/app/paths/Flow.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/paths/Flow.h b/src/xrpld/app/paths/Flow.h index deafd1c7716..5390394b7f0 100644 --- a/src/xrpld/app/paths/Flow.h +++ b/src/xrpld/app/paths/Flow.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_APP_PATHS_FLOW_H_INCLUDED #define RIPPLE_APP_PATHS_FLOW_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/paths/PathRequest.cpp b/src/xrpld/app/paths/PathRequest.cpp index 948c6698ad1..4cd9f7d71f7 100644 --- a/src/xrpld/app/paths/PathRequest.cpp +++ b/src/xrpld/app/paths/PathRequest.cpp @@ -17,22 +17,22 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include #include #include diff --git a/src/xrpld/app/paths/PathRequest.h b/src/xrpld/app/paths/PathRequest.h index 70c286d6e1f..21f10d066ba 100644 --- a/src/xrpld/app/paths/PathRequest.h +++ b/src/xrpld/app/paths/PathRequest.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_APP_PATHS_PATHREQUEST_H_INCLUDED #define RIPPLE_APP_PATHS_PATHREQUEST_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/paths/PathRequests.cpp b/src/xrpld/app/paths/PathRequests.cpp index 700cf137209..86560445ec7 100644 --- a/src/xrpld/app/paths/PathRequests.cpp +++ b/src/xrpld/app/paths/PathRequests.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/paths/PathRequests.h b/src/xrpld/app/paths/PathRequests.h index db683ee4c13..670790518a1 100644 --- a/src/xrpld/app/paths/PathRequests.h +++ b/src/xrpld/app/paths/PathRequests.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_APP_PATHS_PATHREQUESTS_H_INCLUDED #define RIPPLE_APP_PATHS_PATHREQUESTS_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/paths/Pathfinder.cpp b/src/xrpld/app/paths/Pathfinder.cpp index 556622ee7bf..885a8ae9b47 100644 --- a/src/xrpld/app/paths/Pathfinder.cpp +++ b/src/xrpld/app/paths/Pathfinder.cpp @@ -17,18 +17,18 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/paths/Pathfinder.h b/src/xrpld/app/paths/Pathfinder.h index 375e5e24677..01556a3c63f 100644 --- a/src/xrpld/app/paths/Pathfinder.h +++ b/src/xrpld/app/paths/Pathfinder.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_APP_PATHS_PATHFINDER_H_INCLUDED #define RIPPLE_APP_PATHS_PATHFINDER_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/paths/RippleCalc.cpp b/src/xrpld/app/paths/RippleCalc.cpp index 87ef694fa58..c7b2e1f01e0 100644 --- a/src/xrpld/app/paths/RippleCalc.cpp +++ b/src/xrpld/app/paths/RippleCalc.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace path { diff --git a/src/xrpld/app/paths/RippleCalc.h b/src/xrpld/app/paths/RippleCalc.h index fd9ff598114..9e03da9c906 100644 --- a/src/xrpld/app/paths/RippleCalc.h +++ b/src/xrpld/app/paths/RippleCalc.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_APP_PATHS_RIPPLECALC_H_INCLUDED #define RIPPLE_APP_PATHS_RIPPLECALC_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/paths/RippleLineCache.cpp b/src/xrpld/app/paths/RippleLineCache.cpp index 2487924ff0e..0ff967c0821 100644 --- a/src/xrpld/app/paths/RippleLineCache.cpp +++ b/src/xrpld/app/paths/RippleLineCache.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/paths/RippleLineCache.h b/src/xrpld/app/paths/RippleLineCache.h index 590c50082f7..cde1d589f92 100644 --- a/src/xrpld/app/paths/RippleLineCache.h +++ b/src/xrpld/app/paths/RippleLineCache.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_APP_PATHS_RIPPLELINECACHE_H_INCLUDED #define RIPPLE_APP_PATHS_RIPPLELINECACHE_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/paths/TrustLine.cpp b/src/xrpld/app/paths/TrustLine.cpp index 14a5d6f8823..6390c8d2117 100644 --- a/src/xrpld/app/paths/TrustLine.cpp +++ b/src/xrpld/app/paths/TrustLine.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/paths/TrustLine.h b/src/xrpld/app/paths/TrustLine.h index 6b27dca3669..381ef471875 100644 --- a/src/xrpld/app/paths/TrustLine.h +++ b/src/xrpld/app/paths/TrustLine.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_APP_PATHS_RIPPLESTATE_H_INCLUDED #define RIPPLE_APP_PATHS_RIPPLESTATE_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/paths/detail/AMMLiquidity.cpp b/src/xrpld/app/paths/detail/AMMLiquidity.cpp index 9ec23d08a1a..8215cdee593 100644 --- a/src/xrpld/app/paths/detail/AMMLiquidity.cpp +++ b/src/xrpld/app/paths/detail/AMMLiquidity.cpp @@ -16,9 +16,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include +#include -#include +#include namespace ripple { diff --git a/src/xrpld/app/paths/detail/AMMOffer.cpp b/src/xrpld/app/paths/detail/AMMOffer.cpp index bf85ead6194..16ea8628f3b 100644 --- a/src/xrpld/app/paths/detail/AMMOffer.cpp +++ b/src/xrpld/app/paths/detail/AMMOffer.cpp @@ -16,10 +16,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //==============================================================================/ -#include +#include -#include -#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/paths/detail/AmountSpec.h b/src/xrpld/app/paths/detail/AmountSpec.h index ca814c7b3ac..8a1117f9920 100644 --- a/src/xrpld/app/paths/detail/AmountSpec.h +++ b/src/xrpld/app/paths/detail/AmountSpec.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_PATH_IMPL_AMOUNTSPEC_H_INCLUDED #define RIPPLE_PATH_IMPL_AMOUNTSPEC_H_INCLUDED -#include -#include -#include +#include +#include +#include #include diff --git a/src/xrpld/app/paths/detail/BookStep.cpp b/src/xrpld/app/paths/detail/BookStep.cpp index af0c40b1925..4fa6f140aae 100644 --- a/src/xrpld/app/paths/detail/BookStep.cpp +++ b/src/xrpld/app/paths/detail/BookStep.cpp @@ -17,21 +17,21 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/paths/detail/DirectStep.cpp b/src/xrpld/app/paths/detail/DirectStep.cpp index 00647121b74..25e78e9c47e 100644 --- a/src/xrpld/app/paths/detail/DirectStep.cpp +++ b/src/xrpld/app/paths/detail/DirectStep.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/paths/detail/FlowDebugInfo.h b/src/xrpld/app/paths/detail/FlowDebugInfo.h index 2d1728b5f88..000db4e5714 100644 --- a/src/xrpld/app/paths/detail/FlowDebugInfo.h +++ b/src/xrpld/app/paths/detail/FlowDebugInfo.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_PATH_IMPL_FLOWDEBUGINFO_H_INCLUDED #define RIPPLE_PATH_IMPL_FLOWDEBUGINFO_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/paths/detail/PathfinderUtils.h b/src/xrpld/app/paths/detail/PathfinderUtils.h index 066d905a1cd..b06dded75bd 100644 --- a/src/xrpld/app/paths/detail/PathfinderUtils.h +++ b/src/xrpld/app/paths/detail/PathfinderUtils.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PATH_IMPL_PATHFINDERUTILS_H_INCLUDED #define RIPPLE_PATH_IMPL_PATHFINDERUTILS_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/paths/detail/PaySteps.cpp b/src/xrpld/app/paths/detail/PaySteps.cpp index b96d6ee57b2..f28c1b96a7c 100644 --- a/src/xrpld/app/paths/detail/PaySteps.cpp +++ b/src/xrpld/app/paths/detail/PaySteps.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/paths/detail/StepChecks.h b/src/xrpld/app/paths/detail/StepChecks.h index 9d8664a8dc1..140c9d1fe46 100644 --- a/src/xrpld/app/paths/detail/StepChecks.h +++ b/src/xrpld/app/paths/detail/StepChecks.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_APP_PATHS_IMPL_STEP_CHECKS_H_INCLUDED #define RIPPLE_APP_PATHS_IMPL_STEP_CHECKS_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/paths/detail/Steps.h b/src/xrpld/app/paths/detail/Steps.h index 2a4bfe310dd..dee90f617a5 100644 --- a/src/xrpld/app/paths/detail/Steps.h +++ b/src/xrpld/app/paths/detail/Steps.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_APP_PATHS_IMPL_PAYSTEPS_H_INCLUDED #define RIPPLE_APP_PATHS_IMPL_PAYSTEPS_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/paths/detail/StrandFlow.h b/src/xrpld/app/paths/detail/StrandFlow.h index 2df496d8311..329a4cc643f 100644 --- a/src/xrpld/app/paths/detail/StrandFlow.h +++ b/src/xrpld/app/paths/detail/StrandFlow.h @@ -20,18 +20,18 @@ #ifndef RIPPLE_APP_PATHS_IMPL_STRANDFLOW_H_INCLUDED #define RIPPLE_APP_PATHS_IMPL_STRANDFLOW_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/paths/detail/XRPEndpointStep.cpp b/src/xrpld/app/paths/detail/XRPEndpointStep.cpp index 4878463801c..ac88152c9dd 100644 --- a/src/xrpld/app/paths/detail/XRPEndpointStep.cpp +++ b/src/xrpld/app/paths/detail/XRPEndpointStep.cpp @@ -17,16 +17,16 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/rdb/Download.h b/src/xrpld/app/rdb/Download.h index b72b5ec57e7..6ee02d4c100 100644 --- a/src/xrpld/app/rdb/Download.h +++ b/src/xrpld/app/rdb/Download.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_APP_RDB_DOWNLOAD_H_INCLUDED #define RIPPLE_APP_RDB_DOWNLOAD_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/rdb/PeerFinder.h b/src/xrpld/app/rdb/PeerFinder.h index 06cd80f670b..8becd053fbe 100644 --- a/src/xrpld/app/rdb/PeerFinder.h +++ b/src/xrpld/app/rdb/PeerFinder.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_APP_RDB_PEERFINDER_H_INCLUDED #define RIPPLE_APP_RDB_PEERFINDER_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/rdb/RelationalDatabase.h b/src/xrpld/app/rdb/RelationalDatabase.h index a269bf256c8..b30c94153f7 100644 --- a/src/xrpld/app/rdb/RelationalDatabase.h +++ b/src/xrpld/app/rdb/RelationalDatabase.h @@ -20,13 +20,13 @@ #ifndef RIPPLE_APP_RDB_RELATIONALDATABASE_H_INCLUDED #define RIPPLE_APP_RDB_RELATIONALDATABASE_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/rdb/ShardArchive.h b/src/xrpld/app/rdb/ShardArchive.h index 20c4382b056..44f990ab5f5 100644 --- a/src/xrpld/app/rdb/ShardArchive.h +++ b/src/xrpld/app/rdb/ShardArchive.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_APP_RDB_SHARDARCHIVE_H_INCLUDED #define RIPPLE_APP_RDB_SHARDARCHIVE_H_INCLUDED -#include +#include #include namespace ripple { diff --git a/src/xrpld/app/rdb/State.h b/src/xrpld/app/rdb/State.h index fe74d5f19d3..b245270cda2 100644 --- a/src/xrpld/app/rdb/State.h +++ b/src/xrpld/app/rdb/State.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_APP_RDB_STATE_H_INCLUDED #define RIPPLE_APP_RDB_STATE_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/rdb/UnitaryShard.h b/src/xrpld/app/rdb/UnitaryShard.h index d2ac773dbd3..e848000221d 100644 --- a/src/xrpld/app/rdb/UnitaryShard.h +++ b/src/xrpld/app/rdb/UnitaryShard.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_APP_RDB_UNITARYSHARD_H_INCLUDED #define RIPPLE_APP_RDB_UNITARYSHARD_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/rdb/Vacuum.h b/src/xrpld/app/rdb/Vacuum.h index 3db18da045a..5ac796d43be 100644 --- a/src/xrpld/app/rdb/Vacuum.h +++ b/src/xrpld/app/rdb/Vacuum.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_APP_RDB_VACUUM_H_INCLUDED #define RIPPLE_APP_RDB_VACUUM_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/rdb/Wallet.h b/src/xrpld/app/rdb/Wallet.h index e9846714ece..b79bf9f1377 100644 --- a/src/xrpld/app/rdb/Wallet.h +++ b/src/xrpld/app/rdb/Wallet.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_APP_RDB_WALLET_H_INCLUDED #define RIPPLE_APP_RDB_WALLET_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/rdb/backend/PostgresDatabase.h b/src/xrpld/app/rdb/backend/PostgresDatabase.h index e8673611279..c2841cefd8c 100644 --- a/src/xrpld/app/rdb/backend/PostgresDatabase.h +++ b/src/xrpld/app/rdb/backend/PostgresDatabase.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_APP_RDB_BACKEND_POSTGRESDATABASE_H_INCLUDED #define RIPPLE_APP_RDB_BACKEND_POSTGRESDATABASE_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/rdb/backend/SQLiteDatabase.h b/src/xrpld/app/rdb/backend/SQLiteDatabase.h index 07f9be3e228..27c01c1b83d 100644 --- a/src/xrpld/app/rdb/backend/SQLiteDatabase.h +++ b/src/xrpld/app/rdb/backend/SQLiteDatabase.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_APP_RDB_BACKEND_SQLITEDATABASE_H_INCLUDED #define RIPPLE_APP_RDB_BACKEND_SQLITEDATABASE_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/rdb/backend/detail/Node.h b/src/xrpld/app/rdb/backend/detail/Node.h index ab3a99f5f95..d7c170663a5 100644 --- a/src/xrpld/app/rdb/backend/detail/Node.h +++ b/src/xrpld/app/rdb/backend/detail/Node.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_APP_RDB_BACKEND_DETAIL_NODE_H_INCLUDED #define RIPPLE_APP_RDB_BACKEND_DETAIL_NODE_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/rdb/backend/detail/PostgresDatabase.cpp b/src/xrpld/app/rdb/backend/detail/PostgresDatabase.cpp index c57dee30610..ac998991a6d 100644 --- a/src/xrpld/app/rdb/backend/detail/PostgresDatabase.cpp +++ b/src/xrpld/app/rdb/backend/detail/PostgresDatabase.cpp @@ -17,23 +17,23 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/rdb/backend/detail/SQLiteDatabase.cpp b/src/xrpld/app/rdb/backend/detail/SQLiteDatabase.cpp index 547ab843b36..3edc5d163d8 100644 --- a/src/xrpld/app/rdb/backend/detail/SQLiteDatabase.cpp +++ b/src/xrpld/app/rdb/backend/detail/SQLiteDatabase.cpp @@ -17,21 +17,21 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/rdb/backend/detail/Shard.h b/src/xrpld/app/rdb/backend/detail/Shard.h index ac88c24bd78..870b6b82fe4 100644 --- a/src/xrpld/app/rdb/backend/detail/Shard.h +++ b/src/xrpld/app/rdb/backend/detail/Shard.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_APP_RDB_BACKEND_DETAIL_SHARD_H_INCLUDED #define RIPPLE_APP_RDB_BACKEND_DETAIL_SHARD_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/rdb/backend/detail/detail/Node.cpp b/src/xrpld/app/rdb/backend/detail/detail/Node.cpp index 0905d6121ae..67a80b43cf3 100644 --- a/src/xrpld/app/rdb/backend/detail/detail/Node.cpp +++ b/src/xrpld/app/rdb/backend/detail/detail/Node.cpp @@ -17,19 +17,19 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/rdb/backend/detail/detail/Shard.cpp b/src/xrpld/app/rdb/backend/detail/detail/Shard.cpp index f7a0ce4571b..6db64b1249b 100644 --- a/src/xrpld/app/rdb/backend/detail/detail/Shard.cpp +++ b/src/xrpld/app/rdb/backend/detail/detail/Shard.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace detail { diff --git a/src/xrpld/app/rdb/detail/Download.cpp b/src/xrpld/app/rdb/detail/Download.cpp index 0905ee577b1..012d60b3734 100644 --- a/src/xrpld/app/rdb/detail/Download.cpp +++ b/src/xrpld/app/rdb/detail/Download.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include namespace ripple { diff --git a/src/xrpld/app/rdb/detail/PeerFinder.cpp b/src/xrpld/app/rdb/detail/PeerFinder.cpp index 46dca3760c7..b2eaf3dfe11 100644 --- a/src/xrpld/app/rdb/detail/PeerFinder.cpp +++ b/src/xrpld/app/rdb/detail/PeerFinder.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/xrpld/app/rdb/detail/RelationalDatabase.cpp b/src/xrpld/app/rdb/detail/RelationalDatabase.cpp index 8a3ce5b016d..874550abd97 100644 --- a/src/xrpld/app/rdb/detail/RelationalDatabase.cpp +++ b/src/xrpld/app/rdb/detail/RelationalDatabase.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/rdb/detail/ShardArchive.cpp b/src/xrpld/app/rdb/detail/ShardArchive.cpp index 6880aa00136..81b99348cb4 100644 --- a/src/xrpld/app/rdb/detail/ShardArchive.cpp +++ b/src/xrpld/app/rdb/detail/ShardArchive.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/xrpld/app/rdb/detail/State.cpp b/src/xrpld/app/rdb/detail/State.cpp index 8f8beb0c7e1..c3de860689c 100644 --- a/src/xrpld/app/rdb/detail/State.cpp +++ b/src/xrpld/app/rdb/detail/State.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/xrpld/app/rdb/detail/UnitaryShard.cpp b/src/xrpld/app/rdb/detail/UnitaryShard.cpp index ab1758b4852..dd64759f4a8 100644 --- a/src/xrpld/app/rdb/detail/UnitaryShard.cpp +++ b/src/xrpld/app/rdb/detail/UnitaryShard.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include diff --git a/src/xrpld/app/rdb/detail/Vacuum.cpp b/src/xrpld/app/rdb/detail/Vacuum.cpp index aad456cc5a8..71129c5b5df 100644 --- a/src/xrpld/app/rdb/detail/Vacuum.cpp +++ b/src/xrpld/app/rdb/detail/Vacuum.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include namespace ripple { diff --git a/src/xrpld/app/rdb/detail/Wallet.cpp b/src/xrpld/app/rdb/detail/Wallet.cpp index 3715c4c7458..bec727506db 100644 --- a/src/xrpld/app/rdb/detail/Wallet.cpp +++ b/src/xrpld/app/rdb/detail/Wallet.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include namespace ripple { diff --git a/src/xrpld/app/reporting/ETLHelpers.h b/src/xrpld/app/reporting/ETLHelpers.h index 04f282ca53e..b11d2c4aa18 100644 --- a/src/xrpld/app/reporting/ETLHelpers.h +++ b/src/xrpld/app/reporting/ETLHelpers.h @@ -19,8 +19,8 @@ #ifndef RIPPLE_APP_REPORTING_ETLHELPERS_H_INCLUDED #define RIPPLE_APP_REPORTING_ETLHELPERS_H_INCLUDED -#include -#include +#include +#include #include #include #include diff --git a/src/xrpld/app/reporting/ETLSource.cpp b/src/xrpld/app/reporting/ETLSource.cpp index 73ba9816950..8a181c62b1d 100644 --- a/src/xrpld/app/reporting/ETLSource.cpp +++ b/src/xrpld/app/reporting/ETLSource.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/reporting/ETLSource.h b/src/xrpld/app/reporting/ETLSource.h index b9f27a1bf1f..633b72afac1 100644 --- a/src/xrpld/app/reporting/ETLSource.h +++ b/src/xrpld/app/reporting/ETLSource.h @@ -19,11 +19,11 @@ #ifndef RIPPLE_APP_REPORTING_ETLSOURCE_H_INCLUDED #define RIPPLE_APP_REPORTING_ETLSOURCE_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/reporting/P2pProxy.cpp b/src/xrpld/app/reporting/P2pProxy.cpp index ee04b68e6b5..df699f4faf0 100644 --- a/src/xrpld/app/reporting/P2pProxy.cpp +++ b/src/xrpld/app/reporting/P2pProxy.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/reporting/P2pProxy.h b/src/xrpld/app/reporting/P2pProxy.h index 55ebc726726..d49389f42d3 100644 --- a/src/xrpld/app/reporting/P2pProxy.h +++ b/src/xrpld/app/reporting/P2pProxy.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_APP_REPORTING_P2PPROXY_H_INCLUDED #define RIPPLE_APP_REPORTING_P2PPROXY_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/reporting/ReportingETL.cpp b/src/xrpld/app/reporting/ReportingETL.cpp index d8d6af36881..2f6411b0808 100644 --- a/src/xrpld/app/reporting/ReportingETL.cpp +++ b/src/xrpld/app/reporting/ReportingETL.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include +#include +#include -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/reporting/ReportingETL.h b/src/xrpld/app/reporting/ReportingETL.h index 71e08adf1f3..fc15f90b43b 100644 --- a/src/xrpld/app/reporting/ReportingETL.h +++ b/src/xrpld/app/reporting/ReportingETL.h @@ -20,27 +20,27 @@ #ifndef RIPPLE_APP_REPORTING_REPORTINGETL_H_INCLUDED #define RIPPLE_APP_REPORTING_REPORTINGETL_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include -#include "org/xrpl/rpc/v1/xrp_ledger.grpc.pb.h" +#include #include #include diff --git a/src/xrpld/app/tx/apply.h b/src/xrpld/app/tx/apply.h index b71e7ed4a9d..6a0401e2b55 100644 --- a/src/xrpld/app/tx/apply.h +++ b/src/xrpld/app/tx/apply.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_TX_APPLY_H_INCLUDED #define RIPPLE_TX_APPLY_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/tx/applySteps.h b/src/xrpld/app/tx/applySteps.h index ede7bd8cc09..1df537515e9 100644 --- a/src/xrpld/app/tx/applySteps.h +++ b/src/xrpld/app/tx/applySteps.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_TX_APPLYSTEPS_H_INCLUDED #define RIPPLE_TX_APPLYSTEPS_H_INCLUDED -#include -#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/AMMBid.cpp b/src/xrpld/app/tx/detail/AMMBid.cpp index e49c378ceeb..9de3762d2e3 100644 --- a/src/xrpld/app/tx/detail/AMMBid.cpp +++ b/src/xrpld/app/tx/detail/AMMBid.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/AMMBid.h b/src/xrpld/app/tx/detail/AMMBid.h index db3d8d9b016..4bb3a2adfd2 100644 --- a/src/xrpld/app/tx/detail/AMMBid.h +++ b/src/xrpld/app/tx/detail/AMMBid.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_AMMBID_H_INCLUDED #define RIPPLE_TX_AMMBID_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/AMMCreate.cpp b/src/xrpld/app/tx/detail/AMMCreate.cpp index cab99f1669e..237e1afa240 100644 --- a/src/xrpld/app/tx/detail/AMMCreate.cpp +++ b/src/xrpld/app/tx/detail/AMMCreate.cpp @@ -17,18 +17,18 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/AMMCreate.h b/src/xrpld/app/tx/detail/AMMCreate.h index f521f5870b4..189d66a55ac 100644 --- a/src/xrpld/app/tx/detail/AMMCreate.h +++ b/src/xrpld/app/tx/detail/AMMCreate.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_AMMCREATE_H_INCLUDED #define RIPPLE_TX_AMMCREATE_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/AMMDelete.cpp b/src/xrpld/app/tx/detail/AMMDelete.cpp index 25502be4f44..89ce34052d2 100644 --- a/src/xrpld/app/tx/detail/AMMDelete.cpp +++ b/src/xrpld/app/tx/detail/AMMDelete.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/AMMDelete.h b/src/xrpld/app/tx/detail/AMMDelete.h index cf7f55cb715..19885b1dad6 100644 --- a/src/xrpld/app/tx/detail/AMMDelete.h +++ b/src/xrpld/app/tx/detail/AMMDelete.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_AMMDELETE_H_INCLUDED #define RIPPLE_TX_AMMDELETE_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/AMMDeposit.cpp b/src/xrpld/app/tx/detail/AMMDeposit.cpp index 74cba160edc..9bbf5b4a60a 100644 --- a/src/xrpld/app/tx/detail/AMMDeposit.cpp +++ b/src/xrpld/app/tx/detail/AMMDeposit.cpp @@ -17,16 +17,16 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/tx/detail/AMMDeposit.h b/src/xrpld/app/tx/detail/AMMDeposit.h index 385ce7c24e5..0acb1dd9ab3 100644 --- a/src/xrpld/app/tx/detail/AMMDeposit.h +++ b/src/xrpld/app/tx/detail/AMMDeposit.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_AMMDEPOSIT_H_INCLUDED #define RIPPLE_TX_AMMDEPOSIT_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/AMMVote.cpp b/src/xrpld/app/tx/detail/AMMVote.cpp index d908a93c383..6da320f83e2 100644 --- a/src/xrpld/app/tx/detail/AMMVote.cpp +++ b/src/xrpld/app/tx/detail/AMMVote.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/AMMVote.h b/src/xrpld/app/tx/detail/AMMVote.h index 97d257d0513..2bee01aff53 100644 --- a/src/xrpld/app/tx/detail/AMMVote.h +++ b/src/xrpld/app/tx/detail/AMMVote.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_AMMVOTE_H_INCLUDED #define RIPPLE_TX_AMMVOTE_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/AMMWithdraw.cpp b/src/xrpld/app/tx/detail/AMMWithdraw.cpp index c8d0d67dc97..51b512aba0a 100644 --- a/src/xrpld/app/tx/detail/AMMWithdraw.cpp +++ b/src/xrpld/app/tx/detail/AMMWithdraw.cpp @@ -17,16 +17,16 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/tx/detail/AMMWithdraw.h b/src/xrpld/app/tx/detail/AMMWithdraw.h index 40686266315..9e9920aa5f6 100644 --- a/src/xrpld/app/tx/detail/AMMWithdraw.h +++ b/src/xrpld/app/tx/detail/AMMWithdraw.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_AMMWITHDRAW_H_INCLUDED #define RIPPLE_TX_AMMWITHDRAW_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/ApplyContext.cpp b/src/xrpld/app/tx/detail/ApplyContext.cpp index 27287241637..969af7960eb 100644 --- a/src/xrpld/app/tx/detail/ApplyContext.cpp +++ b/src/xrpld/app/tx/detail/ApplyContext.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/tx/detail/ApplyContext.h b/src/xrpld/app/tx/detail/ApplyContext.h index 415054ef4bb..45de05a73db 100644 --- a/src/xrpld/app/tx/detail/ApplyContext.h +++ b/src/xrpld/app/tx/detail/ApplyContext.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_TX_APPLYCONTEXT_H_INCLUDED #define RIPPLE_TX_APPLYCONTEXT_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/tx/detail/BookTip.cpp b/src/xrpld/app/tx/detail/BookTip.cpp index 88bfd1d516c..011d992dd72 100644 --- a/src/xrpld/app/tx/detail/BookTip.cpp +++ b/src/xrpld/app/tx/detail/BookTip.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/BookTip.h b/src/xrpld/app/tx/detail/BookTip.h index d57700ad4f8..4de6b785b90 100644 --- a/src/xrpld/app/tx/detail/BookTip.h +++ b/src/xrpld/app/tx/detail/BookTip.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_APP_BOOK_BOOKTIP_H_INCLUDED #define RIPPLE_APP_BOOK_BOOKTIP_H_INCLUDED -#include -#include -#include +#include +#include +#include #include diff --git a/src/xrpld/app/tx/detail/CancelCheck.cpp b/src/xrpld/app/tx/detail/CancelCheck.cpp index 5e7050d86a3..7954e86cf3b 100644 --- a/src/xrpld/app/tx/detail/CancelCheck.cpp +++ b/src/xrpld/app/tx/detail/CancelCheck.cpp @@ -17,16 +17,16 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/CancelCheck.h b/src/xrpld/app/tx/detail/CancelCheck.h index a7e0f6e5d93..582d8559e50 100644 --- a/src/xrpld/app/tx/detail/CancelCheck.h +++ b/src/xrpld/app/tx/detail/CancelCheck.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_CANCELCHECK_H_INCLUDED #define RIPPLE_TX_CANCELCHECK_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/CancelOffer.cpp b/src/xrpld/app/tx/detail/CancelOffer.cpp index 95d51501cb9..11b07f06df3 100644 --- a/src/xrpld/app/tx/detail/CancelOffer.cpp +++ b/src/xrpld/app/tx/detail/CancelOffer.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/CancelOffer.h b/src/xrpld/app/tx/detail/CancelOffer.h index 32aee335375..1e3b4a5c983 100644 --- a/src/xrpld/app/tx/detail/CancelOffer.h +++ b/src/xrpld/app/tx/detail/CancelOffer.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_TX_CANCELOFFER_H_INCLUDED #define RIPPLE_TX_CANCELOFFER_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/CashCheck.cpp b/src/xrpld/app/tx/detail/CashCheck.cpp index bc3d838540b..8b5ef79b6d4 100644 --- a/src/xrpld/app/tx/detail/CashCheck.cpp +++ b/src/xrpld/app/tx/detail/CashCheck.cpp @@ -17,16 +17,16 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/tx/detail/CashCheck.h b/src/xrpld/app/tx/detail/CashCheck.h index 3acc3204a3d..c90cd93a9f8 100644 --- a/src/xrpld/app/tx/detail/CashCheck.h +++ b/src/xrpld/app/tx/detail/CashCheck.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_CASHCHECK_H_INCLUDED #define RIPPLE_TX_CASHCHECK_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/Change.cpp b/src/xrpld/app/tx/detail/Change.cpp index b36ae88a75e..0ebdb1e93ba 100644 --- a/src/xrpld/app/tx/detail/Change.cpp +++ b/src/xrpld/app/tx/detail/Change.cpp @@ -17,16 +17,16 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/tx/detail/Change.h b/src/xrpld/app/tx/detail/Change.h index f366a5754ce..7a569bc920e 100644 --- a/src/xrpld/app/tx/detail/Change.h +++ b/src/xrpld/app/tx/detail/Change.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_TX_CHANGE_H_INCLUDED #define RIPPLE_TX_CHANGE_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/Clawback.cpp b/src/xrpld/app/tx/detail/Clawback.cpp index 58546db5ca7..15d76526094 100644 --- a/src/xrpld/app/tx/detail/Clawback.cpp +++ b/src/xrpld/app/tx/detail/Clawback.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/Clawback.h b/src/xrpld/app/tx/detail/Clawback.h index c5f072c8463..d908a2e4ef2 100644 --- a/src/xrpld/app/tx/detail/Clawback.h +++ b/src/xrpld/app/tx/detail/Clawback.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_CLAWBACK_H_INCLUDED #define RIPPLE_TX_CLAWBACK_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/CreateCheck.cpp b/src/xrpld/app/tx/detail/CreateCheck.cpp index 77ce4d017a1..3a278eed738 100644 --- a/src/xrpld/app/tx/detail/CreateCheck.cpp +++ b/src/xrpld/app/tx/detail/CreateCheck.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/CreateCheck.h b/src/xrpld/app/tx/detail/CreateCheck.h index 537b230eb46..86daad07061 100644 --- a/src/xrpld/app/tx/detail/CreateCheck.h +++ b/src/xrpld/app/tx/detail/CreateCheck.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_CREATECHECK_H_INCLUDED #define RIPPLE_TX_CREATECHECK_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/CreateOffer.cpp b/src/xrpld/app/tx/detail/CreateOffer.cpp index 17f7e2853db..2a5145594a1 100644 --- a/src/xrpld/app/tx/detail/CreateOffer.cpp +++ b/src/xrpld/app/tx/detail/CreateOffer.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/CreateOffer.h b/src/xrpld/app/tx/detail/CreateOffer.h index 597ee22c0d9..47129df5b04 100644 --- a/src/xrpld/app/tx/detail/CreateOffer.h +++ b/src/xrpld/app/tx/detail/CreateOffer.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_TX_CREATEOFFER_H_INCLUDED #define RIPPLE_TX_CREATEOFFER_H_INCLUDED -#include -#include -#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/tx/detail/CreateTicket.cpp b/src/xrpld/app/tx/detail/CreateTicket.cpp index a901231822c..b04f4af1d30 100644 --- a/src/xrpld/app/tx/detail/CreateTicket.cpp +++ b/src/xrpld/app/tx/detail/CreateTicket.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/CreateTicket.h b/src/xrpld/app/tx/detail/CreateTicket.h index c1909ddf724..edfcaa787c9 100644 --- a/src/xrpld/app/tx/detail/CreateTicket.h +++ b/src/xrpld/app/tx/detail/CreateTicket.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_TX_CREATETICKET_H_INCLUDED #define RIPPLE_TX_CREATETICKET_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/DID.cpp b/src/xrpld/app/tx/detail/DID.cpp index 1cad8992ad9..6e5a3108c72 100644 --- a/src/xrpld/app/tx/detail/DID.cpp +++ b/src/xrpld/app/tx/detail/DID.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/DID.h b/src/xrpld/app/tx/detail/DID.h index 13d5a261542..54ae6630f2e 100644 --- a/src/xrpld/app/tx/detail/DID.h +++ b/src/xrpld/app/tx/detail/DID.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_DID_H_INCLUDED #define RIPPLE_TX_DID_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/DeleteAccount.cpp b/src/xrpld/app/tx/detail/DeleteAccount.cpp index efa38a4b74e..fb2f3fc507f 100644 --- a/src/xrpld/app/tx/detail/DeleteAccount.cpp +++ b/src/xrpld/app/tx/detail/DeleteAccount.cpp @@ -17,21 +17,21 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/DeleteAccount.h b/src/xrpld/app/tx/detail/DeleteAccount.h index 0f298bb8596..e1da2f45964 100644 --- a/src/xrpld/app/tx/detail/DeleteAccount.h +++ b/src/xrpld/app/tx/detail/DeleteAccount.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_TX_DELETEACCOUNT_H_INCLUDED #define RIPPLE_TX_DELETEACCOUNT_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/DeleteOracle.cpp b/src/xrpld/app/tx/detail/DeleteOracle.cpp index 9331daee97d..807e52ee6b4 100644 --- a/src/xrpld/app/tx/detail/DeleteOracle.cpp +++ b/src/xrpld/app/tx/detail/DeleteOracle.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/DeleteOracle.h b/src/xrpld/app/tx/detail/DeleteOracle.h index e578adaaaf0..8f1402563a2 100644 --- a/src/xrpld/app/tx/detail/DeleteOracle.h +++ b/src/xrpld/app/tx/detail/DeleteOracle.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_DELETEORACLE_H_INCLUDED #define RIPPLE_TX_DELETEORACLE_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/DepositPreauth.cpp b/src/xrpld/app/tx/detail/DepositPreauth.cpp index 7d99e63017a..b60fd3e0eae 100644 --- a/src/xrpld/app/tx/detail/DepositPreauth.cpp +++ b/src/xrpld/app/tx/detail/DepositPreauth.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/DepositPreauth.h b/src/xrpld/app/tx/detail/DepositPreauth.h index 8111c215602..5edcee104d0 100644 --- a/src/xrpld/app/tx/detail/DepositPreauth.h +++ b/src/xrpld/app/tx/detail/DepositPreauth.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_DEPOSIT_PREAUTH_H_INCLUDED #define RIPPLE_TX_DEPOSIT_PREAUTH_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/Escrow.cpp b/src/xrpld/app/tx/detail/Escrow.cpp index 9d8aa6a2289..e34b675998d 100644 --- a/src/xrpld/app/tx/detail/Escrow.cpp +++ b/src/xrpld/app/tx/detail/Escrow.cpp @@ -17,22 +17,22 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // During an EscrowFinish, the transaction must specify both // a condition and a fulfillment. We track whether that diff --git a/src/xrpld/app/tx/detail/Escrow.h b/src/xrpld/app/tx/detail/Escrow.h index 0f5fd940144..9e30da76175 100644 --- a/src/xrpld/app/tx/detail/Escrow.h +++ b/src/xrpld/app/tx/detail/Escrow.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_ESCROW_H_INCLUDED #define RIPPLE_TX_ESCROW_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/InvariantCheck.cpp b/src/xrpld/app/tx/detail/InvariantCheck.cpp index c0ef5bbf0c5..d1d5890bec3 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.cpp +++ b/src/xrpld/app/tx/detail/InvariantCheck.cpp @@ -17,18 +17,18 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/InvariantCheck.h b/src/xrpld/app/tx/detail/InvariantCheck.h index eb606c2ed3b..ef89569cb7c 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.h +++ b/src/xrpld/app/tx/detail/InvariantCheck.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_APP_TX_INVARIANTCHECK_H_INCLUDED #define RIPPLE_APP_TX_INVARIANTCHECK_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/tx/detail/NFTokenAcceptOffer.cpp b/src/xrpld/app/tx/detail/NFTokenAcceptOffer.cpp index 0b61799ac35..b884a791e78 100644 --- a/src/xrpld/app/tx/detail/NFTokenAcceptOffer.cpp +++ b/src/xrpld/app/tx/detail/NFTokenAcceptOffer.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/NFTokenAcceptOffer.h b/src/xrpld/app/tx/detail/NFTokenAcceptOffer.h index e1b26cbecea..dff3febbb21 100644 --- a/src/xrpld/app/tx/detail/NFTokenAcceptOffer.h +++ b/src/xrpld/app/tx/detail/NFTokenAcceptOffer.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_NFTOKENACCEPTOFFER_H_INCLUDED #define RIPPLE_TX_NFTOKENACCEPTOFFER_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/NFTokenBurn.cpp b/src/xrpld/app/tx/detail/NFTokenBurn.cpp index 99acfd61dca..f43dda71f59 100644 --- a/src/xrpld/app/tx/detail/NFTokenBurn.cpp +++ b/src/xrpld/app/tx/detail/NFTokenBurn.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/tx/detail/NFTokenBurn.h b/src/xrpld/app/tx/detail/NFTokenBurn.h index 61079c4a49a..3f5296c217b 100644 --- a/src/xrpld/app/tx/detail/NFTokenBurn.h +++ b/src/xrpld/app/tx/detail/NFTokenBurn.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_BURNNFT_H_INCLUDED #define RIPPLE_TX_BURNNFT_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/NFTokenCancelOffer.cpp b/src/xrpld/app/tx/detail/NFTokenCancelOffer.cpp index 50199ace88b..ef66ceecd0c 100644 --- a/src/xrpld/app/tx/detail/NFTokenCancelOffer.cpp +++ b/src/xrpld/app/tx/detail/NFTokenCancelOffer.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/tx/detail/NFTokenCancelOffer.h b/src/xrpld/app/tx/detail/NFTokenCancelOffer.h index 752d33ac818..d460675711e 100644 --- a/src/xrpld/app/tx/detail/NFTokenCancelOffer.h +++ b/src/xrpld/app/tx/detail/NFTokenCancelOffer.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_NFTOKENCANCELOFFER_H_INCLUDED #define RIPPLE_TX_NFTOKENCANCELOFFER_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/NFTokenCreateOffer.cpp b/src/xrpld/app/tx/detail/NFTokenCreateOffer.cpp index e1a0e04aa52..43178d31b4a 100644 --- a/src/xrpld/app/tx/detail/NFTokenCreateOffer.cpp +++ b/src/xrpld/app/tx/detail/NFTokenCreateOffer.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/tx/detail/NFTokenCreateOffer.h b/src/xrpld/app/tx/detail/NFTokenCreateOffer.h index 676b546f4b9..075a5a712fd 100644 --- a/src/xrpld/app/tx/detail/NFTokenCreateOffer.h +++ b/src/xrpld/app/tx/detail/NFTokenCreateOffer.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_NFTOKENOFFERCREATE_H_INCLUDED #define RIPPLE_TX_NFTOKENOFFERCREATE_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/NFTokenMint.cpp b/src/xrpld/app/tx/detail/NFTokenMint.cpp index daffd29ed31..d5c3a8707c2 100644 --- a/src/xrpld/app/tx/detail/NFTokenMint.cpp +++ b/src/xrpld/app/tx/detail/NFTokenMint.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/tx/detail/NFTokenMint.h b/src/xrpld/app/tx/detail/NFTokenMint.h index 690843c19ce..e0eb54bbc93 100644 --- a/src/xrpld/app/tx/detail/NFTokenMint.h +++ b/src/xrpld/app/tx/detail/NFTokenMint.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_TX_NFTTOKENMINT_H_INCLUDED #define RIPPLE_TX_NFTTOKENMINT_H_INCLUDED -#include -#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/NFTokenUtils.cpp b/src/xrpld/app/tx/detail/NFTokenUtils.cpp index 4acc00f956e..b2ed29714df 100644 --- a/src/xrpld/app/tx/detail/NFTokenUtils.cpp +++ b/src/xrpld/app/tx/detail/NFTokenUtils.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/tx/detail/NFTokenUtils.h b/src/xrpld/app/tx/detail/NFTokenUtils.h index 48ed3993357..243c5273399 100644 --- a/src/xrpld/app/tx/detail/NFTokenUtils.h +++ b/src/xrpld/app/tx/detail/NFTokenUtils.h @@ -20,13 +20,13 @@ #ifndef RIPPLE_TX_IMPL_DETAILS_NFTOKENUTILS_H_INCLUDED #define RIPPLE_TX_IMPL_DETAILS_NFTOKENUTILS_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/Offer.h b/src/xrpld/app/tx/detail/Offer.h index 53253426c40..a6f707ba561 100644 --- a/src/xrpld/app/tx/detail/Offer.h +++ b/src/xrpld/app/tx/detail/Offer.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_APP_BOOK_OFFER_H_INCLUDED #define RIPPLE_APP_BOOK_OFFER_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/tx/detail/OfferStream.cpp b/src/xrpld/app/tx/detail/OfferStream.cpp index 5933d9c3838..b963195259a 100644 --- a/src/xrpld/app/tx/detail/OfferStream.cpp +++ b/src/xrpld/app/tx/detail/OfferStream.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/OfferStream.h b/src/xrpld/app/tx/detail/OfferStream.h index 9472bc4e74d..be224a67b4e 100644 --- a/src/xrpld/app/tx/detail/OfferStream.h +++ b/src/xrpld/app/tx/detail/OfferStream.h @@ -20,13 +20,13 @@ #ifndef RIPPLE_APP_BOOK_OFFERSTREAM_H_INCLUDED #define RIPPLE_APP_BOOK_OFFERSTREAM_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/app/tx/detail/PayChan.cpp b/src/xrpld/app/tx/detail/PayChan.cpp index 3fe2a28a7cf..d17736c4738 100644 --- a/src/xrpld/app/tx/detail/PayChan.cpp +++ b/src/xrpld/app/tx/detail/PayChan.cpp @@ -17,19 +17,19 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/PayChan.h b/src/xrpld/app/tx/detail/PayChan.h index 9fe4b841944..8bb3a6d9379 100644 --- a/src/xrpld/app/tx/detail/PayChan.h +++ b/src/xrpld/app/tx/detail/PayChan.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_PAYCHAN_H_INCLUDED #define RIPPLE_TX_PAYCHAN_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/Payment.cpp b/src/xrpld/app/tx/detail/Payment.cpp index 3903aa75045..309e9d4a498 100644 --- a/src/xrpld/app/tx/detail/Payment.cpp +++ b/src/xrpld/app/tx/detail/Payment.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/Payment.h b/src/xrpld/app/tx/detail/Payment.h index 1d4711198b9..3176ae1c0d3 100644 --- a/src/xrpld/app/tx/detail/Payment.h +++ b/src/xrpld/app/tx/detail/Payment.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_TX_PAYMENT_H_INCLUDED #define RIPPLE_TX_PAYMENT_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/SetAccount.cpp b/src/xrpld/app/tx/detail/SetAccount.cpp index d43b3b339e5..c0e115c2497 100644 --- a/src/xrpld/app/tx/detail/SetAccount.cpp +++ b/src/xrpld/app/tx/detail/SetAccount.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/SetAccount.h b/src/xrpld/app/tx/detail/SetAccount.h index 1c6bb4b7d80..8e9b74d860b 100644 --- a/src/xrpld/app/tx/detail/SetAccount.h +++ b/src/xrpld/app/tx/detail/SetAccount.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_TX_SETACCOUNT_H_INCLUDED #define RIPPLE_TX_SETACCOUNT_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/SetOracle.cpp b/src/xrpld/app/tx/detail/SetOracle.cpp index d0987d26538..055143cc6fd 100644 --- a/src/xrpld/app/tx/detail/SetOracle.cpp +++ b/src/xrpld/app/tx/detail/SetOracle.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/SetOracle.h b/src/xrpld/app/tx/detail/SetOracle.h index 0ab8e603aa5..13c4d7a0cc9 100644 --- a/src/xrpld/app/tx/detail/SetOracle.h +++ b/src/xrpld/app/tx/detail/SetOracle.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_TX_SETORACLE_H_INCLUDED #define RIPPLE_TX_SETORACLE_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/SetRegularKey.cpp b/src/xrpld/app/tx/detail/SetRegularKey.cpp index 8b789d75aed..9f165612f3a 100644 --- a/src/xrpld/app/tx/detail/SetRegularKey.cpp +++ b/src/xrpld/app/tx/detail/SetRegularKey.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/SetRegularKey.h b/src/xrpld/app/tx/detail/SetRegularKey.h index 402ee436ed5..89a714342ff 100644 --- a/src/xrpld/app/tx/detail/SetRegularKey.h +++ b/src/xrpld/app/tx/detail/SetRegularKey.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_TX_SETREGULARKEY_H_INCLUDED #define RIPPLE_TX_SETREGULARKEY_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/SetSignerList.cpp b/src/xrpld/app/tx/detail/SetSignerList.cpp index 07cc705bad1..37790f14f40 100644 --- a/src/xrpld/app/tx/detail/SetSignerList.cpp +++ b/src/xrpld/app/tx/detail/SetSignerList.cpp @@ -17,16 +17,16 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/tx/detail/SetSignerList.h b/src/xrpld/app/tx/detail/SetSignerList.h index f8e49e4a7b0..c2006945eca 100644 --- a/src/xrpld/app/tx/detail/SetSignerList.h +++ b/src/xrpld/app/tx/detail/SetSignerList.h @@ -20,15 +20,15 @@ #ifndef RIPPLE_TX_SETSIGNERLIST_H_INCLUDED #define RIPPLE_TX_SETSIGNERLIST_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/app/tx/detail/SetTrust.cpp b/src/xrpld/app/tx/detail/SetTrust.cpp index 00a5165221e..3a7fe9cca0d 100644 --- a/src/xrpld/app/tx/detail/SetTrust.cpp +++ b/src/xrpld/app/tx/detail/SetTrust.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/SetTrust.h b/src/xrpld/app/tx/detail/SetTrust.h index 259ed077412..a86c8498d48 100644 --- a/src/xrpld/app/tx/detail/SetTrust.h +++ b/src/xrpld/app/tx/detail/SetTrust.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_TX_SETTRUST_H_INCLUDED #define RIPPLE_TX_SETTRUST_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/SignerEntries.cpp b/src/xrpld/app/tx/detail/SignerEntries.cpp index a948b2f902b..f6a42120d11 100644 --- a/src/xrpld/app/tx/detail/SignerEntries.cpp +++ b/src/xrpld/app/tx/detail/SignerEntries.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/tx/detail/SignerEntries.h b/src/xrpld/app/tx/detail/SignerEntries.h index cf4921ecf4b..c64e106ae9e 100644 --- a/src/xrpld/app/tx/detail/SignerEntries.h +++ b/src/xrpld/app/tx/detail/SignerEntries.h @@ -20,13 +20,13 @@ #ifndef RIPPLE_TX_IMPL_SIGNER_ENTRIES_H_INCLUDED #define RIPPLE_TX_IMPL_SIGNER_ENTRIES_H_INCLUDED -#include // NotTEC -#include // -#include // beast::Journal -#include // Rules -#include // STTx::maxMultiSigners -#include // temMALFORMED -#include // AccountID +#include // NotTEC +#include // +#include // beast::Journal +#include // Rules +#include // STTx::maxMultiSigners +#include // temMALFORMED +#include // AccountID #include namespace ripple { diff --git a/src/xrpld/app/tx/detail/Taker.cpp b/src/xrpld/app/tx/detail/Taker.cpp index f463ce41198..9d335de2846 100644 --- a/src/xrpld/app/tx/detail/Taker.cpp +++ b/src/xrpld/app/tx/detail/Taker.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/Taker.h b/src/xrpld/app/tx/detail/Taker.h index 4a516dccec1..3e64c59b542 100644 --- a/src/xrpld/app/tx/detail/Taker.h +++ b/src/xrpld/app/tx/detail/Taker.h @@ -20,14 +20,14 @@ #ifndef RIPPLE_APP_BOOK_TAKER_H_INCLUDED #define RIPPLE_APP_BOOK_TAKER_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/app/tx/detail/Transactor.cpp b/src/xrpld/app/tx/detail/Transactor.cpp index c02b57a3ae4..42e9f0677ab 100644 --- a/src/xrpld/app/tx/detail/Transactor.cpp +++ b/src/xrpld/app/tx/detail/Transactor.cpp @@ -17,22 +17,22 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/Transactor.h b/src/xrpld/app/tx/detail/Transactor.h index cc280e6141d..27f22a0eb2e 100644 --- a/src/xrpld/app/tx/detail/Transactor.h +++ b/src/xrpld/app/tx/detail/Transactor.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_APP_TX_TRANSACTOR_H_INCLUDED #define RIPPLE_APP_TX_TRANSACTOR_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/XChainBridge.cpp b/src/xrpld/app/tx/detail/XChainBridge.cpp index be315236f2c..f5633903567 100644 --- a/src/xrpld/app/tx/detail/XChainBridge.cpp +++ b/src/xrpld/app/tx/detail/XChainBridge.cpp @@ -17,31 +17,31 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/app/tx/detail/XChainBridge.h b/src/xrpld/app/tx/detail/XChainBridge.h index 4d41c7d1c21..822f687729a 100644 --- a/src/xrpld/app/tx/detail/XChainBridge.h +++ b/src/xrpld/app/tx/detail/XChainBridge.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_TX_XCHAINBRIDGE_H_INCLUDED #define RIPPLE_TX_XCHAINBRIDGE_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/apply.cpp b/src/xrpld/app/tx/detail/apply.cpp index c0704c5c3ae..103ec041074 100644 --- a/src/xrpld/app/tx/detail/apply.cpp +++ b/src/xrpld/app/tx/detail/apply.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/applySteps.cpp b/src/xrpld/app/tx/detail/applySteps.cpp index 1a1fc343e3c..9ddaa3051c4 100644 --- a/src/xrpld/app/tx/detail/applySteps.cpp +++ b/src/xrpld/app/tx/detail/applySteps.cpp @@ -17,41 +17,41 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/conditions/Condition.h b/src/xrpld/conditions/Condition.h index 340b7c96124..a3120f1b3ca 100644 --- a/src/xrpld/conditions/Condition.h +++ b/src/xrpld/conditions/Condition.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_CONDITIONS_CONDITION_H #define RIPPLE_CONDITIONS_CONDITION_H -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/conditions/Fulfillment.h b/src/xrpld/conditions/Fulfillment.h index 075c005100c..e70bcf54d41 100644 --- a/src/xrpld/conditions/Fulfillment.h +++ b/src/xrpld/conditions/Fulfillment.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_CONDITIONS_FULFILLMENT_H #define RIPPLE_CONDITIONS_FULFILLMENT_H -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { namespace cryptoconditions { diff --git a/src/xrpld/conditions/detail/Condition.cpp b/src/xrpld/conditions/detail/Condition.cpp index 8a1d30916a1..3085ace0a31 100644 --- a/src/xrpld/conditions/detail/Condition.cpp +++ b/src/xrpld/conditions/detail/Condition.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/conditions/detail/Fulfillment.cpp b/src/xrpld/conditions/detail/Fulfillment.cpp index ff47e386469..285113ebfb2 100644 --- a/src/xrpld/conditions/detail/Fulfillment.cpp +++ b/src/xrpld/conditions/detail/Fulfillment.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/conditions/detail/PreimageSha256.h b/src/xrpld/conditions/detail/PreimageSha256.h index 316e57ac173..c0eca96b066 100644 --- a/src/xrpld/conditions/detail/PreimageSha256.h +++ b/src/xrpld/conditions/detail/PreimageSha256.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_CONDITIONS_PREIMAGE_SHA256_H #define RIPPLE_CONDITIONS_PREIMAGE_SHA256_H -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/conditions/detail/error.cpp b/src/xrpld/conditions/detail/error.cpp index f685a45899e..3594c9e14da 100644 --- a/src/xrpld/conditions/detail/error.cpp +++ b/src/xrpld/conditions/detail/error.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include #include diff --git a/src/xrpld/conditions/detail/utils.h b/src/xrpld/conditions/detail/utils.h index e9ab1770a18..35d9c7dea51 100644 --- a/src/xrpld/conditions/detail/utils.h +++ b/src/xrpld/conditions/detail/utils.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_CONDITIONS_UTILS_H #define RIPPLE_CONDITIONS_UTILS_H -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/consensus/Consensus.cpp b/src/xrpld/consensus/Consensus.cpp index cc1f84270e7..01451c6a255 100644 --- a/src/xrpld/consensus/Consensus.cpp +++ b/src/xrpld/consensus/Consensus.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { diff --git a/src/xrpld/consensus/Consensus.h b/src/xrpld/consensus/Consensus.h index 248bbdc4a1b..fd3560b1744 100644 --- a/src/xrpld/consensus/Consensus.h +++ b/src/xrpld/consensus/Consensus.h @@ -20,15 +20,15 @@ #ifndef RIPPLE_CONSENSUS_CONSENSUS_H_INCLUDED #define RIPPLE_CONSENSUS_CONSENSUS_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/consensus/ConsensusProposal.h b/src/xrpld/consensus/ConsensusProposal.h index c5103cfe0d5..c00bffe0237 100644 --- a/src/xrpld/consensus/ConsensusProposal.h +++ b/src/xrpld/consensus/ConsensusProposal.h @@ -19,11 +19,11 @@ #ifndef RIPPLE_CONSENSUS_CONSENSUSPROPOSAL_H_INCLUDED #define RIPPLE_CONSENSUS_CONSENSUSPROPOSAL_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/consensus/ConsensusTypes.h b/src/xrpld/consensus/ConsensusTypes.h index 05d03c8a9c6..da03fc4875a 100644 --- a/src/xrpld/consensus/ConsensusTypes.h +++ b/src/xrpld/consensus/ConsensusTypes.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_CONSENSUS_CONSENSUS_TYPES_H_INCLUDED #define RIPPLE_CONSENSUS_CONSENSUS_TYPES_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/xrpld/consensus/DisputedTx.h b/src/xrpld/consensus/DisputedTx.h index ae127197eec..bffb1009323 100644 --- a/src/xrpld/consensus/DisputedTx.h +++ b/src/xrpld/consensus/DisputedTx.h @@ -20,13 +20,13 @@ #ifndef RIPPLE_APP_CONSENSUS_IMPL_DISPUTEDTX_H_INCLUDED #define RIPPLE_APP_CONSENSUS_IMPL_DISPUTEDTX_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/consensus/LedgerTiming.h b/src/xrpld/consensus/LedgerTiming.h index 9320cf07de1..1bb5bfd730f 100644 --- a/src/xrpld/consensus/LedgerTiming.h +++ b/src/xrpld/consensus/LedgerTiming.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_APP_LEDGER_LEDGERTIMING_H_INCLUDED #define RIPPLE_APP_LEDGER_LEDGERTIMING_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/src/xrpld/consensus/LedgerTrie.h b/src/xrpld/consensus/LedgerTrie.h index 12cd0d3cbbc..32bae28cc07 100644 --- a/src/xrpld/consensus/LedgerTrie.h +++ b/src/xrpld/consensus/LedgerTrie.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_APP_CONSENSUS_LEDGERS_TRIE_H_INCLUDED #define RIPPLE_APP_CONSENSUS_LEDGERS_TRIE_H_INCLUDED -#include -#include +#include +#include #include #include #include diff --git a/src/xrpld/consensus/Validations.h b/src/xrpld/consensus/Validations.h index 1bef76d961c..ed07858d321 100644 --- a/src/xrpld/consensus/Validations.h +++ b/src/xrpld/consensus/Validations.h @@ -20,13 +20,13 @@ #ifndef RIPPLE_CONSENSUS_VALIDATIONS_H_INCLUDED #define RIPPLE_CONSENSUS_VALIDATIONS_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/core/ClosureCounter.h b/src/xrpld/core/ClosureCounter.h index 9f5bc3ee617..9b1a69bf95d 100644 --- a/src/xrpld/core/ClosureCounter.h +++ b/src/xrpld/core/ClosureCounter.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_CORE_CLOSURE_COUNTER_H_INCLUDED #define RIPPLE_CORE_CLOSURE_COUNTER_H_INCLUDED -#include +#include #include #include #include diff --git a/src/xrpld/core/Config.h b/src/xrpld/core/Config.h index 24b762cf8c5..2872193f0ee 100644 --- a/src/xrpld/core/Config.h +++ b/src/xrpld/core/Config.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_CORE_CONFIG_H_INCLUDED #define RIPPLE_CORE_CONFIG_H_INCLUDED -#include -#include -#include -#include -#include -#include // VFALCO Breaks levelization +#include +#include +#include +#include +#include +#include // VFALCO Breaks levelization #include #include // VFALCO FIX: This include should not be here diff --git a/src/xrpld/core/Coro.ipp b/src/xrpld/core/Coro.ipp index 2b07c5a4584..a936dd896ae 100644 --- a/src/xrpld/core/Coro.ipp +++ b/src/xrpld/core/Coro.ipp @@ -20,7 +20,7 @@ #ifndef RIPPLE_CORE_COROINL_H_INCLUDED #define RIPPLE_CORE_COROINL_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/core/DatabaseCon.h b/src/xrpld/core/DatabaseCon.h index 59eec3a32e9..d2f6b0a4f05 100644 --- a/src/xrpld/core/DatabaseCon.h +++ b/src/xrpld/core/DatabaseCon.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_APP_DATA_DATABASECON_H_INCLUDED #define RIPPLE_APP_DATA_DATABASECON_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/core/Job.h b/src/xrpld/core/Job.h index c4f2eddf35a..c5926ae2e08 100644 --- a/src/xrpld/core/Job.h +++ b/src/xrpld/core/Job.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_CORE_JOB_H_INCLUDED #define RIPPLE_CORE_JOB_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/xrpld/core/JobQueue.h b/src/xrpld/core/JobQueue.h index a9d541baa75..06f90dd1c4e 100644 --- a/src/xrpld/core/JobQueue.h +++ b/src/xrpld/core/JobQueue.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_CORE_JOBQUEUE_H_INCLUDED #define RIPPLE_CORE_JOBQUEUE_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include // workaround for boost 1.72 bug #include // workaround for boost 1.72 bug @@ -402,7 +402,7 @@ class JobQueue : private Workers::Callback } // namespace ripple -#include +#include namespace ripple { diff --git a/src/xrpld/core/JobTypeData.h b/src/xrpld/core/JobTypeData.h index 3f0cdb6e939..43d63895d8b 100644 --- a/src/xrpld/core/JobTypeData.h +++ b/src/xrpld/core/JobTypeData.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_CORE_JOBTYPEDATA_H_INCLUDED #define RIPPLE_CORE_JOBTYPEDATA_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/core/JobTypeInfo.h b/src/xrpld/core/JobTypeInfo.h index 7ed7c469711..a521980ebe8 100644 --- a/src/xrpld/core/JobTypeInfo.h +++ b/src/xrpld/core/JobTypeInfo.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_CORE_JOBTYPEINFO_H_INCLUDED #define RIPPLE_CORE_JOBTYPEINFO_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/core/JobTypes.h b/src/xrpld/core/JobTypes.h index 2803537f115..2dbc45ca1b5 100644 --- a/src/xrpld/core/JobTypes.h +++ b/src/xrpld/core/JobTypes.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_CORE_JOBTYPES_H_INCLUDED #define RIPPLE_CORE_JOBTYPES_H_INCLUDED -#include -#include +#include +#include #include #include #include diff --git a/src/xrpld/core/LoadMonitor.h b/src/xrpld/core/LoadMonitor.h index e903bf25e31..e57429da23b 100644 --- a/src/xrpld/core/LoadMonitor.h +++ b/src/xrpld/core/LoadMonitor.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_CORE_LOADMONITOR_H_INCLUDED #define RIPPLE_CORE_LOADMONITOR_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/xrpld/core/Pg.cpp b/src/xrpld/core/Pg.cpp index df0f6da5ef5..829e17658c1 100644 --- a/src/xrpld/core/Pg.cpp +++ b/src/xrpld/core/Pg.cpp @@ -29,8 +29,8 @@ #include #endif -#include -#include +#include +#include #include #include #include diff --git a/src/xrpld/core/Pg.h b/src/xrpld/core/Pg.h index b2e8f465c30..c1333ed66fb 100644 --- a/src/xrpld/core/Pg.h +++ b/src/xrpld/core/Pg.h @@ -21,9 +21,9 @@ #ifndef RIPPLE_CORE_PG_H_INCLUDED #define RIPPLE_CORE_PG_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/core/SociDB.h b/src/xrpld/core/SociDB.h index 621754098f8..20f210d4e38 100644 --- a/src/xrpld/core/SociDB.h +++ b/src/xrpld/core/SociDB.h @@ -33,8 +33,8 @@ #pragma clang diagnostic ignored "-Wdeprecated" #endif -#include -#include +#include +#include #define SOCI_USE_BOOST #include #include diff --git a/src/xrpld/core/TimeKeeper.h b/src/xrpld/core/TimeKeeper.h index e239a2f7565..f94a92a6666 100644 --- a/src/xrpld/core/TimeKeeper.h +++ b/src/xrpld/core/TimeKeeper.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_CORE_TIMEKEEPER_H_INCLUDED #define RIPPLE_CORE_TIMEKEEPER_H_INCLUDED -#include -#include +#include +#include #include diff --git a/src/xrpld/core/detail/Config.cpp b/src/xrpld/core/detail/Config.cpp index 2f26b8ba525..07d269883e2 100644 --- a/src/xrpld/core/detail/Config.cpp +++ b/src/xrpld/core/detail/Config.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/core/detail/DatabaseCon.cpp b/src/xrpld/core/detail/DatabaseCon.cpp index 4f65f7003f6..c23c7491b04 100644 --- a/src/xrpld/core/detail/DatabaseCon.cpp +++ b/src/xrpld/core/detail/DatabaseCon.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/core/detail/Job.cpp b/src/xrpld/core/detail/Job.cpp index 780a9f49cdf..0782fd05a66 100644 --- a/src/xrpld/core/detail/Job.cpp +++ b/src/xrpld/core/detail/Job.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/core/detail/JobQueue.cpp b/src/xrpld/core/detail/JobQueue.cpp index 28947300cc6..1c859d724f4 100644 --- a/src/xrpld/core/detail/JobQueue.cpp +++ b/src/xrpld/core/detail/JobQueue.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/core/detail/LoadEvent.cpp b/src/xrpld/core/detail/LoadEvent.cpp index 38617e7f541..ca78fdb19cc 100644 --- a/src/xrpld/core/detail/LoadEvent.cpp +++ b/src/xrpld/core/detail/LoadEvent.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include diff --git a/src/xrpld/core/detail/LoadMonitor.cpp b/src/xrpld/core/detail/LoadMonitor.cpp index e70b7947a32..80b08bbdfc3 100644 --- a/src/xrpld/core/detail/LoadMonitor.cpp +++ b/src/xrpld/core/detail/LoadMonitor.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/core/detail/SociDB.cpp b/src/xrpld/core/detail/SociDB.cpp index 2d133263607..94f9098d9c0 100644 --- a/src/xrpld/core/detail/SociDB.cpp +++ b/src/xrpld/core/detail/SociDB.cpp @@ -22,12 +22,12 @@ #pragma clang diagnostic ignored "-Wdeprecated" #endif -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/core/detail/Workers.cpp b/src/xrpld/core/detail/Workers.cpp index 732e6f0ec8a..ff861010d95 100644 --- a/src/xrpld/core/detail/Workers.cpp +++ b/src/xrpld/core/detail/Workers.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/core/detail/Workers.h b/src/xrpld/core/detail/Workers.h index 88ab8fa27e2..3645d4fbcf0 100644 --- a/src/xrpld/core/detail/Workers.h +++ b/src/xrpld/core/detail/Workers.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_CORE_WORKERS_H_INCLUDED #define RIPPLE_CORE_WORKERS_H_INCLUDED -#include -#include +#include +#include #include #include #include diff --git a/src/xrpld/ledger/ApplyView.h b/src/xrpld/ledger/ApplyView.h index a37ba6c46a1..f0166cd0b38 100644 --- a/src/xrpld/ledger/ApplyView.h +++ b/src/xrpld/ledger/ApplyView.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_LEDGER_APPLYVIEW_H_INCLUDED #define RIPPLE_LEDGER_APPLYVIEW_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/ledger/ApplyViewImpl.h b/src/xrpld/ledger/ApplyViewImpl.h index a7fb1bd426b..65678c5a6c4 100644 --- a/src/xrpld/ledger/ApplyViewImpl.h +++ b/src/xrpld/ledger/ApplyViewImpl.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_LEDGER_APPLYVIEWIMPL_H_INCLUDED #define RIPPLE_LEDGER_APPLYVIEWIMPL_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/ledger/BookDirs.h b/src/xrpld/ledger/BookDirs.h index 86ea67d9166..2c27a5b6596 100644 --- a/src/xrpld/ledger/BookDirs.h +++ b/src/xrpld/ledger/BookDirs.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_LEDGER_BOOK_DIRS_H_INCLUDED #define RIPPLE_LEDGER_BOOK_DIRS_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/ledger/CachedSLEs.h b/src/xrpld/ledger/CachedSLEs.h index d2b04e2cb5c..bc94092e20d 100644 --- a/src/xrpld/ledger/CachedSLEs.h +++ b/src/xrpld/ledger/CachedSLEs.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_LEDGER_CACHEDSLES_H_INCLUDED #define RIPPLE_LEDGER_CACHEDSLES_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { using CachedSLEs = TaggedCache; diff --git a/src/xrpld/ledger/CachedView.h b/src/xrpld/ledger/CachedView.h index da483b34948..fd921c63ca9 100644 --- a/src/xrpld/ledger/CachedView.h +++ b/src/xrpld/ledger/CachedView.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_LEDGER_CACHEDVIEW_H_INCLUDED #define RIPPLE_LEDGER_CACHEDVIEW_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/ledger/Directory.h b/src/xrpld/ledger/Directory.h index 0efcf43e773..cc8b3c13a3a 100644 --- a/src/xrpld/ledger/Directory.h +++ b/src/xrpld/ledger/Directory.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_LEDGER_DIR_H_INCLUDED #define RIPPLE_LEDGER_DIR_H_INCLUDED -#include -#include +#include +#include namespace ripple { diff --git a/src/xrpld/ledger/OpenView.h b/src/xrpld/ledger/OpenView.h index 98b783e3a48..bd8627a18b2 100644 --- a/src/xrpld/ledger/OpenView.h +++ b/src/xrpld/ledger/OpenView.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_LEDGER_OPENVIEW_H_INCLUDED #define RIPPLE_LEDGER_OPENVIEW_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/ledger/PaymentSandbox.h b/src/xrpld/ledger/PaymentSandbox.h index 60e42af1147..d7299b2efbf 100644 --- a/src/xrpld/ledger/PaymentSandbox.h +++ b/src/xrpld/ledger/PaymentSandbox.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_LEDGER_PAYMENTSANDBOX_H_INCLUDED #define RIPPLE_LEDGER_PAYMENTSANDBOX_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/ledger/RawView.h b/src/xrpld/ledger/RawView.h index 29c9ab9abb9..cd9bcff8761 100644 --- a/src/xrpld/ledger/RawView.h +++ b/src/xrpld/ledger/RawView.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_LEDGER_RAWVIEW_H_INCLUDED #define RIPPLE_LEDGER_RAWVIEW_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/ledger/ReadView.h b/src/xrpld/ledger/ReadView.h index 2ea3ab492ed..50f1a7d98c1 100644 --- a/src/xrpld/ledger/ReadView.h +++ b/src/xrpld/ledger/ReadView.h @@ -20,21 +20,21 @@ #ifndef RIPPLE_LEDGER_READVIEW_H_INCLUDED #define RIPPLE_LEDGER_READVIEW_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -283,6 +283,6 @@ makeRulesGivenLedger( } // namespace ripple -#include +#include #endif diff --git a/src/xrpld/ledger/Sandbox.h b/src/xrpld/ledger/Sandbox.h index d8610a69ef1..22b8dbecfb2 100644 --- a/src/xrpld/ledger/Sandbox.h +++ b/src/xrpld/ledger/Sandbox.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_LEDGER_SANDBOX_H_INCLUDED #define RIPPLE_LEDGER_SANDBOX_H_INCLUDED -#include -#include +#include +#include namespace ripple { diff --git a/src/xrpld/ledger/View.h b/src/xrpld/ledger/View.h index 5680114a79c..09f374d2c29 100644 --- a/src/xrpld/ledger/View.h +++ b/src/xrpld/ledger/View.h @@ -20,19 +20,19 @@ #ifndef RIPPLE_LEDGER_VIEW_H_INCLUDED #define RIPPLE_LEDGER_VIEW_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/ledger/detail/ApplyStateTable.cpp b/src/xrpld/ledger/detail/ApplyStateTable.cpp index ab2f0ca8cdb..b849365c83f 100644 --- a/src/xrpld/ledger/detail/ApplyStateTable.cpp +++ b/src/xrpld/ledger/detail/ApplyStateTable.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/ledger/detail/ApplyStateTable.h b/src/xrpld/ledger/detail/ApplyStateTable.h index 3fbc4960973..d1616d095e5 100644 --- a/src/xrpld/ledger/detail/ApplyStateTable.h +++ b/src/xrpld/ledger/detail/ApplyStateTable.h @@ -20,13 +20,13 @@ #ifndef RIPPLE_LEDGER_APPLYSTATETABLE_H_INCLUDED #define RIPPLE_LEDGER_APPLYSTATETABLE_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/ledger/detail/ApplyView.cpp b/src/xrpld/ledger/detail/ApplyView.cpp index 53dc073c33d..735aa9906e0 100644 --- a/src/xrpld/ledger/detail/ApplyView.cpp +++ b/src/xrpld/ledger/detail/ApplyView.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/ledger/detail/ApplyViewBase.cpp b/src/xrpld/ledger/detail/ApplyViewBase.cpp index ac87aabb47f..647927ae965 100644 --- a/src/xrpld/ledger/detail/ApplyViewBase.cpp +++ b/src/xrpld/ledger/detail/ApplyViewBase.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { namespace detail { diff --git a/src/xrpld/ledger/detail/ApplyViewBase.h b/src/xrpld/ledger/detail/ApplyViewBase.h index 68c210c7b71..8305731b29e 100644 --- a/src/xrpld/ledger/detail/ApplyViewBase.h +++ b/src/xrpld/ledger/detail/ApplyViewBase.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_LEDGER_APPLYVIEWBASE_H_INCLUDED #define RIPPLE_LEDGER_APPLYVIEWBASE_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { namespace detail { diff --git a/src/xrpld/ledger/detail/ApplyViewImpl.cpp b/src/xrpld/ledger/detail/ApplyViewImpl.cpp index 155ff4df99f..ffbf681cd20 100644 --- a/src/xrpld/ledger/detail/ApplyViewImpl.cpp +++ b/src/xrpld/ledger/detail/ApplyViewImpl.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/ledger/detail/BookDirs.cpp b/src/xrpld/ledger/detail/BookDirs.cpp index f8589d5575c..58527b02ff2 100644 --- a/src/xrpld/ledger/detail/BookDirs.cpp +++ b/src/xrpld/ledger/detail/BookDirs.cpp @@ -18,9 +18,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/ledger/detail/CachedView.cpp b/src/xrpld/ledger/detail/CachedView.cpp index 210031346d3..5502c40e6d5 100644 --- a/src/xrpld/ledger/detail/CachedView.cpp +++ b/src/xrpld/ledger/detail/CachedView.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include namespace ripple { namespace detail { diff --git a/src/xrpld/ledger/detail/Directory.cpp b/src/xrpld/ledger/detail/Directory.cpp index 759b4d71b74..9153d013fd8 100644 --- a/src/xrpld/ledger/detail/Directory.cpp +++ b/src/xrpld/ledger/detail/Directory.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/xrpld/ledger/detail/OpenView.cpp b/src/xrpld/ledger/detail/OpenView.cpp index 67858ad5667..619006161f8 100644 --- a/src/xrpld/ledger/detail/OpenView.cpp +++ b/src/xrpld/ledger/detail/OpenView.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { diff --git a/src/xrpld/ledger/detail/PaymentSandbox.cpp b/src/xrpld/ledger/detail/PaymentSandbox.cpp index 45a57cd30d6..d182d22b56c 100644 --- a/src/xrpld/ledger/detail/PaymentSandbox.cpp +++ b/src/xrpld/ledger/detail/PaymentSandbox.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/ledger/detail/RawStateTable.cpp b/src/xrpld/ledger/detail/RawStateTable.cpp index 019ef6156c2..4d3732f8a45 100644 --- a/src/xrpld/ledger/detail/RawStateTable.cpp +++ b/src/xrpld/ledger/detail/RawStateTable.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { namespace detail { diff --git a/src/xrpld/ledger/detail/RawStateTable.h b/src/xrpld/ledger/detail/RawStateTable.h index 2bb38dc49d8..2db37d98333 100644 --- a/src/xrpld/ledger/detail/RawStateTable.h +++ b/src/xrpld/ledger/detail/RawStateTable.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_LEDGER_RAWSTATETABLE_H_INCLUDED #define RIPPLE_LEDGER_RAWSTATETABLE_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/src/xrpld/ledger/detail/ReadView.cpp b/src/xrpld/ledger/detail/ReadView.cpp index 1ce21777297..69a4b5d6a95 100644 --- a/src/xrpld/ledger/detail/ReadView.cpp +++ b/src/xrpld/ledger/detail/ReadView.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/xrpld/ledger/detail/View.cpp b/src/xrpld/ledger/detail/View.cpp index b71b4f39e5e..13ac07e5e74 100644 --- a/src/xrpld/ledger/detail/View.cpp +++ b/src/xrpld/ledger/detail/View.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/net/AutoSocket.h b/src/xrpld/net/AutoSocket.h index e64c7a1e5cf..be35c082461 100644 --- a/src/xrpld/net/AutoSocket.h +++ b/src/xrpld/net/AutoSocket.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_WEBSOCKET_AUTOSOCKET_AUTOSOCKET_H_INCLUDED #define RIPPLE_WEBSOCKET_AUTOSOCKET_AUTOSOCKET_H_INCLUDED -#include -#include +#include +#include #include #include #include diff --git a/src/xrpld/net/DatabaseBody.h b/src/xrpld/net/DatabaseBody.h index c828e5bf123..15780ced313 100644 --- a/src/xrpld/net/DatabaseBody.h +++ b/src/xrpld/net/DatabaseBody.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_NET_DATABASEBODY_H #define RIPPLE_NET_DATABASEBODY_H -#include +#include #include #include #include @@ -174,6 +174,6 @@ class DatabaseBody::reader } // namespace ripple -#include +#include #endif // RIPPLE_NET_DATABASEBODY_H diff --git a/src/xrpld/net/DatabaseDownloader.h b/src/xrpld/net/DatabaseDownloader.h index 3e920909417..490e7c62e16 100644 --- a/src/xrpld/net/DatabaseDownloader.h +++ b/src/xrpld/net/DatabaseDownloader.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_NET_DATABASEDOWNLOADER_H #define RIPPLE_NET_DATABASEDOWNLOADER_H -#include -#include +#include +#include namespace ripple { diff --git a/src/xrpld/net/HTTPClient.h b/src/xrpld/net/HTTPClient.h index f133e3ee04a..3b7da776ea4 100644 --- a/src/xrpld/net/HTTPClient.h +++ b/src/xrpld/net/HTTPClient.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_NET_HTTPCLIENT_H_INCLUDED #define RIPPLE_NET_HTTPCLIENT_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/src/xrpld/net/HTTPClientSSLContext.h b/src/xrpld/net/HTTPClientSSLContext.h index b0f6942ae13..64ca2461d23 100644 --- a/src/xrpld/net/HTTPClientSSLContext.h +++ b/src/xrpld/net/HTTPClientSSLContext.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_NET_HTTPCLIENTSSLCONTEXT_H_INCLUDED #define RIPPLE_NET_HTTPCLIENTSSLCONTEXT_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/net/HTTPDownloader.h b/src/xrpld/net/HTTPDownloader.h index 39b9a904aa3..f96fb8e572b 100644 --- a/src/xrpld/net/HTTPDownloader.h +++ b/src/xrpld/net/HTTPDownloader.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_NET_HTTPDOWNLOADER_H_INCLUDED #define RIPPLE_NET_HTTPDOWNLOADER_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/xrpld/net/HTTPStream.h b/src/xrpld/net/HTTPStream.h index f5aaaa48a81..275d8ca9544 100644 --- a/src/xrpld/net/HTTPStream.h +++ b/src/xrpld/net/HTTPStream.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_NET_HTTPSTREAM_H_INCLUDED #define RIPPLE_NET_HTTPSTREAM_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/src/xrpld/net/InfoSub.h b/src/xrpld/net/InfoSub.h index 33441dde632..08fba26ff00 100644 --- a/src/xrpld/net/InfoSub.h +++ b/src/xrpld/net/InfoSub.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_NET_INFOSUB_H_INCLUDED #define RIPPLE_NET_INFOSUB_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/net/RPCCall.h b/src/xrpld/net/RPCCall.h index 600fad28e58..9c78bb20d25 100644 --- a/src/xrpld/net/RPCCall.h +++ b/src/xrpld/net/RPCCall.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_NET_RPCCALL_H_INCLUDED #define RIPPLE_NET_RPCCALL_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/net/RPCSub.h b/src/xrpld/net/RPCSub.h index e2193b1ce1a..b2a751d4a19 100644 --- a/src/xrpld/net/RPCSub.h +++ b/src/xrpld/net/RPCSub.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_NET_RPCSUB_H_INCLUDED #define RIPPLE_NET_RPCSUB_H_INCLUDED -#include -#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/net/RegisterSSLCerts.h b/src/xrpld/net/RegisterSSLCerts.h index 8b09f1031d7..88664139f19 100644 --- a/src/xrpld/net/RegisterSSLCerts.h +++ b/src/xrpld/net/RegisterSSLCerts.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_NET_REGISTER_SSL_CERTS_H_INCLUDED #define RIPPLE_NET_REGISTER_SSL_CERTS_H_INCLUDED -#include +#include #include namespace ripple { diff --git a/src/xrpld/net/detail/DatabaseBody.ipp b/src/xrpld/net/detail/DatabaseBody.ipp index cdc7da2bc41..76223ca6a35 100644 --- a/src/xrpld/net/detail/DatabaseBody.ipp +++ b/src/xrpld/net/detail/DatabaseBody.ipp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/xrpld/net/detail/DatabaseDownloader.cpp b/src/xrpld/net/detail/DatabaseDownloader.cpp index eab0d74d7d9..b39e6904c46 100644 --- a/src/xrpld/net/detail/DatabaseDownloader.cpp +++ b/src/xrpld/net/detail/DatabaseDownloader.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/xrpld/net/detail/HTTPClient.cpp b/src/xrpld/net/detail/HTTPClient.cpp index 6ab01317516..61c2875a5fa 100644 --- a/src/xrpld/net/detail/HTTPClient.cpp +++ b/src/xrpld/net/detail/HTTPClient.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/net/detail/HTTPDownloader.cpp b/src/xrpld/net/detail/HTTPDownloader.cpp index 44d27466224..760aa020e4a 100644 --- a/src/xrpld/net/detail/HTTPDownloader.cpp +++ b/src/xrpld/net/detail/HTTPDownloader.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include namespace ripple { diff --git a/src/xrpld/net/detail/HTTPStream.cpp b/src/xrpld/net/detail/HTTPStream.cpp index d235767739d..b94f8959ec9 100644 --- a/src/xrpld/net/detail/HTTPStream.cpp +++ b/src/xrpld/net/detail/HTTPStream.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/xrpld/net/detail/InfoSub.cpp b/src/xrpld/net/detail/InfoSub.cpp index 5b37cf0759b..3dc891cb5f9 100644 --- a/src/xrpld/net/detail/InfoSub.cpp +++ b/src/xrpld/net/detail/InfoSub.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include namespace ripple { diff --git a/src/xrpld/net/detail/RPCCall.cpp b/src/xrpld/net/detail/RPCCall.cpp index 8537f76b703..533878ab1b0 100644 --- a/src/xrpld/net/detail/RPCCall.cpp +++ b/src/xrpld/net/detail/RPCCall.cpp @@ -17,27 +17,27 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/net/detail/RPCSub.cpp b/src/xrpld/net/detail/RPCSub.cpp index 8b052e817cb..13bdf9119b4 100644 --- a/src/xrpld/net/detail/RPCSub.cpp +++ b/src/xrpld/net/detail/RPCSub.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/net/detail/RegisterSSLCerts.cpp b/src/xrpld/net/detail/RegisterSSLCerts.cpp index b4e3f51a93d..ede42b03af2 100644 --- a/src/xrpld/net/detail/RegisterSSLCerts.cpp +++ b/src/xrpld/net/detail/RegisterSSLCerts.cpp @@ -16,7 +16,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include +#include #include #if BOOST_OS_WINDOWS diff --git a/src/xrpld/nodestore/Backend.h b/src/xrpld/nodestore/Backend.h index d773be74198..85d38ec0a7b 100644 --- a/src/xrpld/nodestore/Backend.h +++ b/src/xrpld/nodestore/Backend.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_NODESTORE_BACKEND_H_INCLUDED #define RIPPLE_NODESTORE_BACKEND_H_INCLUDED -#include +#include #include #include diff --git a/src/xrpld/nodestore/Database.h b/src/xrpld/nodestore/Database.h index 0f9e95b23e1..ad843c55d52 100644 --- a/src/xrpld/nodestore/Database.h +++ b/src/xrpld/nodestore/Database.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_NODESTORE_DATABASE_H_INCLUDED #define RIPPLE_NODESTORE_DATABASE_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/nodestore/DatabaseRotating.h b/src/xrpld/nodestore/DatabaseRotating.h index c8d7104fe59..10f575c4662 100644 --- a/src/xrpld/nodestore/DatabaseRotating.h +++ b/src/xrpld/nodestore/DatabaseRotating.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_NODESTORE_DATABASEROTATING_H_INCLUDED #define RIPPLE_NODESTORE_DATABASEROTATING_H_INCLUDED -#include +#include namespace ripple { namespace NodeStore { diff --git a/src/xrpld/nodestore/DatabaseShard.h b/src/xrpld/nodestore/DatabaseShard.h index 55f864f41b7..408ac3501d3 100644 --- a/src/xrpld/nodestore/DatabaseShard.h +++ b/src/xrpld/nodestore/DatabaseShard.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_NODESTORE_DATABASESHARD_H_INCLUDED #define RIPPLE_NODESTORE_DATABASESHARD_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/nodestore/DummyScheduler.h b/src/xrpld/nodestore/DummyScheduler.h index cfe7c3fd5dd..4e6fab7827d 100644 --- a/src/xrpld/nodestore/DummyScheduler.h +++ b/src/xrpld/nodestore/DummyScheduler.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_NODESTORE_DUMMYSCHEDULER_H_INCLUDED #define RIPPLE_NODESTORE_DUMMYSCHEDULER_H_INCLUDED -#include +#include namespace ripple { namespace NodeStore { diff --git a/src/xrpld/nodestore/Factory.h b/src/xrpld/nodestore/Factory.h index 4313b4ef12f..8853a6ce9a5 100644 --- a/src/xrpld/nodestore/Factory.h +++ b/src/xrpld/nodestore/Factory.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_NODESTORE_FACTORY_H_INCLUDED #define RIPPLE_NODESTORE_FACTORY_H_INCLUDED -#include -#include -#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/nodestore/Manager.h b/src/xrpld/nodestore/Manager.h index 26fdc8789eb..5a4d46068be 100644 --- a/src/xrpld/nodestore/Manager.h +++ b/src/xrpld/nodestore/Manager.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_NODESTORE_MANAGER_H_INCLUDED #define RIPPLE_NODESTORE_MANAGER_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/nodestore/NodeObject.h b/src/xrpld/nodestore/NodeObject.h index a94e689b34b..f5a1fdb075d 100644 --- a/src/xrpld/nodestore/NodeObject.h +++ b/src/xrpld/nodestore/NodeObject.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_NODESTORE_NODEOBJECT_H_INCLUDED #define RIPPLE_NODESTORE_NODEOBJECT_H_INCLUDED -#include -#include -#include +#include +#include +#include // VFALCO NOTE Intentionally not in the NodeStore namespace diff --git a/src/xrpld/nodestore/Scheduler.h b/src/xrpld/nodestore/Scheduler.h index c97f75ae59b..236c2260eed 100644 --- a/src/xrpld/nodestore/Scheduler.h +++ b/src/xrpld/nodestore/Scheduler.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_NODESTORE_SCHEDULER_H_INCLUDED #define RIPPLE_NODESTORE_SCHEDULER_H_INCLUDED -#include +#include #include namespace ripple { diff --git a/src/xrpld/nodestore/ShardInfo.h b/src/xrpld/nodestore/ShardInfo.h index 90400276f85..b894ddc34a3 100644 --- a/src/xrpld/nodestore/ShardInfo.h +++ b/src/xrpld/nodestore/ShardInfo.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_NODESTORE_SHARDINFO_H_INCLUDED #define RIPPLE_NODESTORE_SHARDINFO_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { namespace NodeStore { diff --git a/src/xrpld/nodestore/Types.h b/src/xrpld/nodestore/Types.h index 6d8583ed9d1..39104f946e3 100644 --- a/src/xrpld/nodestore/Types.h +++ b/src/xrpld/nodestore/Types.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_NODESTORE_TYPES_H_INCLUDED #define RIPPLE_NODESTORE_TYPES_H_INCLUDED -#include -#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/nodestore/backend/CassandraFactory.cpp b/src/xrpld/nodestore/backend/CassandraFactory.cpp index d13cd71827b..c53e7709587 100644 --- a/src/xrpld/nodestore/backend/CassandraFactory.cpp +++ b/src/xrpld/nodestore/backend/CassandraFactory.cpp @@ -22,17 +22,17 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/nodestore/backend/MemoryFactory.cpp b/src/xrpld/nodestore/backend/MemoryFactory.cpp index f82c14429ee..767db9d1695 100644 --- a/src/xrpld/nodestore/backend/MemoryFactory.cpp +++ b/src/xrpld/nodestore/backend/MemoryFactory.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/nodestore/backend/NuDBFactory.cpp b/src/xrpld/nodestore/backend/NuDBFactory.cpp index 30b848e82af..742bf05031b 100644 --- a/src/xrpld/nodestore/backend/NuDBFactory.cpp +++ b/src/xrpld/nodestore/backend/NuDBFactory.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/nodestore/backend/NullFactory.cpp b/src/xrpld/nodestore/backend/NullFactory.cpp index 8509787b318..47254cd50fc 100644 --- a/src/xrpld/nodestore/backend/NullFactory.cpp +++ b/src/xrpld/nodestore/backend/NullFactory.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/nodestore/backend/RocksDBFactory.cpp b/src/xrpld/nodestore/backend/RocksDBFactory.cpp index b34560dba89..9ba9fffe1db 100644 --- a/src/xrpld/nodestore/backend/RocksDBFactory.cpp +++ b/src/xrpld/nodestore/backend/RocksDBFactory.cpp @@ -17,20 +17,20 @@ */ //============================================================================== -#include +#include #if RIPPLE_ROCKSDB_AVAILABLE -#include -#include -#include -#include -#include // VFALCO Bad dependency -#include -#include -#include -#include -#include +#include // VFALCO Bad dependency +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/nodestore/detail/BatchWriter.cpp b/src/xrpld/nodestore/detail/BatchWriter.cpp index 692032016cc..1c5067d5bed 100644 --- a/src/xrpld/nodestore/detail/BatchWriter.cpp +++ b/src/xrpld/nodestore/detail/BatchWriter.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { namespace NodeStore { diff --git a/src/xrpld/nodestore/detail/BatchWriter.h b/src/xrpld/nodestore/detail/BatchWriter.h index 9ce4f120329..c48002f4f80 100644 --- a/src/xrpld/nodestore/detail/BatchWriter.h +++ b/src/xrpld/nodestore/detail/BatchWriter.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_NODESTORE_BATCHWRITER_H_INCLUDED #define RIPPLE_NODESTORE_BATCHWRITER_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/xrpld/nodestore/detail/Database.cpp b/src/xrpld/nodestore/detail/Database.cpp index 70416c873d5..93468eb6084 100644 --- a/src/xrpld/nodestore/detail/Database.cpp +++ b/src/xrpld/nodestore/detail/Database.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/nodestore/detail/DatabaseNodeImp.cpp b/src/xrpld/nodestore/detail/DatabaseNodeImp.cpp index 9ef878bf3be..d61c68e759a 100644 --- a/src/xrpld/nodestore/detail/DatabaseNodeImp.cpp +++ b/src/xrpld/nodestore/detail/DatabaseNodeImp.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include namespace ripple { namespace NodeStore { diff --git a/src/xrpld/nodestore/detail/DatabaseNodeImp.h b/src/xrpld/nodestore/detail/DatabaseNodeImp.h index 452bd8d27fe..f5f5f64bd1d 100644 --- a/src/xrpld/nodestore/detail/DatabaseNodeImp.h +++ b/src/xrpld/nodestore/detail/DatabaseNodeImp.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_NODESTORE_DATABASENODEIMP_H_INCLUDED #define RIPPLE_NODESTORE_DATABASENODEIMP_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { namespace NodeStore { diff --git a/src/xrpld/nodestore/detail/DatabaseRotatingImp.cpp b/src/xrpld/nodestore/detail/DatabaseRotatingImp.cpp index 267b4ee581f..b1283d7de71 100644 --- a/src/xrpld/nodestore/detail/DatabaseRotatingImp.cpp +++ b/src/xrpld/nodestore/detail/DatabaseRotatingImp.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include namespace ripple { namespace NodeStore { diff --git a/src/xrpld/nodestore/detail/DatabaseRotatingImp.h b/src/xrpld/nodestore/detail/DatabaseRotatingImp.h index 3a9fd302b4f..ec46fc687be 100644 --- a/src/xrpld/nodestore/detail/DatabaseRotatingImp.h +++ b/src/xrpld/nodestore/detail/DatabaseRotatingImp.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_NODESTORE_DATABASEROTATINGIMP_H_INCLUDED #define RIPPLE_NODESTORE_DATABASEROTATINGIMP_H_INCLUDED -#include +#include #include diff --git a/src/xrpld/nodestore/detail/DatabaseShardImp.cpp b/src/xrpld/nodestore/detail/DatabaseShardImp.cpp index 33000b5d24c..c7e45641d7f 100644 --- a/src/xrpld/nodestore/detail/DatabaseShardImp.cpp +++ b/src/xrpld/nodestore/detail/DatabaseShardImp.cpp @@ -17,22 +17,22 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/nodestore/detail/DatabaseShardImp.h b/src/xrpld/nodestore/detail/DatabaseShardImp.h index 5cf1f3701c4..df740cf407c 100644 --- a/src/xrpld/nodestore/detail/DatabaseShardImp.h +++ b/src/xrpld/nodestore/detail/DatabaseShardImp.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_NODESTORE_DATABASESHARDIMP_H_INCLUDED #define RIPPLE_NODESTORE_DATABASESHARDIMP_H_INCLUDED -#include -#include -#include +#include +#include +#include #include diff --git a/src/xrpld/nodestore/detail/DecodedBlob.cpp b/src/xrpld/nodestore/detail/DecodedBlob.cpp index 13175d36295..b71f2c543b1 100644 --- a/src/xrpld/nodestore/detail/DecodedBlob.cpp +++ b/src/xrpld/nodestore/detail/DecodedBlob.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include diff --git a/src/xrpld/nodestore/detail/DecodedBlob.h b/src/xrpld/nodestore/detail/DecodedBlob.h index 623e1f18dce..d52f20c4eef 100644 --- a/src/xrpld/nodestore/detail/DecodedBlob.h +++ b/src/xrpld/nodestore/detail/DecodedBlob.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_NODESTORE_DECODEDBLOB_H_INCLUDED #define RIPPLE_NODESTORE_DECODEDBLOB_H_INCLUDED -#include +#include namespace ripple { namespace NodeStore { diff --git a/src/xrpld/nodestore/detail/DeterministicShard.cpp b/src/xrpld/nodestore/detail/DeterministicShard.cpp index 5dd6bfb4cb3..c575a685ded 100644 --- a/src/xrpld/nodestore/detail/DeterministicShard.cpp +++ b/src/xrpld/nodestore/detail/DeterministicShard.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/nodestore/detail/DeterministicShard.h b/src/xrpld/nodestore/detail/DeterministicShard.h index c32a45127ef..3eb5eaa8144 100644 --- a/src/xrpld/nodestore/detail/DeterministicShard.h +++ b/src/xrpld/nodestore/detail/DeterministicShard.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_NODESTORE_DETERMINISTICSHARD_H_INCLUDED #define RIPPLE_NODESTORE_DETERMINISTICSHARD_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/src/xrpld/nodestore/detail/DummyScheduler.cpp b/src/xrpld/nodestore/detail/DummyScheduler.cpp index ee44e02fb81..76cd89610cc 100644 --- a/src/xrpld/nodestore/detail/DummyScheduler.cpp +++ b/src/xrpld/nodestore/detail/DummyScheduler.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { namespace NodeStore { diff --git a/src/xrpld/nodestore/detail/EncodedBlob.h b/src/xrpld/nodestore/detail/EncodedBlob.h index 77f8fbf3c6c..2b506a0df3f 100644 --- a/src/xrpld/nodestore/detail/EncodedBlob.h +++ b/src/xrpld/nodestore/detail/EncodedBlob.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_NODESTORE_ENCODEDBLOB_H_INCLUDED #define RIPPLE_NODESTORE_ENCODEDBLOB_H_INCLUDED -#include -#include +#include +#include #include #include #include diff --git a/src/xrpld/nodestore/detail/ManagerImp.cpp b/src/xrpld/nodestore/detail/ManagerImp.cpp index d5ea29059df..019dd1f8122 100644 --- a/src/xrpld/nodestore/detail/ManagerImp.cpp +++ b/src/xrpld/nodestore/detail/ManagerImp.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include diff --git a/src/xrpld/nodestore/detail/ManagerImp.h b/src/xrpld/nodestore/detail/ManagerImp.h index 42f8584ef07..92411cc7601 100644 --- a/src/xrpld/nodestore/detail/ManagerImp.h +++ b/src/xrpld/nodestore/detail/ManagerImp.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_NODESTORE_MANAGERIMP_H_INCLUDED #define RIPPLE_NODESTORE_MANAGERIMP_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/nodestore/detail/NodeObject.cpp b/src/xrpld/nodestore/detail/NodeObject.cpp index fb476107c8e..f633014b09f 100644 --- a/src/xrpld/nodestore/detail/NodeObject.cpp +++ b/src/xrpld/nodestore/detail/NodeObject.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include namespace ripple { diff --git a/src/xrpld/nodestore/detail/Shard.cpp b/src/xrpld/nodestore/detail/Shard.cpp index 10adf298361..8c2e9997fbf 100644 --- a/src/xrpld/nodestore/detail/Shard.cpp +++ b/src/xrpld/nodestore/detail/Shard.cpp @@ -17,16 +17,16 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace NodeStore { diff --git a/src/xrpld/nodestore/detail/Shard.h b/src/xrpld/nodestore/detail/Shard.h index 210bdd54a60..be11e538c77 100644 --- a/src/xrpld/nodestore/detail/Shard.h +++ b/src/xrpld/nodestore/detail/Shard.h @@ -20,17 +20,17 @@ #ifndef RIPPLE_NODESTORE_SHARD_H_INCLUDED #define RIPPLE_NODESTORE_SHARD_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/nodestore/detail/ShardInfo.cpp b/src/xrpld/nodestore/detail/ShardInfo.cpp index fca828ab447..43a9d484900 100644 --- a/src/xrpld/nodestore/detail/ShardInfo.cpp +++ b/src/xrpld/nodestore/detail/ShardInfo.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { namespace NodeStore { diff --git a/src/xrpld/nodestore/detail/TaskQueue.cpp b/src/xrpld/nodestore/detail/TaskQueue.cpp index 90b6ba3451a..6062138c60f 100644 --- a/src/xrpld/nodestore/detail/TaskQueue.cpp +++ b/src/xrpld/nodestore/detail/TaskQueue.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include diff --git a/src/xrpld/nodestore/detail/TaskQueue.h b/src/xrpld/nodestore/detail/TaskQueue.h index 942bd9c32d8..8a743ff6016 100644 --- a/src/xrpld/nodestore/detail/TaskQueue.h +++ b/src/xrpld/nodestore/detail/TaskQueue.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_NODESTORE_TASKQUEUE_H_INCLUDED #define RIPPLE_NODESTORE_TASKQUEUE_H_INCLUDED -#include +#include #include #include diff --git a/src/xrpld/nodestore/detail/codec.h b/src/xrpld/nodestore/detail/codec.h index a6749e0d162..f19672b8123 100644 --- a/src/xrpld/nodestore/detail/codec.h +++ b/src/xrpld/nodestore/detail/codec.h @@ -23,11 +23,11 @@ // Disable lz4 deprecation warning due to incompatibility with clang attributes #define LZ4_DISABLE_DEPRECATE_WARNINGS -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/overlay/Cluster.h b/src/xrpld/overlay/Cluster.h index 46d5a6ddb3c..42bda586c0d 100644 --- a/src/xrpld/overlay/Cluster.h +++ b/src/xrpld/overlay/Cluster.h @@ -20,13 +20,13 @@ #ifndef RIPPLE_OVERLAY_CLUSTER_H_INCLUDED #define RIPPLE_OVERLAY_CLUSTER_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/overlay/ClusterNode.h b/src/xrpld/overlay/ClusterNode.h index 7996f8ffd26..1ca78208dd5 100644 --- a/src/xrpld/overlay/ClusterNode.h +++ b/src/xrpld/overlay/ClusterNode.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_APP_PEERS_CLUSTERNODESTATUS_H_INCLUDED #define RIPPLE_APP_PEERS_CLUSTERNODESTATUS_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/src/xrpld/overlay/Compression.h b/src/xrpld/overlay/Compression.h index 6bb94792b43..1cf13fcb185 100644 --- a/src/xrpld/overlay/Compression.h +++ b/src/xrpld/overlay/Compression.h @@ -20,8 +20,8 @@ #ifndef RIPPLED_COMPRESSION_H_INCLUDED #define RIPPLED_COMPRESSION_H_INCLUDED -#include -#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/overlay/Message.h b/src/xrpld/overlay/Message.h index 0d6479366e8..247e53ec9fd 100644 --- a/src/xrpld/overlay/Message.h +++ b/src/xrpld/overlay/Message.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_OVERLAY_MESSAGE_H_INCLUDED #define RIPPLE_OVERLAY_MESSAGE_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/overlay/Overlay.h b/src/xrpld/overlay/Overlay.h index 844eafb86cc..1a3362d386f 100644 --- a/src/xrpld/overlay/Overlay.h +++ b/src/xrpld/overlay/Overlay.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_OVERLAY_OVERLAY_H_INCLUDED #define RIPPLE_OVERLAY_OVERLAY_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/overlay/Peer.h b/src/xrpld/overlay/Peer.h index ba415974151..81c04f7206c 100644 --- a/src/xrpld/overlay/Peer.h +++ b/src/xrpld/overlay/Peer.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_OVERLAY_PEER_H_INCLUDED #define RIPPLE_OVERLAY_PEER_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/overlay/PeerReservationTable.h b/src/xrpld/overlay/PeerReservationTable.h index e8fd4a29437..fb3add61f70 100644 --- a/src/xrpld/overlay/PeerReservationTable.h +++ b/src/xrpld/overlay/PeerReservationTable.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_OVERLAY_PEER_RESERVATION_TABLE_H_INCLUDED #define RIPPLE_OVERLAY_PEER_RESERVATION_TABLE_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/overlay/PeerSet.h b/src/xrpld/overlay/PeerSet.h index db21b0c7498..aca6242f9de 100644 --- a/src/xrpld/overlay/PeerSet.h +++ b/src/xrpld/overlay/PeerSet.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_APP_PEERS_PEERSET_H_INCLUDED #define RIPPLE_APP_PEERS_PEERSET_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/overlay/Slot.h b/src/xrpld/overlay/Slot.h index e58619e66f8..2a8b2146a02 100644 --- a/src/xrpld/overlay/Slot.h +++ b/src/xrpld/overlay/Slot.h @@ -20,15 +20,15 @@ #ifndef RIPPLE_OVERLAY_SLOT_H_INCLUDED #define RIPPLE_OVERLAY_SLOT_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/overlay/Squelch.h b/src/xrpld/overlay/Squelch.h index 175c80a0af2..2919922da92 100644 --- a/src/xrpld/overlay/Squelch.h +++ b/src/xrpld/overlay/Squelch.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_OVERLAY_SQUELCH_H_INCLUDED #define RIPPLE_OVERLAY_SQUELCH_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/overlay/detail/Cluster.cpp b/src/xrpld/overlay/detail/Cluster.cpp index a7b1e44d4b7..9d25248e8df 100644 --- a/src/xrpld/overlay/detail/Cluster.cpp +++ b/src/xrpld/overlay/detail/Cluster.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/overlay/detail/ConnectAttempt.cpp b/src/xrpld/overlay/detail/ConnectAttempt.cpp index f1d1c6ffe00..6a3ebdd5b98 100644 --- a/src/xrpld/overlay/detail/ConnectAttempt.cpp +++ b/src/xrpld/overlay/detail/ConnectAttempt.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/overlay/detail/ConnectAttempt.h b/src/xrpld/overlay/detail/ConnectAttempt.h index 65eac6809f4..474ac3c069f 100644 --- a/src/xrpld/overlay/detail/ConnectAttempt.h +++ b/src/xrpld/overlay/detail/ConnectAttempt.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_OVERLAY_CONNECTATTEMPT_H_INCLUDED #define RIPPLE_OVERLAY_CONNECTATTEMPT_H_INCLUDED -#include -#include +#include +#include namespace ripple { diff --git a/src/xrpld/overlay/detail/Handshake.cpp b/src/xrpld/overlay/detail/Handshake.cpp index b655859dcbc..8f1aae8c025 100644 --- a/src/xrpld/overlay/detail/Handshake.cpp +++ b/src/xrpld/overlay/detail/Handshake.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/overlay/detail/Handshake.h b/src/xrpld/overlay/detail/Handshake.h index 2accf5d221e..76c11b287ca 100644 --- a/src/xrpld/overlay/detail/Handshake.h +++ b/src/xrpld/overlay/detail/Handshake.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_OVERLAY_HANDSHAKE_H_INCLUDED #define RIPPLE_OVERLAY_HANDSHAKE_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/overlay/detail/Message.cpp b/src/xrpld/overlay/detail/Message.cpp index b4cb1f192aa..e19d718c73d 100644 --- a/src/xrpld/overlay/detail/Message.cpp +++ b/src/xrpld/overlay/detail/Message.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/overlay/detail/OverlayImpl.cpp b/src/xrpld/overlay/detail/OverlayImpl.cpp index 7e60b2c120c..f033ad4e9f9 100644 --- a/src/xrpld/overlay/detail/OverlayImpl.cpp +++ b/src/xrpld/overlay/detail/OverlayImpl.cpp @@ -17,26 +17,26 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/overlay/detail/OverlayImpl.h b/src/xrpld/overlay/detail/OverlayImpl.h index 2ba7999cbe0..1934a7c94c8 100644 --- a/src/xrpld/overlay/detail/OverlayImpl.h +++ b/src/xrpld/overlay/detail/OverlayImpl.h @@ -20,21 +20,21 @@ #ifndef RIPPLE_OVERLAY_OVERLAYIMPL_H_INCLUDED #define RIPPLE_OVERLAY_OVERLAYIMPL_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/overlay/detail/PeerImp.cpp b/src/xrpld/overlay/detail/PeerImp.cpp index 4cd3a89452d..96f793b8d80 100644 --- a/src/xrpld/overlay/detail/PeerImp.cpp +++ b/src/xrpld/overlay/detail/PeerImp.cpp @@ -17,28 +17,28 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/overlay/detail/PeerImp.h b/src/xrpld/overlay/detail/PeerImp.h index 710ab4d74d6..1c25d8089b8 100644 --- a/src/xrpld/overlay/detail/PeerImp.h +++ b/src/xrpld/overlay/detail/PeerImp.h @@ -20,22 +20,22 @@ #ifndef RIPPLE_OVERLAY_PEERIMP_H_INCLUDED #define RIPPLE_OVERLAY_PEERIMP_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/overlay/detail/PeerReservationTable.cpp b/src/xrpld/overlay/detail/PeerReservationTable.cpp index 6f39d12e99c..6fd0112f46f 100644 --- a/src/xrpld/overlay/detail/PeerReservationTable.cpp +++ b/src/xrpld/overlay/detail/PeerReservationTable.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/overlay/detail/PeerSet.cpp b/src/xrpld/overlay/detail/PeerSet.cpp index de5c3cd9f93..909b20c3079 100644 --- a/src/xrpld/overlay/detail/PeerSet.cpp +++ b/src/xrpld/overlay/detail/PeerSet.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/overlay/detail/ProtocolMessage.h b/src/xrpld/overlay/detail/ProtocolMessage.h index d6fb14bc78c..b8c6a2c1cf2 100644 --- a/src/xrpld/overlay/detail/ProtocolMessage.h +++ b/src/xrpld/overlay/detail/ProtocolMessage.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_OVERLAY_PROTOCOLMESSAGE_H_INCLUDED #define RIPPLE_OVERLAY_PROTOCOLMESSAGE_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/overlay/detail/ProtocolVersion.cpp b/src/xrpld/overlay/detail/ProtocolVersion.cpp index fbd48474420..bd2effa6341 100644 --- a/src/xrpld/overlay/detail/ProtocolVersion.cpp +++ b/src/xrpld/overlay/detail/ProtocolVersion.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/overlay/detail/TrafficCount.cpp b/src/xrpld/overlay/detail/TrafficCount.cpp index 9b35d47683c..f3e9c137fba 100644 --- a/src/xrpld/overlay/detail/TrafficCount.cpp +++ b/src/xrpld/overlay/detail/TrafficCount.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/xrpld/overlay/detail/TrafficCount.h b/src/xrpld/overlay/detail/TrafficCount.h index 9e212da7917..acd96695257 100644 --- a/src/xrpld/overlay/detail/TrafficCount.h +++ b/src/xrpld/overlay/detail/TrafficCount.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_OVERLAY_TRAFFIC_H_INCLUDED #define RIPPLE_OVERLAY_TRAFFIC_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/src/xrpld/overlay/detail/TxMetrics.cpp b/src/xrpld/overlay/detail/TxMetrics.cpp index c9b826e9a36..8759e0122e5 100644 --- a/src/xrpld/overlay/detail/TxMetrics.cpp +++ b/src/xrpld/overlay/detail/TxMetrics.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include diff --git a/src/xrpld/overlay/detail/TxMetrics.h b/src/xrpld/overlay/detail/TxMetrics.h index d70cadee1b1..eda7f1bb1b3 100644 --- a/src/xrpld/overlay/detail/TxMetrics.h +++ b/src/xrpld/overlay/detail/TxMetrics.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_OVERLAY_TXMETRICS_H_INCLUDED #define RIPPLE_OVERLAY_TXMETRICS_H_INCLUDED -#include -#include +#include +#include #include diff --git a/src/xrpld/overlay/make_Overlay.h b/src/xrpld/overlay/make_Overlay.h index 9a63f5a46af..6532281f3dc 100644 --- a/src/xrpld/overlay/make_Overlay.h +++ b/src/xrpld/overlay/make_Overlay.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_OVERLAY_MAKE_OVERLAY_H_INCLUDED #define RIPPLE_OVERLAY_MAKE_OVERLAY_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/overlay/predicates.h b/src/xrpld/overlay/predicates.h index 8e403b81fa8..88e7ce6aa4d 100644 --- a/src/xrpld/overlay/predicates.h +++ b/src/xrpld/overlay/predicates.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_OVERLAY_PREDICATES_H_INCLUDED #define RIPPLE_OVERLAY_PREDICATES_H_INCLUDED -#include -#include +#include +#include #include diff --git a/src/xrpld/peerfinder/PeerfinderManager.h b/src/xrpld/peerfinder/PeerfinderManager.h index a831cbb707e..10de99abe62 100644 --- a/src/xrpld/peerfinder/PeerfinderManager.h +++ b/src/xrpld/peerfinder/PeerfinderManager.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_PEERFINDER_MANAGER_H_INCLUDED #define RIPPLE_PEERFINDER_MANAGER_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/peerfinder/Slot.h b/src/xrpld/peerfinder/Slot.h index b43b8075ddc..879c6a53317 100644 --- a/src/xrpld/peerfinder/Slot.h +++ b/src/xrpld/peerfinder/Slot.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_PEERFINDER_SLOT_H_INCLUDED #define RIPPLE_PEERFINDER_SLOT_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/src/xrpld/peerfinder/detail/Bootcache.cpp b/src/xrpld/peerfinder/detail/Bootcache.cpp index a07c53417d2..9e94a12e619 100644 --- a/src/xrpld/peerfinder/detail/Bootcache.cpp +++ b/src/xrpld/peerfinder/detail/Bootcache.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { namespace PeerFinder { diff --git a/src/xrpld/peerfinder/detail/Bootcache.h b/src/xrpld/peerfinder/detail/Bootcache.h index b48f248ae40..07e8869594c 100644 --- a/src/xrpld/peerfinder/detail/Bootcache.h +++ b/src/xrpld/peerfinder/detail/Bootcache.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_PEERFINDER_BOOTCACHE_H_INCLUDED #define RIPPLE_PEERFINDER_BOOTCACHE_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/peerfinder/detail/Checker.h b/src/xrpld/peerfinder/detail/Checker.h index 3a5ef901328..338bd839541 100644 --- a/src/xrpld/peerfinder/detail/Checker.h +++ b/src/xrpld/peerfinder/detail/Checker.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PEERFINDER_CHECKER_H_INCLUDED #define RIPPLE_PEERFINDER_CHECKER_H_INCLUDED -#include +#include #include #include #include diff --git a/src/xrpld/peerfinder/detail/Counts.h b/src/xrpld/peerfinder/detail/Counts.h index 5d9e318594f..1ea6ff976de 100644 --- a/src/xrpld/peerfinder/detail/Counts.h +++ b/src/xrpld/peerfinder/detail/Counts.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_PEERFINDER_COUNTS_H_INCLUDED #define RIPPLE_PEERFINDER_COUNTS_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include diff --git a/src/xrpld/peerfinder/detail/Endpoint.cpp b/src/xrpld/peerfinder/detail/Endpoint.cpp index 9740b60206b..53415a8c131 100644 --- a/src/xrpld/peerfinder/detail/Endpoint.cpp +++ b/src/xrpld/peerfinder/detail/Endpoint.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { namespace PeerFinder { diff --git a/src/xrpld/peerfinder/detail/Fixed.h b/src/xrpld/peerfinder/detail/Fixed.h index bf7a2b6b35b..464a4d97d9a 100644 --- a/src/xrpld/peerfinder/detail/Fixed.h +++ b/src/xrpld/peerfinder/detail/Fixed.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PEERFINDER_FIXED_H_INCLUDED #define RIPPLE_PEERFINDER_FIXED_H_INCLUDED -#include +#include namespace ripple { namespace PeerFinder { diff --git a/src/xrpld/peerfinder/detail/Handouts.h b/src/xrpld/peerfinder/detail/Handouts.h index 00e163bbeaa..0b54dc205fa 100644 --- a/src/xrpld/peerfinder/detail/Handouts.h +++ b/src/xrpld/peerfinder/detail/Handouts.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_PEERFINDER_HANDOUTS_H_INCLUDED #define RIPPLE_PEERFINDER_HANDOUTS_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/peerfinder/detail/Livecache.h b/src/xrpld/peerfinder/detail/Livecache.h index 8ecd68e845e..1583ccd96a3 100644 --- a/src/xrpld/peerfinder/detail/Livecache.h +++ b/src/xrpld/peerfinder/detail/Livecache.h @@ -20,13 +20,13 @@ #ifndef RIPPLE_PEERFINDER_LIVECACHE_H_INCLUDED #define RIPPLE_PEERFINDER_LIVECACHE_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/peerfinder/detail/Logic.h b/src/xrpld/peerfinder/detail/Logic.h index 7a2b6a7543a..49b71a6a545 100644 --- a/src/xrpld/peerfinder/detail/Logic.h +++ b/src/xrpld/peerfinder/detail/Logic.h @@ -20,22 +20,22 @@ #ifndef RIPPLE_PEERFINDER_LOGIC_H_INCLUDED #define RIPPLE_PEERFINDER_LOGIC_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/peerfinder/detail/PeerfinderConfig.cpp b/src/xrpld/peerfinder/detail/PeerfinderConfig.cpp index 8b90bc97184..3075224189e 100644 --- a/src/xrpld/peerfinder/detail/PeerfinderConfig.cpp +++ b/src/xrpld/peerfinder/detail/PeerfinderConfig.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { namespace PeerFinder { diff --git a/src/xrpld/peerfinder/detail/PeerfinderManager.cpp b/src/xrpld/peerfinder/detail/PeerfinderManager.cpp index e3743c047e4..8baa2b50b9a 100644 --- a/src/xrpld/peerfinder/detail/PeerfinderManager.cpp +++ b/src/xrpld/peerfinder/detail/PeerfinderManager.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/peerfinder/detail/SlotImp.cpp b/src/xrpld/peerfinder/detail/SlotImp.cpp index c41aeb9d5d8..a5d13aa729e 100644 --- a/src/xrpld/peerfinder/detail/SlotImp.cpp +++ b/src/xrpld/peerfinder/detail/SlotImp.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include namespace ripple { namespace PeerFinder { diff --git a/src/xrpld/peerfinder/detail/SlotImp.h b/src/xrpld/peerfinder/detail/SlotImp.h index 49e5d731ba0..45143a90121 100644 --- a/src/xrpld/peerfinder/detail/SlotImp.h +++ b/src/xrpld/peerfinder/detail/SlotImp.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_PEERFINDER_SLOTIMP_H_INCLUDED #define RIPPLE_PEERFINDER_SLOTIMP_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/peerfinder/detail/Source.h b/src/xrpld/peerfinder/detail/Source.h index 5c148438148..a64da7b9e79 100644 --- a/src/xrpld/peerfinder/detail/Source.h +++ b/src/xrpld/peerfinder/detail/Source.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PEERFINDER_SOURCE_H_INCLUDED #define RIPPLE_PEERFINDER_SOURCE_H_INCLUDED -#include +#include #include namespace ripple { diff --git a/src/xrpld/peerfinder/detail/SourceStrings.cpp b/src/xrpld/peerfinder/detail/SourceStrings.cpp index 4e5db79c75c..b01fbfd8c21 100644 --- a/src/xrpld/peerfinder/detail/SourceStrings.cpp +++ b/src/xrpld/peerfinder/detail/SourceStrings.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { namespace PeerFinder { diff --git a/src/xrpld/peerfinder/detail/SourceStrings.h b/src/xrpld/peerfinder/detail/SourceStrings.h index 5d67d0887f3..52d985a7017 100644 --- a/src/xrpld/peerfinder/detail/SourceStrings.h +++ b/src/xrpld/peerfinder/detail/SourceStrings.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PEERFINDER_SOURCESTRINGS_H_INCLUDED #define RIPPLE_PEERFINDER_SOURCESTRINGS_H_INCLUDED -#include +#include #include namespace ripple { diff --git a/src/xrpld/peerfinder/detail/StoreSqdb.h b/src/xrpld/peerfinder/detail/StoreSqdb.h index 879bee83b6f..ad8b886d4a3 100644 --- a/src/xrpld/peerfinder/detail/StoreSqdb.h +++ b/src/xrpld/peerfinder/detail/StoreSqdb.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_PEERFINDER_STORESQDB_H_INCLUDED #define RIPPLE_PEERFINDER_STORESQDB_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/peerfinder/make_Manager.h b/src/xrpld/peerfinder/make_Manager.h index 932fccb9abd..3a4f68d94c9 100644 --- a/src/xrpld/peerfinder/make_Manager.h +++ b/src/xrpld/peerfinder/make_Manager.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PEERFINDER_MAKE_MANAGER_H_INCLUDED #define RIPPLE_PEERFINDER_MAKE_MANAGER_H_INCLUDED -#include +#include #include #include diff --git a/src/xrpld/perflog/PerfLog.h b/src/xrpld/perflog/PerfLog.h index 3d1cb371715..17147ccce3c 100644 --- a/src/xrpld/perflog/PerfLog.h +++ b/src/xrpld/perflog/PerfLog.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_BASICS_PERFLOG_H #define RIPPLE_BASICS_PERFLOG_H -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/perflog/detail/PerfLogImp.cpp b/src/xrpld/perflog/detail/PerfLogImp.cpp index 3d07d0ed625..b9691e05c23 100644 --- a/src/xrpld/perflog/detail/PerfLogImp.cpp +++ b/src/xrpld/perflog/detail/PerfLogImp.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/perflog/detail/PerfLogImp.h b/src/xrpld/perflog/detail/PerfLogImp.h index 4904126d95f..937486f75dc 100644 --- a/src/xrpld/perflog/detail/PerfLogImp.h +++ b/src/xrpld/perflog/detail/PerfLogImp.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_BASICS_PERFLOGIMP_H #define RIPPLE_BASICS_PERFLOGIMP_H -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/rpc/Context.h b/src/xrpld/rpc/Context.h index ea18efcec6c..edc5582a401 100644 --- a/src/xrpld/rpc/Context.h +++ b/src/xrpld/rpc/Context.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_RPC_CONTEXT_H_INCLUDED #define RIPPLE_RPC_CONTEXT_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include -#include +#include namespace ripple { diff --git a/src/xrpld/rpc/DeliveredAmount.h b/src/xrpld/rpc/DeliveredAmount.h index 94fff68f7bd..2ebadd38752 100644 --- a/src/xrpld/rpc/DeliveredAmount.h +++ b/src/xrpld/rpc/DeliveredAmount.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_RPC_DELIVEREDAMOUNT_H_INCLUDED #define RIPPLE_RPC_DELIVEREDAMOUNT_H_INCLUDED -#include -#include +#include +#include #include #include diff --git a/src/xrpld/rpc/GRPCHandlers.h b/src/xrpld/rpc/GRPCHandlers.h index 9fb8d0909fe..679b16fd8ac 100644 --- a/src/xrpld/rpc/GRPCHandlers.h +++ b/src/xrpld/rpc/GRPCHandlers.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_RPC_GRPCHANDLER_H_INCLUDED #define RIPPLE_RPC_GRPCHANDLER_H_INCLUDED -#include -#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/rpc/RPCHandler.h b/src/xrpld/rpc/RPCHandler.h index 45c737783c6..c056ca27eb6 100644 --- a/src/xrpld/rpc/RPCHandler.h +++ b/src/xrpld/rpc/RPCHandler.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_RPC_RPCHANDLER_H_INCLUDED #define RIPPLE_RPC_RPCHANDLER_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { namespace RPC { diff --git a/src/xrpld/rpc/Request.h b/src/xrpld/rpc/Request.h index 4f9918215a3..ec65e38d4f4 100644 --- a/src/xrpld/rpc/Request.h +++ b/src/xrpld/rpc/Request.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_RPC_REQUEST_H_INCLUDED #define RIPPLE_RPC_REQUEST_H_INCLUDED -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/Role.h b/src/xrpld/rpc/Role.h index 1ce76f90d6d..0ce84e09ef6 100644 --- a/src/xrpld/rpc/Role.h +++ b/src/xrpld/rpc/Role.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_SERVER_ROLE_H_INCLUDED #define RIPPLE_SERVER_ROLE_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/rpc/ServerHandler.h b/src/xrpld/rpc/ServerHandler.h index 7e9e427cfdb..a8d4e900fc6 100644 --- a/src/xrpld/rpc/ServerHandler.h +++ b/src/xrpld/rpc/ServerHandler.h @@ -20,14 +20,14 @@ #ifndef RIPPLE_RPC_SERVERHANDLER_H_INCLUDED #define RIPPLE_RPC_SERVERHANDLER_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/rpc/ShardArchiveHandler.h b/src/xrpld/rpc/ShardArchiveHandler.h index b9e9b3a60a9..3a407b37976 100644 --- a/src/xrpld/rpc/ShardArchiveHandler.h +++ b/src/xrpld/rpc/ShardArchiveHandler.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_RPC_SHARDARCHIVEHANDLER_H_INCLUDED #define RIPPLE_RPC_SHARDARCHIVEHANDLER_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/rpc/ShardVerificationScheduler.h b/src/xrpld/rpc/ShardVerificationScheduler.h index 659b3e90491..bc561381b3e 100644 --- a/src/xrpld/rpc/ShardVerificationScheduler.h +++ b/src/xrpld/rpc/ShardVerificationScheduler.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_RPC_SHARDVERIFICATIONSCHEDULER_H_INCLUDED #define RIPPLE_RPC_SHARDVERIFICATIONSCHEDULER_H_INCLUDED -#include +#include #include namespace ripple { diff --git a/src/xrpld/rpc/Status.h b/src/xrpld/rpc/Status.h index d930d7ab439..1d94a6837a8 100644 --- a/src/xrpld/rpc/Status.h +++ b/src/xrpld/rpc/Status.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_RPC_STATUS_H_INCLUDED #define RIPPLE_RPC_STATUS_H_INCLUDED -#include -#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/rpc/detail/DeliveredAmount.cpp b/src/xrpld/rpc/detail/DeliveredAmount.cpp index 59316d91cf5..7874997e24f 100644 --- a/src/xrpld/rpc/detail/DeliveredAmount.cpp +++ b/src/xrpld/rpc/detail/DeliveredAmount.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/rpc/detail/Handler.cpp b/src/xrpld/rpc/detail/Handler.cpp index 1fc160dc4db..4bac4610229 100644 --- a/src/xrpld/rpc/detail/Handler.cpp +++ b/src/xrpld/rpc/detail/Handler.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/rpc/detail/Handler.h b/src/xrpld/rpc/detail/Handler.h index 28d1ee60c85..81fbc2be321 100644 --- a/src/xrpld/rpc/detail/Handler.h +++ b/src/xrpld/rpc/detail/Handler.h @@ -20,13 +20,13 @@ #ifndef RIPPLE_RPC_HANDLER_H_INCLUDED #define RIPPLE_RPC_HANDLER_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include namespace Json { diff --git a/src/xrpld/rpc/detail/LegacyPathFind.cpp b/src/xrpld/rpc/detail/LegacyPathFind.cpp index 1c13709ead6..35220178bf5 100644 --- a/src/xrpld/rpc/detail/LegacyPathFind.cpp +++ b/src/xrpld/rpc/detail/LegacyPathFind.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace RPC { diff --git a/src/xrpld/rpc/detail/RPCHandler.cpp b/src/xrpld/rpc/detail/RPCHandler.cpp index 9c5aa6d465b..8504fe72a83 100644 --- a/src/xrpld/rpc/detail/RPCHandler.cpp +++ b/src/xrpld/rpc/detail/RPCHandler.cpp @@ -17,29 +17,29 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/rpc/detail/RPCHelpers.cpp b/src/xrpld/rpc/detail/RPCHelpers.cpp index a6179b04c88..42bd4faded5 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.cpp +++ b/src/xrpld/rpc/detail/RPCHelpers.cpp @@ -17,22 +17,22 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/rpc/detail/RPCHelpers.h b/src/xrpld/rpc/detail/RPCHelpers.h index e003773e50c..30b48807fcd 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.h +++ b/src/xrpld/rpc/detail/RPCHelpers.h @@ -20,17 +20,17 @@ #ifndef RIPPLE_RPC_RPCHELPERS_H_INCLUDED #define RIPPLE_RPC_RPCHELPERS_H_INCLUDED -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/rpc/detail/Role.cpp b/src/xrpld/rpc/detail/Role.cpp index 54f6d6e2575..5cfe30b26e6 100644 --- a/src/xrpld/rpc/detail/Role.cpp +++ b/src/xrpld/rpc/detail/Role.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include #include #include diff --git a/src/xrpld/rpc/detail/ServerHandler.cpp b/src/xrpld/rpc/detail/ServerHandler.cpp index 700e1c64976..c006111894b 100644 --- a/src/xrpld/rpc/detail/ServerHandler.cpp +++ b/src/xrpld/rpc/detail/ServerHandler.cpp @@ -17,33 +17,33 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/rpc/detail/ShardArchiveHandler.cpp b/src/xrpld/rpc/detail/ShardArchiveHandler.cpp index d05744f483a..1ab8f7767b5 100644 --- a/src/xrpld/rpc/detail/ShardArchiveHandler.cpp +++ b/src/xrpld/rpc/detail/ShardArchiveHandler.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/rpc/detail/ShardVerificationScheduler.cpp b/src/xrpld/rpc/detail/ShardVerificationScheduler.cpp index ad6b6df7b5c..f571e8b29cd 100644 --- a/src/xrpld/rpc/detail/ShardVerificationScheduler.cpp +++ b/src/xrpld/rpc/detail/ShardVerificationScheduler.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include namespace ripple { namespace RPC { diff --git a/src/xrpld/rpc/detail/Status.cpp b/src/xrpld/rpc/detail/Status.cpp index e9e64da7ac0..af212d37f14 100644 --- a/src/xrpld/rpc/detail/Status.cpp +++ b/src/xrpld/rpc/detail/Status.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include #include namespace ripple { diff --git a/src/xrpld/rpc/detail/TransactionSign.cpp b/src/xrpld/rpc/detail/TransactionSign.cpp index 3f4407c86e7..5ea895b60e4 100644 --- a/src/xrpld/rpc/detail/TransactionSign.cpp +++ b/src/xrpld/rpc/detail/TransactionSign.cpp @@ -17,29 +17,29 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include // Validity::Valid -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // Validity::Valid +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/rpc/detail/TransactionSign.h b/src/xrpld/rpc/detail/TransactionSign.h index 2a38031f50a..36fb60555cf 100644 --- a/src/xrpld/rpc/detail/TransactionSign.h +++ b/src/xrpld/rpc/detail/TransactionSign.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_RPC_TRANSACTIONSIGN_H_INCLUDED #define RIPPLE_RPC_TRANSACTIONSIGN_H_INCLUDED -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/detail/WSInfoSub.h b/src/xrpld/rpc/detail/WSInfoSub.h index 31f6353b994..2267b9147f4 100644 --- a/src/xrpld/rpc/detail/WSInfoSub.h +++ b/src/xrpld/rpc/detail/WSInfoSub.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_RPC_WSINFOSUB_H #define RIPPLE_RPC_WSINFOSUB_H -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/rpc/handlers/AMMInfo.cpp b/src/xrpld/rpc/handlers/AMMInfo.cpp index b4f56ffba21..aad8faea213 100644 --- a/src/xrpld/rpc/handlers/AMMInfo.cpp +++ b/src/xrpld/rpc/handlers/AMMInfo.cpp @@ -16,15 +16,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/rpc/handlers/AccountChannels.cpp b/src/xrpld/rpc/handlers/AccountChannels.cpp index ebd89b04418..5ae87e32a12 100644 --- a/src/xrpld/rpc/handlers/AccountChannels.cpp +++ b/src/xrpld/rpc/handlers/AccountChannels.cpp @@ -17,18 +17,18 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { void diff --git a/src/xrpld/rpc/handlers/AccountCurrenciesHandler.cpp b/src/xrpld/rpc/handlers/AccountCurrenciesHandler.cpp index 45dc8b545ca..04336114987 100644 --- a/src/xrpld/rpc/handlers/AccountCurrenciesHandler.cpp +++ b/src/xrpld/rpc/handlers/AccountCurrenciesHandler.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/AccountInfo.cpp b/src/xrpld/rpc/handlers/AccountInfo.cpp index bd2184f49a3..29b8679505d 100644 --- a/src/xrpld/rpc/handlers/AccountInfo.cpp +++ b/src/xrpld/rpc/handlers/AccountInfo.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/rpc/handlers/AccountLines.cpp b/src/xrpld/rpc/handlers/AccountLines.cpp index 3bfcd225b14..cace3487bb8 100644 --- a/src/xrpld/rpc/handlers/AccountLines.cpp +++ b/src/xrpld/rpc/handlers/AccountLines.cpp @@ -17,16 +17,16 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/AccountObjects.cpp b/src/xrpld/rpc/handlers/AccountObjects.cpp index 2531cd03115..dfc4e9b3388 100644 --- a/src/xrpld/rpc/handlers/AccountObjects.cpp +++ b/src/xrpld/rpc/handlers/AccountObjects.cpp @@ -17,19 +17,19 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/rpc/handlers/AccountOffers.cpp b/src/xrpld/rpc/handlers/AccountOffers.cpp index 867f888e241..1a3b5227ed8 100644 --- a/src/xrpld/rpc/handlers/AccountOffers.cpp +++ b/src/xrpld/rpc/handlers/AccountOffers.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/AccountTx.cpp b/src/xrpld/rpc/handlers/AccountTx.cpp index 7fe7472721f..4f9431ce081 100644 --- a/src/xrpld/rpc/handlers/AccountTx.cpp +++ b/src/xrpld/rpc/handlers/AccountTx.cpp @@ -17,26 +17,26 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/rpc/handlers/BlackList.cpp b/src/xrpld/rpc/handlers/BlackList.cpp index 3fe5b99e5a0..3e887ff7309 100644 --- a/src/xrpld/rpc/handlers/BlackList.cpp +++ b/src/xrpld/rpc/handlers/BlackList.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/BookOffers.cpp b/src/xrpld/rpc/handlers/BookOffers.cpp index e21d7047f69..6126913a5b6 100644 --- a/src/xrpld/rpc/handlers/BookOffers.cpp +++ b/src/xrpld/rpc/handlers/BookOffers.cpp @@ -17,18 +17,18 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/CanDelete.cpp b/src/xrpld/rpc/handlers/CanDelete.cpp index 3127b5c4390..db9fdf7c5d0 100644 --- a/src/xrpld/rpc/handlers/CanDelete.cpp +++ b/src/xrpld/rpc/handlers/CanDelete.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/rpc/handlers/Connect.cpp b/src/xrpld/rpc/handlers/Connect.cpp index 46fac457cb8..dadf0a0515e 100644 --- a/src/xrpld/rpc/handlers/Connect.cpp +++ b/src/xrpld/rpc/handlers/Connect.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/ConsensusInfo.cpp b/src/xrpld/rpc/handlers/ConsensusInfo.cpp index ee7eb10e684..42fbb60ba76 100644 --- a/src/xrpld/rpc/handlers/ConsensusInfo.cpp +++ b/src/xrpld/rpc/handlers/ConsensusInfo.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/CrawlShards.cpp b/src/xrpld/rpc/handlers/CrawlShards.cpp index 41b74860c3a..f586d750439 100644 --- a/src/xrpld/rpc/handlers/CrawlShards.cpp +++ b/src/xrpld/rpc/handlers/CrawlShards.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/DepositAuthorized.cpp b/src/xrpld/rpc/handlers/DepositAuthorized.cpp index bb6e3b07a9a..0efa584625b 100644 --- a/src/xrpld/rpc/handlers/DepositAuthorized.cpp +++ b/src/xrpld/rpc/handlers/DepositAuthorized.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/DownloadShard.cpp b/src/xrpld/rpc/handlers/DownloadShard.cpp index eacf499df04..1ec12e0fa66 100644 --- a/src/xrpld/rpc/handlers/DownloadShard.cpp +++ b/src/xrpld/rpc/handlers/DownloadShard.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/rpc/handlers/Feature1.cpp b/src/xrpld/rpc/handlers/Feature1.cpp index 94a205e62f7..d4499f120ef 100644 --- a/src/xrpld/rpc/handlers/Feature1.cpp +++ b/src/xrpld/rpc/handlers/Feature1.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/Fee1.cpp b/src/xrpld/rpc/handlers/Fee1.cpp index 89fa9c6ea07..da766fdbb32 100644 --- a/src/xrpld/rpc/handlers/Fee1.cpp +++ b/src/xrpld/rpc/handlers/Fee1.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { Json::Value diff --git a/src/xrpld/rpc/handlers/FetchInfo.cpp b/src/xrpld/rpc/handlers/FetchInfo.cpp index 79d82b646a0..113ae78a35c 100644 --- a/src/xrpld/rpc/handlers/FetchInfo.cpp +++ b/src/xrpld/rpc/handlers/FetchInfo.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/GatewayBalances.cpp b/src/xrpld/rpc/handlers/GatewayBalances.cpp index 89be6290f77..8fd13d472cc 100644 --- a/src/xrpld/rpc/handlers/GatewayBalances.cpp +++ b/src/xrpld/rpc/handlers/GatewayBalances.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/GetAggregatePrice.cpp b/src/xrpld/rpc/handlers/GetAggregatePrice.cpp index 3554ba90c96..7467b94b63f 100644 --- a/src/xrpld/rpc/handlers/GetAggregatePrice.cpp +++ b/src/xrpld/rpc/handlers/GetAggregatePrice.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/rpc/handlers/GetCounts.cpp b/src/xrpld/rpc/handlers/GetCounts.cpp index 131cf7d3614..0a2327e117a 100644 --- a/src/xrpld/rpc/handlers/GetCounts.cpp +++ b/src/xrpld/rpc/handlers/GetCounts.cpp @@ -17,22 +17,22 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/GetCounts.h b/src/xrpld/rpc/handlers/GetCounts.h index 28a3e7d0604..dacf93fa910 100644 --- a/src/xrpld/rpc/handlers/GetCounts.h +++ b/src/xrpld/rpc/handlers/GetCounts.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_RPC_HANDLERS_GETCOUNTS_H_INCLUDED #define RIPPLE_RPC_HANDLERS_GETCOUNTS_H_INCLUDED -#include -#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/Handlers.h b/src/xrpld/rpc/handlers/Handlers.h index 6c74c5c7e5c..917ad38a741 100644 --- a/src/xrpld/rpc/handlers/Handlers.h +++ b/src/xrpld/rpc/handlers/Handlers.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_RPC_HANDLERS_HANDLERS_H_INCLUDED #define RIPPLE_RPC_HANDLERS_HANDLERS_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/LedgerAccept.cpp b/src/xrpld/rpc/handlers/LedgerAccept.cpp index 14177791164..742a84fbb4e 100644 --- a/src/xrpld/rpc/handlers/LedgerAccept.cpp +++ b/src/xrpld/rpc/handlers/LedgerAccept.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/rpc/handlers/LedgerCleanerHandler.cpp b/src/xrpld/rpc/handlers/LedgerCleanerHandler.cpp index 5b76f3f8b9d..48f024c051e 100644 --- a/src/xrpld/rpc/handlers/LedgerCleanerHandler.cpp +++ b/src/xrpld/rpc/handlers/LedgerCleanerHandler.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/LedgerClosed.cpp b/src/xrpld/rpc/handlers/LedgerClosed.cpp index 66e003e08f5..9bc9315f648 100644 --- a/src/xrpld/rpc/handlers/LedgerClosed.cpp +++ b/src/xrpld/rpc/handlers/LedgerClosed.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/LedgerCurrent.cpp b/src/xrpld/rpc/handlers/LedgerCurrent.cpp index 3539c800946..7f1d83c17a7 100644 --- a/src/xrpld/rpc/handlers/LedgerCurrent.cpp +++ b/src/xrpld/rpc/handlers/LedgerCurrent.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/LedgerData.cpp b/src/xrpld/rpc/handlers/LedgerData.cpp index f5433945772..ad26b83b43b 100644 --- a/src/xrpld/rpc/handlers/LedgerData.cpp +++ b/src/xrpld/rpc/handlers/LedgerData.cpp @@ -17,16 +17,16 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/LedgerDiff.cpp b/src/xrpld/rpc/handlers/LedgerDiff.cpp index 122dcfa31d5..6398be60973 100644 --- a/src/xrpld/rpc/handlers/LedgerDiff.cpp +++ b/src/xrpld/rpc/handlers/LedgerDiff.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include namespace ripple { std::pair diff --git a/src/xrpld/rpc/handlers/LedgerEntry.cpp b/src/xrpld/rpc/handlers/LedgerEntry.cpp index 8985a880824..f461cd3100b 100644 --- a/src/xrpld/rpc/handlers/LedgerEntry.cpp +++ b/src/xrpld/rpc/handlers/LedgerEntry.cpp @@ -17,20 +17,20 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/LedgerHandler.cpp b/src/xrpld/rpc/handlers/LedgerHandler.cpp index 623cb8d75ac..6d695abc85f 100644 --- a/src/xrpld/rpc/handlers/LedgerHandler.cpp +++ b/src/xrpld/rpc/handlers/LedgerHandler.cpp @@ -17,16 +17,16 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { namespace RPC { diff --git a/src/xrpld/rpc/handlers/LedgerHandler.h b/src/xrpld/rpc/handlers/LedgerHandler.h index b0bca8e6635..0a1ba2b427e 100644 --- a/src/xrpld/rpc/handlers/LedgerHandler.h +++ b/src/xrpld/rpc/handlers/LedgerHandler.h @@ -20,17 +20,17 @@ #ifndef RIPPLE_RPC_HANDLERS_LEDGER_H_INCLUDED #define RIPPLE_RPC_HANDLERS_LEDGER_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace Json { class Object; diff --git a/src/xrpld/rpc/handlers/LedgerHeader.cpp b/src/xrpld/rpc/handlers/LedgerHeader.cpp index 0f44436569c..b73ee260d4a 100644 --- a/src/xrpld/rpc/handlers/LedgerHeader.cpp +++ b/src/xrpld/rpc/handlers/LedgerHeader.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/LedgerRequest.cpp b/src/xrpld/rpc/handlers/LedgerRequest.cpp index 83e7a2184f1..8f79bb04f30 100644 --- a/src/xrpld/rpc/handlers/LedgerRequest.cpp +++ b/src/xrpld/rpc/handlers/LedgerRequest.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/rpc/handlers/LogLevel.cpp b/src/xrpld/rpc/handlers/LogLevel.cpp index 20931898d20..bf0a0e1e285 100644 --- a/src/xrpld/rpc/handlers/LogLevel.cpp +++ b/src/xrpld/rpc/handlers/LogLevel.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/rpc/handlers/LogRotate.cpp b/src/xrpld/rpc/handlers/LogRotate.cpp index 93e66451f5d..b7a887b0e27 100644 --- a/src/xrpld/rpc/handlers/LogRotate.cpp +++ b/src/xrpld/rpc/handlers/LogRotate.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/Manifest.cpp b/src/xrpld/rpc/handlers/Manifest.cpp index 22abfde8a24..700d6ab39df 100644 --- a/src/xrpld/rpc/handlers/Manifest.cpp +++ b/src/xrpld/rpc/handlers/Manifest.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { Json::Value diff --git a/src/xrpld/rpc/handlers/NFTOffers.cpp b/src/xrpld/rpc/handlers/NFTOffers.cpp index bca862d27e3..bffb3dfbb60 100644 --- a/src/xrpld/rpc/handlers/NFTOffers.cpp +++ b/src/xrpld/rpc/handlers/NFTOffers.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/NoRippleCheck.cpp b/src/xrpld/rpc/handlers/NoRippleCheck.cpp index 91d69df96bd..e4012468434 100644 --- a/src/xrpld/rpc/handlers/NoRippleCheck.cpp +++ b/src/xrpld/rpc/handlers/NoRippleCheck.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/NodeToShard.cpp b/src/xrpld/rpc/handlers/NodeToShard.cpp index 552900d1548..917086ab0f4 100644 --- a/src/xrpld/rpc/handlers/NodeToShard.cpp +++ b/src/xrpld/rpc/handlers/NodeToShard.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/OwnerInfo.cpp b/src/xrpld/rpc/handlers/OwnerInfo.cpp index 546a2e70980..83bf8b0ef21 100644 --- a/src/xrpld/rpc/handlers/OwnerInfo.cpp +++ b/src/xrpld/rpc/handlers/OwnerInfo.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/PathFind.cpp b/src/xrpld/rpc/handlers/PathFind.cpp index 9c8794b5997..cab14f9b52e 100644 --- a/src/xrpld/rpc/handlers/PathFind.cpp +++ b/src/xrpld/rpc/handlers/PathFind.cpp @@ -17,15 +17,15 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/PayChanClaim.cpp b/src/xrpld/rpc/handlers/PayChanClaim.cpp index 33561463f21..1fecd5f1449 100644 --- a/src/xrpld/rpc/handlers/PayChanClaim.cpp +++ b/src/xrpld/rpc/handlers/PayChanClaim.cpp @@ -17,18 +17,18 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/rpc/handlers/Peers.cpp b/src/xrpld/rpc/handlers/Peers.cpp index 4f377da7277..718070ec927 100644 --- a/src/xrpld/rpc/handlers/Peers.cpp +++ b/src/xrpld/rpc/handlers/Peers.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/Ping.cpp b/src/xrpld/rpc/handlers/Ping.cpp index efe9063a1e2..cb0dabcb9de 100644 --- a/src/xrpld/rpc/handlers/Ping.cpp +++ b/src/xrpld/rpc/handlers/Ping.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/Print.cpp b/src/xrpld/rpc/handlers/Print.cpp index 191ecf1ec54..df501240882 100644 --- a/src/xrpld/rpc/handlers/Print.cpp +++ b/src/xrpld/rpc/handlers/Print.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/Random.cpp b/src/xrpld/rpc/handlers/Random.cpp index 5362969660a..cea83a616c2 100644 --- a/src/xrpld/rpc/handlers/Random.cpp +++ b/src/xrpld/rpc/handlers/Random.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/Reservations.cpp b/src/xrpld/rpc/handlers/Reservations.cpp index ffbfd0f98bf..57a8fb3664a 100644 --- a/src/xrpld/rpc/handlers/Reservations.cpp +++ b/src/xrpld/rpc/handlers/Reservations.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/rpc/handlers/RipplePathFind.cpp b/src/xrpld/rpc/handlers/RipplePathFind.cpp index 19bce998494..5e18a1210e9 100644 --- a/src/xrpld/rpc/handlers/RipplePathFind.cpp +++ b/src/xrpld/rpc/handlers/RipplePathFind.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/ServerInfo.cpp b/src/xrpld/rpc/handlers/ServerInfo.cpp index 83c73e20558..769974985da 100644 --- a/src/xrpld/rpc/handlers/ServerInfo.cpp +++ b/src/xrpld/rpc/handlers/ServerInfo.cpp @@ -17,20 +17,20 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/xrpld/rpc/handlers/ServerState.cpp b/src/xrpld/rpc/handlers/ServerState.cpp index 756a3953968..dec18eca119 100644 --- a/src/xrpld/rpc/handlers/ServerState.cpp +++ b/src/xrpld/rpc/handlers/ServerState.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/SignFor.cpp b/src/xrpld/rpc/handlers/SignFor.cpp index 722cf7da157..da8ff869fba 100644 --- a/src/xrpld/rpc/handlers/SignFor.cpp +++ b/src/xrpld/rpc/handlers/SignFor.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/SignHandler.cpp b/src/xrpld/rpc/handlers/SignHandler.cpp index 4d89cdcb2e0..ed634161f74 100644 --- a/src/xrpld/rpc/handlers/SignHandler.cpp +++ b/src/xrpld/rpc/handlers/SignHandler.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/Stop.cpp b/src/xrpld/rpc/handlers/Stop.cpp index 9467556969d..ea37a1aaa1b 100644 --- a/src/xrpld/rpc/handlers/Stop.cpp +++ b/src/xrpld/rpc/handlers/Stop.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include #include diff --git a/src/xrpld/rpc/handlers/Submit.cpp b/src/xrpld/rpc/handlers/Submit.cpp index a151778fbb8..73fdc3822c2 100644 --- a/src/xrpld/rpc/handlers/Submit.cpp +++ b/src/xrpld/rpc/handlers/Submit.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/SubmitMultiSigned.cpp b/src/xrpld/rpc/handlers/SubmitMultiSigned.cpp index 5b9d5b34ac6..9949d3e3212 100644 --- a/src/xrpld/rpc/handlers/SubmitMultiSigned.cpp +++ b/src/xrpld/rpc/handlers/SubmitMultiSigned.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/Subscribe.cpp b/src/xrpld/rpc/handlers/Subscribe.cpp index 24465a2c3a5..9f9181e1ab2 100644 --- a/src/xrpld/rpc/handlers/Subscribe.cpp +++ b/src/xrpld/rpc/handlers/Subscribe.cpp @@ -17,19 +17,19 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/TransactionEntry.cpp b/src/xrpld/rpc/handlers/TransactionEntry.cpp index 6d157891d1c..e81e0434595 100644 --- a/src/xrpld/rpc/handlers/TransactionEntry.cpp +++ b/src/xrpld/rpc/handlers/TransactionEntry.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/Tx.cpp b/src/xrpld/rpc/handlers/Tx.cpp index d4c9c95a341..de95044b71f 100644 --- a/src/xrpld/rpc/handlers/Tx.cpp +++ b/src/xrpld/rpc/handlers/Tx.cpp @@ -17,22 +17,22 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/rpc/handlers/TxHistory.cpp b/src/xrpld/rpc/handlers/TxHistory.cpp index 8759d4af1b9..de86b182534 100644 --- a/src/xrpld/rpc/handlers/TxHistory.cpp +++ b/src/xrpld/rpc/handlers/TxHistory.cpp @@ -17,21 +17,21 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/rpc/handlers/TxReduceRelay.cpp b/src/xrpld/rpc/handlers/TxReduceRelay.cpp index bb883b8dea1..d8c21b3fa46 100644 --- a/src/xrpld/rpc/handlers/TxReduceRelay.cpp +++ b/src/xrpld/rpc/handlers/TxReduceRelay.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/UnlList.cpp b/src/xrpld/rpc/handlers/UnlList.cpp index 0dc4dfc3776..78bd3f14eab 100644 --- a/src/xrpld/rpc/handlers/UnlList.cpp +++ b/src/xrpld/rpc/handlers/UnlList.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/Unsubscribe.cpp b/src/xrpld/rpc/handlers/Unsubscribe.cpp index 512790f2a10..bab0d99744c 100644 --- a/src/xrpld/rpc/handlers/Unsubscribe.cpp +++ b/src/xrpld/rpc/handlers/Unsubscribe.cpp @@ -17,14 +17,14 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/ValidationCreate.cpp b/src/xrpld/rpc/handlers/ValidationCreate.cpp index f07cbe9cdfa..ce53f84d951 100644 --- a/src/xrpld/rpc/handlers/ValidationCreate.cpp +++ b/src/xrpld/rpc/handlers/ValidationCreate.cpp @@ -17,12 +17,12 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/ValidatorInfo.cpp b/src/xrpld/rpc/handlers/ValidatorInfo.cpp index 910c5e9740f..d1a63371980 100644 --- a/src/xrpld/rpc/handlers/ValidatorInfo.cpp +++ b/src/xrpld/rpc/handlers/ValidatorInfo.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { Json::Value diff --git a/src/xrpld/rpc/handlers/ValidatorListSites.cpp b/src/xrpld/rpc/handlers/ValidatorListSites.cpp index 4800a5e8661..902c373766f 100644 --- a/src/xrpld/rpc/handlers/ValidatorListSites.cpp +++ b/src/xrpld/rpc/handlers/ValidatorListSites.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/Validators.cpp b/src/xrpld/rpc/handlers/Validators.cpp index 39306612bdf..4048e8962de 100644 --- a/src/xrpld/rpc/handlers/Validators.cpp +++ b/src/xrpld/rpc/handlers/Validators.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/Version.h b/src/xrpld/rpc/handlers/Version.h index 8f33b62f1cf..4efeed24848 100644 --- a/src/xrpld/rpc/handlers/Version.h +++ b/src/xrpld/rpc/handlers/Version.h @@ -20,7 +20,7 @@ #ifndef RIPPLED_RIPPLE_RPC_HANDLERS_VERSION_H #define RIPPLED_RIPPLE_RPC_HANDLERS_VERSION_H -#include +#include namespace ripple { namespace RPC { diff --git a/src/xrpld/rpc/handlers/WalletPropose.cpp b/src/xrpld/rpc/handlers/WalletPropose.cpp index 25aaa3bbb8e..f3300b9ed04 100644 --- a/src/xrpld/rpc/handlers/WalletPropose.cpp +++ b/src/xrpld/rpc/handlers/WalletPropose.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/rpc/handlers/WalletPropose.h b/src/xrpld/rpc/handlers/WalletPropose.h index 9da0c9e412f..d09ae9a4cfb 100644 --- a/src/xrpld/rpc/handlers/WalletPropose.h +++ b/src/xrpld/rpc/handlers/WalletPropose.h @@ -20,7 +20,7 @@ #ifndef RIPPLED_RIPPLE_RPC_HANDLERS_WALLETPROPOSE_H #define RIPPLED_RIPPLE_RPC_HANDLERS_WALLETPROPOSE_H -#include +#include namespace ripple { diff --git a/src/xrpld/rpc/json_body.h b/src/xrpld/rpc/json_body.h index fb5289981c0..5c97da43839 100644 --- a/src/xrpld/rpc/json_body.h +++ b/src/xrpld/rpc/json_body.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_RPC_JSON_BODY_H #define RIPPLE_RPC_JSON_BODY_H -#include -#include +#include +#include #include #include diff --git a/src/xrpld/shamap/Family.h b/src/xrpld/shamap/Family.h index fea5545d31c..730f83483a6 100644 --- a/src/xrpld/shamap/Family.h +++ b/src/xrpld/shamap/Family.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_SHAMAP_FAMILY_H_INCLUDED #define RIPPLE_SHAMAP_FAMILY_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/shamap/FullBelowCache.h b/src/xrpld/shamap/FullBelowCache.h index 6d809d3b951..eed7e6294a0 100644 --- a/src/xrpld/shamap/FullBelowCache.h +++ b/src/xrpld/shamap/FullBelowCache.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_SHAMAP_FULLBELOWCACHE_H_INCLUDED #define RIPPLE_SHAMAP_FULLBELOWCACHE_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/shamap/NodeFamily.h b/src/xrpld/shamap/NodeFamily.h index f20abccce9d..c540172c374 100644 --- a/src/xrpld/shamap/NodeFamily.h +++ b/src/xrpld/shamap/NodeFamily.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_SHAMAP_NODEFAMILY_H_INCLUDED #define RIPPLE_SHAMAP_NODEFAMILY_H_INCLUDED -#include -#include +#include +#include namespace ripple { diff --git a/src/xrpld/shamap/SHAMap.h b/src/xrpld/shamap/SHAMap.h index 2d1aa192fc6..a47f1c1c2bc 100644 --- a/src/xrpld/shamap/SHAMap.h +++ b/src/xrpld/shamap/SHAMap.h @@ -20,19 +20,19 @@ #ifndef RIPPLE_SHAMAP_SHAMAP_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAP_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/shamap/SHAMapAccountStateLeafNode.h b/src/xrpld/shamap/SHAMapAccountStateLeafNode.h index 45f0c508078..842c1092dd9 100644 --- a/src/xrpld/shamap/SHAMapAccountStateLeafNode.h +++ b/src/xrpld/shamap/SHAMapAccountStateLeafNode.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_SHAMAP_SHAMAPACCOUNTSTATELEAFNODE_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAPACCOUNTSTATELEAFNODE_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/shamap/SHAMapInnerNode.h b/src/xrpld/shamap/SHAMapInnerNode.h index 44ac05799f2..d2791915c3c 100644 --- a/src/xrpld/shamap/SHAMapInnerNode.h +++ b/src/xrpld/shamap/SHAMapInnerNode.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_SHAMAP_SHAMAPINNERNODE_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAPINNERNODE_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/shamap/SHAMapItem.h b/src/xrpld/shamap/SHAMapItem.h index 160cc3cb49d..1a1822456e9 100644 --- a/src/xrpld/shamap/SHAMapItem.h +++ b/src/xrpld/shamap/SHAMapItem.h @@ -20,11 +20,11 @@ #ifndef RIPPLE_SHAMAP_SHAMAPITEM_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAPITEM_H_INCLUDED -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/shamap/SHAMapLeafNode.h b/src/xrpld/shamap/SHAMapLeafNode.h index f24d7053cbe..d5d84d3f003 100644 --- a/src/xrpld/shamap/SHAMapLeafNode.h +++ b/src/xrpld/shamap/SHAMapLeafNode.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_SHAMAP_SHAMAPLEAFNODE_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAPLEAFNODE_H_INCLUDED -#include -#include -#include +#include +#include +#include #include #include diff --git a/src/xrpld/shamap/SHAMapMissingNode.h b/src/xrpld/shamap/SHAMapMissingNode.h index 811fe5f9615..50aa193b2b6 100644 --- a/src/xrpld/shamap/SHAMapMissingNode.h +++ b/src/xrpld/shamap/SHAMapMissingNode.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_SHAMAP_SHAMAPMISSINGNODE_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAPMISSINGNODE_H_INCLUDED -#include -#include +#include +#include #include #include #include diff --git a/src/xrpld/shamap/SHAMapNodeID.h b/src/xrpld/shamap/SHAMapNodeID.h index 00ca33ac43f..176553fd7d3 100644 --- a/src/xrpld/shamap/SHAMapNodeID.h +++ b/src/xrpld/shamap/SHAMapNodeID.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_SHAMAP_SHAMAPNODEID_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAPNODEID_H_INCLUDED -#include -#include +#include +#include #include #include #include diff --git a/src/xrpld/shamap/SHAMapSyncFilter.h b/src/xrpld/shamap/SHAMapSyncFilter.h index 37eda4fdbc9..b14effac88b 100644 --- a/src/xrpld/shamap/SHAMapSyncFilter.h +++ b/src/xrpld/shamap/SHAMapSyncFilter.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_SHAMAP_SHAMAPSYNCFILTER_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAPSYNCFILTER_H_INCLUDED -#include -#include +#include +#include #include /** Callback for filtering SHAMap during sync. */ diff --git a/src/xrpld/shamap/SHAMapTreeNode.h b/src/xrpld/shamap/SHAMapTreeNode.h index 8e351cce9de..d6b0ebce9e1 100644 --- a/src/xrpld/shamap/SHAMapTreeNode.h +++ b/src/xrpld/shamap/SHAMapTreeNode.h @@ -20,13 +20,13 @@ #ifndef RIPPLE_SHAMAP_SHAMAPTREENODE_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAPTREENODE_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/shamap/SHAMapTxLeafNode.h b/src/xrpld/shamap/SHAMapTxLeafNode.h index e794a1a8f32..f4d3f21e908 100644 --- a/src/xrpld/shamap/SHAMapTxLeafNode.h +++ b/src/xrpld/shamap/SHAMapTxLeafNode.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_SHAMAP_SHAMAPTXLEAFNODE_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAPTXLEAFNODE_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/shamap/SHAMapTxPlusMetaLeafNode.h b/src/xrpld/shamap/SHAMapTxPlusMetaLeafNode.h index ff32c64e09b..6ea55f4ac46 100644 --- a/src/xrpld/shamap/SHAMapTxPlusMetaLeafNode.h +++ b/src/xrpld/shamap/SHAMapTxPlusMetaLeafNode.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_SHAMAP_SHAMAPLEAFTXPLUSMETANODE_H_INCLUDED #define RIPPLE_SHAMAP_SHAMAPLEAFTXPLUSMETANODE_H_INCLUDED -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/shamap/ShardFamily.h b/src/xrpld/shamap/ShardFamily.h index de809cf589c..2e8bece6dcf 100644 --- a/src/xrpld/shamap/ShardFamily.h +++ b/src/xrpld/shamap/ShardFamily.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_SHAMAP_SHARDFAMILY_H_INCLUDED #define RIPPLE_SHAMAP_SHARDFAMILY_H_INCLUDED -#include -#include +#include +#include namespace ripple { diff --git a/src/xrpld/shamap/TreeNodeCache.h b/src/xrpld/shamap/TreeNodeCache.h index f35c252f460..f59fdc92801 100644 --- a/src/xrpld/shamap/TreeNodeCache.h +++ b/src/xrpld/shamap/TreeNodeCache.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_SHAMAP_TREENODECACHE_H_INCLUDED #define RIPPLE_SHAMAP_TREENODECACHE_H_INCLUDED -#include +#include namespace ripple { diff --git a/src/xrpld/shamap/detail/NodeFamily.cpp b/src/xrpld/shamap/detail/NodeFamily.cpp index 1752db06a8e..01440a48799 100644 --- a/src/xrpld/shamap/detail/NodeFamily.cpp +++ b/src/xrpld/shamap/detail/NodeFamily.cpp @@ -17,10 +17,10 @@ */ //============================================================================== -#include -#include -#include -#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/shamap/detail/SHAMap.cpp b/src/xrpld/shamap/detail/SHAMap.cpp index d6348c86c48..e17f9346b85 100644 --- a/src/xrpld/shamap/detail/SHAMap.cpp +++ b/src/xrpld/shamap/detail/SHAMap.cpp @@ -17,13 +17,13 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/shamap/detail/SHAMapDelta.cpp b/src/xrpld/shamap/detail/SHAMapDelta.cpp index ab9e329eb30..0dcb861a63f 100644 --- a/src/xrpld/shamap/detail/SHAMapDelta.cpp +++ b/src/xrpld/shamap/detail/SHAMapDelta.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include -#include +#include +#include #include #include diff --git a/src/xrpld/shamap/detail/SHAMapInnerNode.cpp b/src/xrpld/shamap/detail/SHAMapInnerNode.cpp index c9884955914..99155a6401f 100644 --- a/src/xrpld/shamap/detail/SHAMapInnerNode.cpp +++ b/src/xrpld/shamap/detail/SHAMapInnerNode.cpp @@ -17,17 +17,17 @@ */ //============================================================================== -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/shamap/detail/SHAMapLeafNode.cpp b/src/xrpld/shamap/detail/SHAMapLeafNode.cpp index 8f634cfad88..972919a9bda 100644 --- a/src/xrpld/shamap/detail/SHAMapLeafNode.cpp +++ b/src/xrpld/shamap/detail/SHAMapLeafNode.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/shamap/detail/SHAMapNodeID.cpp b/src/xrpld/shamap/detail/SHAMapNodeID.cpp index bcbdb7f3311..5cbd095e7a9 100644 --- a/src/xrpld/shamap/detail/SHAMapNodeID.cpp +++ b/src/xrpld/shamap/detail/SHAMapNodeID.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/shamap/detail/SHAMapSync.cpp b/src/xrpld/shamap/detail/SHAMapSync.cpp index 3f24047eb7a..02d548be24e 100644 --- a/src/xrpld/shamap/detail/SHAMapSync.cpp +++ b/src/xrpld/shamap/detail/SHAMapSync.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include namespace ripple { diff --git a/src/xrpld/shamap/detail/SHAMapTreeNode.cpp b/src/xrpld/shamap/detail/SHAMapTreeNode.cpp index e7645a16a4e..fe5b5377eee 100644 --- a/src/xrpld/shamap/detail/SHAMapTreeNode.cpp +++ b/src/xrpld/shamap/detail/SHAMapTreeNode.cpp @@ -17,19 +17,19 @@ */ //============================================================================== -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/xrpld/shamap/detail/ShardFamily.cpp b/src/xrpld/shamap/detail/ShardFamily.cpp index f22d4152e2b..aef4c6cde0a 100644 --- a/src/xrpld/shamap/detail/ShardFamily.cpp +++ b/src/xrpld/shamap/detail/ShardFamily.cpp @@ -17,11 +17,11 @@ */ //============================================================================== -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include namespace ripple { diff --git a/src/xrpld/shamap/detail/TaggedPointer.h b/src/xrpld/shamap/detail/TaggedPointer.h index afc0ef582ae..58271f59c01 100644 --- a/src/xrpld/shamap/detail/TaggedPointer.h +++ b/src/xrpld/shamap/detail/TaggedPointer.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_SHAMAP_TAGGEDPOINTER_H_INCLUDED #define RIPPLE_SHAMAP_TAGGEDPOINTER_H_INCLUDED -#include +#include #include #include diff --git a/src/xrpld/shamap/detail/TaggedPointer.ipp b/src/xrpld/shamap/detail/TaggedPointer.ipp index 7cdff6b4944..6770b53021e 100644 --- a/src/xrpld/shamap/detail/TaggedPointer.ipp +++ b/src/xrpld/shamap/detail/TaggedPointer.ipp @@ -17,9 +17,9 @@ */ //============================================================================== -#include -#include -#include +#include +#include +#include #include #include From d028005aa6319338b0adae1aebf8abe113162960 Mon Sep 17 00:00:00 2001 From: Pretty Printer Date: Thu, 20 Jun 2024 09:23:51 -0500 Subject: [PATCH 18/82] Recompute loops (#4997) --- Builds/levelization/results/loops.txt | 68 ++--- Builds/levelization/results/ordering.txt | 362 +++++++++++------------ 2 files changed, 202 insertions(+), 228 deletions(-) diff --git a/Builds/levelization/results/loops.txt b/Builds/levelization/results/loops.txt index cb137f497cb..ee7e6fd3bc6 100644 --- a/Builds/levelization/results/loops.txt +++ b/Builds/levelization/results/loops.txt @@ -1,51 +1,51 @@ -Loop: ripple.app ripple.core - ripple.app > ripple.core +Loop: test.jtx test.toplevel + test.toplevel > test.jtx -Loop: ripple.app ripple.ledger - ripple.app > ripple.ledger +Loop: test.jtx test.unit_test + test.unit_test == test.jtx -Loop: ripple.app ripple.net - ripple.app > ripple.net +Loop: xrpl.basics xrpl.json + xrpl.json ~= xrpl.basics -Loop: ripple.app ripple.nodestore - ripple.app > ripple.nodestore +Loop: xrpld.app xrpld.core + xrpld.app > xrpld.core -Loop: ripple.app ripple.overlay - ripple.overlay ~= ripple.app +Loop: xrpld.app xrpld.ledger + xrpld.app > xrpld.ledger -Loop: ripple.app ripple.peerfinder - ripple.app > ripple.peerfinder +Loop: xrpld.app xrpld.net + xrpld.app > xrpld.net -Loop: ripple.app ripple.rpc - ripple.rpc > ripple.app +Loop: xrpld.app xrpld.nodestore + xrpld.app > xrpld.nodestore -Loop: ripple.app ripple.shamap - ripple.app > ripple.shamap +Loop: xrpld.app xrpld.overlay + xrpld.overlay ~= xrpld.app -Loop: ripple.basics ripple.core - ripple.core > ripple.basics +Loop: xrpld.app xrpld.peerfinder + xrpld.app > xrpld.peerfinder -Loop: ripple.basics ripple.json - ripple.json ~= ripple.basics +Loop: xrpld.app xrpld.rpc + xrpld.rpc > xrpld.app -Loop: ripple.basics ripple.protocol - ripple.protocol > ripple.basics +Loop: xrpld.app xrpld.shamap + xrpld.app > xrpld.shamap -Loop: ripple.core ripple.net - ripple.net > ripple.core +Loop: xrpld.core xrpld.net + xrpld.net > xrpld.core -Loop: ripple.net ripple.rpc - ripple.rpc > ripple.net +Loop: xrpld.core xrpld.perflog + xrpld.perflog ~= xrpld.core -Loop: ripple.nodestore ripple.overlay - ripple.overlay ~= ripple.nodestore +Loop: xrpld.net xrpld.rpc + xrpld.rpc > xrpld.net -Loop: ripple.overlay ripple.rpc - ripple.rpc ~= ripple.overlay +Loop: xrpld.nodestore xrpld.overlay + xrpld.overlay ~= xrpld.nodestore -Loop: test.jtx test.toplevel - test.toplevel > test.jtx +Loop: xrpld.overlay xrpld.rpc + xrpld.rpc ~= xrpld.overlay -Loop: test.jtx test.unit_test - test.unit_test == test.jtx +Loop: xrpld.perflog xrpld.rpc + xrpld.rpc ~= xrpld.perflog diff --git a/Builds/levelization/results/ordering.txt b/Builds/levelization/results/ordering.txt index ed54065d03e..87f9b03a54e 100644 --- a/Builds/levelization/results/ordering.txt +++ b/Builds/levelization/results/ordering.txt @@ -1,229 +1,203 @@ -ripple.app > ripple.basics -ripple.app > ripple.beast -ripple.app > ripple.conditions -ripple.app > ripple.consensus -ripple.app > ripple.crypto -ripple.app > ripple.json -ripple.app > ripple.protocol -ripple.app > ripple.resource -ripple.app > test.unit_test -ripple.basics > ripple.beast -ripple.conditions > ripple.basics -ripple.conditions > ripple.protocol -ripple.consensus > ripple.basics -ripple.consensus > ripple.beast -ripple.consensus > ripple.json -ripple.consensus > ripple.protocol -ripple.core > ripple.beast -ripple.core > ripple.json -ripple.core > ripple.protocol -ripple.crypto > ripple.basics -ripple.json > ripple.beast -ripple.ledger > ripple.basics -ripple.ledger > ripple.beast -ripple.ledger > ripple.core -ripple.ledger > ripple.json -ripple.ledger > ripple.protocol -ripple.net > ripple.basics -ripple.net > ripple.beast -ripple.net > ripple.json -ripple.net > ripple.protocol -ripple.net > ripple.resource -ripple.nodestore > ripple.basics -ripple.nodestore > ripple.beast -ripple.nodestore > ripple.core -ripple.nodestore > ripple.json -ripple.nodestore > ripple.protocol -ripple.nodestore > ripple.unity -ripple.overlay > ripple.basics -ripple.overlay > ripple.beast -ripple.overlay > ripple.core -ripple.overlay > ripple.json -ripple.overlay > ripple.peerfinder -ripple.overlay > ripple.protocol -ripple.overlay > ripple.resource -ripple.overlay > ripple.server -ripple.peerfinder > ripple.basics -ripple.peerfinder > ripple.beast -ripple.peerfinder > ripple.core -ripple.peerfinder > ripple.protocol -ripple.perflog > ripple.basics -ripple.perflog > ripple.beast -ripple.perflog > ripple.core -ripple.perflog > ripple.json -ripple.perflog > ripple.nodestore -ripple.perflog > ripple.protocol -ripple.perflog > ripple.rpc -ripple.protocol > ripple.beast -ripple.protocol > ripple.crypto -ripple.protocol > ripple.json -ripple.resource > ripple.basics -ripple.resource > ripple.beast -ripple.resource > ripple.json -ripple.resource > ripple.protocol -ripple.rpc > ripple.basics -ripple.rpc > ripple.beast -ripple.rpc > ripple.core -ripple.rpc > ripple.crypto -ripple.rpc > ripple.json -ripple.rpc > ripple.ledger -ripple.rpc > ripple.nodestore -ripple.rpc > ripple.protocol -ripple.rpc > ripple.resource -ripple.rpc > ripple.server -ripple.rpc > ripple.shamap -ripple.server > ripple.basics -ripple.server > ripple.beast -ripple.server > ripple.crypto -ripple.server > ripple.json -ripple.server > ripple.protocol -ripple.shamap > ripple.basics -ripple.shamap > ripple.beast -ripple.shamap > ripple.crypto -ripple.shamap > ripple.nodestore -ripple.shamap > ripple.protocol -test.app > ripple.app -test.app > ripple.basics -test.app > ripple.beast -test.app > ripple.core -test.app > ripple.json -test.app > ripple.ledger -test.app > ripple.overlay -test.app > ripple.protocol -test.app > ripple.resource -test.app > ripple.rpc +libxrpl.basics > xrpl.basics +libxrpl.basics > xrpl.protocol +libxrpl.crypto > xrpl.basics +libxrpl.json > xrpl.basics +libxrpl.json > xrpl.json +libxrpl.protocol > xrpl.basics +libxrpl.protocol > xrpl.json +libxrpl.protocol > xrpl.protocol +libxrpl.resource > xrpl.basics +libxrpl.resource > xrpl.resource +libxrpl.server > xrpl.basics +libxrpl.server > xrpl.json +libxrpl.server > xrpl.protocol +libxrpl.server > xrpl.server test.app > test.jtx test.app > test.rpc test.app > test.toplevel test.app > test.unit_test -test.basics > ripple.basics -test.basics > ripple.beast -test.basics > ripple.json -test.basics > ripple.protocol -test.basics > ripple.rpc +test.app > xrpl.basics +test.app > xrpld.app +test.app > xrpld.core +test.app > xrpld.ledger +test.app > xrpld.overlay +test.app > xrpld.rpc +test.app > xrpl.json +test.app > xrpl.protocol +test.app > xrpl.resource test.basics > test.jtx test.basics > test.unit_test -test.beast > ripple.basics -test.beast > ripple.beast -test.conditions > ripple.basics -test.conditions > ripple.beast -test.conditions > ripple.conditions -test.consensus > ripple.app -test.consensus > ripple.basics -test.consensus > ripple.beast -test.consensus > ripple.consensus -test.consensus > ripple.ledger +test.basics > xrpl.basics +test.basics > xrpld.perflog +test.basics > xrpld.rpc +test.basics > xrpl.json +test.basics > xrpl.protocol +test.beast > xrpl.basics +test.conditions > xrpl.basics +test.conditions > xrpld.conditions test.consensus > test.csf test.consensus > test.toplevel test.consensus > test.unit_test -test.core > ripple.basics -test.core > ripple.beast -test.core > ripple.core -test.core > ripple.crypto -test.core > ripple.json -test.core > ripple.server +test.consensus > xrpl.basics +test.consensus > xrpld.app +test.consensus > xrpld.consensus +test.consensus > xrpld.ledger test.core > test.jtx test.core > test.toplevel test.core > test.unit_test -test.csf > ripple.basics -test.csf > ripple.beast -test.csf > ripple.consensus -test.csf > ripple.json -test.csf > ripple.protocol -test.json > ripple.beast -test.json > ripple.json +test.core > xrpl.basics +test.core > xrpld.core +test.core > xrpld.perflog +test.core > xrpl.json +test.core > xrpl.server +test.csf > xrpl.basics +test.csf > xrpld.consensus +test.csf > xrpl.json +test.csf > xrpl.protocol test.json > test.jtx -test.jtx > ripple.app -test.jtx > ripple.basics -test.jtx > ripple.beast -test.jtx > ripple.consensus -test.jtx > ripple.core -test.jtx > ripple.json -test.jtx > ripple.ledger -test.jtx > ripple.net -test.jtx > ripple.protocol -test.jtx > ripple.resource -test.jtx > ripple.rpc -test.jtx > ripple.server -test.ledger > ripple.app -test.ledger > ripple.basics -test.ledger > ripple.beast -test.ledger > ripple.core -test.ledger > ripple.ledger -test.ledger > ripple.protocol +test.json > xrpl.json +test.jtx > xrpl.basics +test.jtx > xrpld.app +test.jtx > xrpld.consensus +test.jtx > xrpld.core +test.jtx > xrpld.ledger +test.jtx > xrpld.net +test.jtx > xrpld.rpc +test.jtx > xrpl.json +test.jtx > xrpl.protocol +test.jtx > xrpl.resource +test.jtx > xrpl.server test.ledger > test.jtx test.ledger > test.toplevel -test.net > ripple.net +test.ledger > xrpl.basics +test.ledger > xrpld.app +test.ledger > xrpld.core +test.ledger > xrpld.ledger +test.ledger > xrpl.protocol test.net > test.jtx test.net > test.toplevel test.net > test.unit_test -test.nodestore > ripple.app -test.nodestore > ripple.basics -test.nodestore > ripple.beast -test.nodestore > ripple.core -test.nodestore > ripple.nodestore -test.nodestore > ripple.protocol -test.nodestore > ripple.unity +test.net > xrpld.net test.nodestore > test.jtx test.nodestore > test.toplevel test.nodestore > test.unit_test -test.overlay > ripple.app -test.overlay > ripple.basics -test.overlay > ripple.beast -test.overlay > ripple.overlay -test.overlay > ripple.peerfinder -test.overlay > ripple.protocol -test.overlay > ripple.shamap +test.nodestore > xrpl.basics +test.nodestore > xrpld.app +test.nodestore > xrpld.core +test.nodestore > xrpld.nodestore +test.nodestore > xrpld.unity +test.nodestore > xrpl.protocol test.overlay > test.jtx test.overlay > test.unit_test -test.peerfinder > ripple.basics -test.peerfinder > ripple.beast -test.peerfinder > ripple.core -test.peerfinder > ripple.peerfinder -test.peerfinder > ripple.protocol +test.overlay > xrpl.basics +test.overlay > xrpld.app +test.overlay > xrpld.overlay +test.overlay > xrpld.peerfinder +test.overlay > xrpld.shamap +test.overlay > xrpl.protocol test.peerfinder > test.beast test.peerfinder > test.unit_test -test.protocol > ripple.basics -test.protocol > ripple.beast -test.protocol > ripple.crypto -test.protocol > ripple.json -test.protocol > ripple.protocol +test.peerfinder > xrpl.basics +test.peerfinder > xrpld.core +test.peerfinder > xrpld.peerfinder +test.peerfinder > xrpl.protocol test.protocol > test.toplevel -test.resource > ripple.basics -test.resource > ripple.beast -test.resource > ripple.resource +test.protocol > xrpl.basics +test.protocol > xrpl.json +test.protocol > xrpl.protocol test.resource > test.unit_test -test.rpc > ripple.app -test.rpc > ripple.basics -test.rpc > ripple.beast -test.rpc > ripple.core -test.rpc > ripple.json -test.rpc > ripple.net -test.rpc > ripple.nodestore -test.rpc > ripple.overlay -test.rpc > ripple.protocol -test.rpc > ripple.resource -test.rpc > ripple.rpc +test.resource > xrpl.basics +test.resource > xrpl.resource test.rpc > test.jtx test.rpc > test.nodestore test.rpc > test.toplevel -test.server > ripple.app -test.server > ripple.basics -test.server > ripple.beast -test.server > ripple.core -test.server > ripple.json -test.server > ripple.rpc -test.server > ripple.server +test.rpc > xrpl.basics +test.rpc > xrpld.app +test.rpc > xrpld.core +test.rpc > xrpld.net +test.rpc > xrpld.nodestore +test.rpc > xrpld.overlay +test.rpc > xrpld.rpc +test.rpc > xrpl.json +test.rpc > xrpl.protocol +test.rpc > xrpl.resource test.server > test.jtx test.server > test.toplevel test.server > test.unit_test -test.shamap > ripple.basics -test.shamap > ripple.beast -test.shamap > ripple.nodestore -test.shamap > ripple.protocol -test.shamap > ripple.shamap +test.server > xrpl.basics +test.server > xrpld.app +test.server > xrpld.core +test.server > xrpld.rpc +test.server > xrpl.json +test.server > xrpl.server test.shamap > test.unit_test -test.toplevel > ripple.json +test.shamap > xrpl.basics +test.shamap > xrpld.nodestore +test.shamap > xrpld.shamap +test.shamap > xrpl.protocol test.toplevel > test.csf -test.unit_test > ripple.basics -test.unit_test > ripple.beast +test.toplevel > xrpl.json +test.unit_test > xrpl.basics +xrpl.protocol > xrpl.basics +xrpl.protocol > xrpl.json +xrpl.resource > xrpl.basics +xrpl.resource > xrpl.json +xrpl.resource > xrpl.protocol +xrpl.server > xrpl.basics +xrpl.server > xrpl.json +xrpl.server > xrpl.protocol +xrpld.app > test.unit_test +xrpld.app > xrpl.basics +xrpld.app > xrpld.conditions +xrpld.app > xrpld.consensus +xrpld.app > xrpld.perflog +xrpld.app > xrpl.json +xrpld.app > xrpl.protocol +xrpld.app > xrpl.resource +xrpld.conditions > xrpl.basics +xrpld.conditions > xrpl.protocol +xrpld.consensus > xrpl.basics +xrpld.consensus > xrpl.json +xrpld.consensus > xrpl.protocol +xrpld.core > xrpl.basics +xrpld.core > xrpl.json +xrpld.core > xrpl.protocol +xrpld.ledger > xrpl.basics +xrpld.ledger > xrpld.core +xrpld.ledger > xrpl.json +xrpld.ledger > xrpl.protocol +xrpld.net > xrpl.basics +xrpld.net > xrpl.json +xrpld.net > xrpl.protocol +xrpld.net > xrpl.resource +xrpld.nodestore > xrpl.basics +xrpld.nodestore > xrpld.core +xrpld.nodestore > xrpld.unity +xrpld.nodestore > xrpl.json +xrpld.nodestore > xrpl.protocol +xrpld.overlay > xrpl.basics +xrpld.overlay > xrpld.core +xrpld.overlay > xrpld.peerfinder +xrpld.overlay > xrpl.json +xrpld.overlay > xrpl.protocol +xrpld.overlay > xrpl.resource +xrpld.overlay > xrpl.server +xrpld.peerfinder > xrpl.basics +xrpld.peerfinder > xrpld.core +xrpld.peerfinder > xrpl.protocol +xrpld.perflog > xrpl.basics +xrpld.perflog > xrpld.nodestore +xrpld.perflog > xrpl.json +xrpld.perflog > xrpl.protocol +xrpld.rpc > xrpl.basics +xrpld.rpc > xrpld.core +xrpld.rpc > xrpld.ledger +xrpld.rpc > xrpld.nodestore +xrpld.rpc > xrpld.shamap +xrpld.rpc > xrpl.json +xrpld.rpc > xrpl.protocol +xrpld.rpc > xrpl.resource +xrpld.rpc > xrpl.server +xrpld.shamap > xrpl.basics +xrpld.shamap > xrpld.nodestore +xrpld.shamap > xrpl.protocol From 7cf4611d7c57e2d0431f2f147cff0a3bc69363f7 Mon Sep 17 00:00:00 2001 From: John Freeman Date: Thu, 20 Jun 2024 13:24:16 -0500 Subject: [PATCH 19/82] Ignore restructuring commits (#4997) --- .git-blame-ignore-revs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index de2d90d36ec..514f90fc5f5 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -6,3 +6,7 @@ e2384885f5f630c8f0ffe4bf21a169b433a16858 241b9ddde9e11beb7480600fd5ed90e1ef109b21 760f16f56835663d9286bd29294d074de26a7ba6 0eebe6a5f4246fced516d52b83ec4e7f47373edd +2189cc950c0cebb89e4e2fa3b2d8817205bf7cef +b9d007813378ad0ff45660dc07285b823c7e9855 +fe9a5365b8a52d4acc42eb27369247e6f238a4f9 +9a93577314e6a8d4b4a8368cc9d2b15a5d8303e8 From ef02893f2f638fd10ff8a11ee12b4a52619c89de Mon Sep 17 00:00:00 2001 From: seelabs Date: Thu, 20 Jun 2024 15:30:07 -0400 Subject: [PATCH 20/82] Set version to 2.3.0-b1 --- src/libxrpl/protocol/BuildInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libxrpl/protocol/BuildInfo.cpp b/src/libxrpl/protocol/BuildInfo.cpp index 9139f29e83c..b0a7bcc9ed7 100644 --- a/src/libxrpl/protocol/BuildInfo.cpp +++ b/src/libxrpl/protocol/BuildInfo.cpp @@ -33,7 +33,7 @@ namespace BuildInfo { // and follow the format described at http://semver.org/ //------------------------------------------------------------------------------ // clang-format off -char const* const versionString = "2.2.0" +char const* const versionString = "2.3.0-b1" // clang-format on #if defined(DEBUG) || defined(SANITIZER) From 9fec615dcab5de7f9b422dcda57e82480c20184a Mon Sep 17 00:00:00 2001 From: Scott Schurr Date: Thu, 27 Jun 2024 11:52:02 -0700 Subject: [PATCH 21/82] fixInnerObjTemplate2 amendment (#5047) * fixInnerObjTemplate2 amendment: Apply inner object templates to all remaining (non-AMM) inner objects. Adds a unit test for applying the template to sfMajorities. Other remaining inner objects showed no problems having templates applied. * Move CMake directory * Rearrange sources * Rewrite includes * Recompute loops --------- Co-authored-by: Pretty Printer --- include/xrpl/protocol/Feature.h | 3 +- include/xrpl/protocol/STObject.h | 3 +- src/libxrpl/protocol/Feature.cpp | 1 + src/libxrpl/protocol/STObject.cpp | 13 +- src/libxrpl/protocol/XChainAttestations.cpp | 10 +- src/test/rpc/LedgerData_test.cpp | 355 ++++++++++---------- src/xrpld/app/ledger/Ledger.cpp | 2 +- src/xrpld/app/misc/detail/AMMUtils.cpp | 4 +- src/xrpld/app/tx/detail/AMMVote.cpp | 6 +- src/xrpld/app/tx/detail/Change.cpp | 8 +- src/xrpld/app/tx/detail/SetSignerList.cpp | 6 +- src/xrpld/rpc/detail/TransactionSign.cpp | 2 +- 12 files changed, 219 insertions(+), 194 deletions(-) diff --git a/include/xrpl/protocol/Feature.h b/include/xrpl/protocol/Feature.h index d2be4c934f6..49f94b88d86 100644 --- a/include/xrpl/protocol/Feature.h +++ b/include/xrpl/protocol/Feature.h @@ -80,7 +80,7 @@ namespace detail { // Feature.cpp. Because it's only used to reserve storage, and determine how // large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than // the actual number of amendments. A LogicError on startup will verify this. -static constexpr std::size_t numFeatures = 76; +static constexpr std::size_t numFeatures = 77; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated @@ -369,6 +369,7 @@ extern uint256 const fixAMMv1_1; extern uint256 const featureNFTokenMintOffer; extern uint256 const fixReducedOffersV2; extern uint256 const fixEnforceNFTokenTrustline; +extern uint256 const fixInnerObjTemplate2; } // namespace ripple diff --git a/include/xrpl/protocol/STObject.h b/include/xrpl/protocol/STObject.h index 5259994a976..b3cef83de5f 100644 --- a/include/xrpl/protocol/STObject.h +++ b/include/xrpl/protocol/STObject.h @@ -44,7 +44,6 @@ namespace ripple { class STArray; -class Rules; inline void throwFieldNotFound(SField const& field) @@ -105,7 +104,7 @@ class STObject : public STBase, public CountedObject explicit STObject(SField const& name); static STObject - makeInnerObject(SField const& name, Rules const& rules); + makeInnerObject(SField const& name); iterator begin() const; diff --git a/src/libxrpl/protocol/Feature.cpp b/src/libxrpl/protocol/Feature.cpp index 992d51ca974..8a978955086 100644 --- a/src/libxrpl/protocol/Feature.cpp +++ b/src/libxrpl/protocol/Feature.cpp @@ -496,6 +496,7 @@ REGISTER_FIX (fixAMMv1_1, Supported::yes, VoteBehavior::De REGISTER_FEATURE(NFTokenMintOffer, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixReducedOffersV2, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixEnforceNFTokenTrustline, Supported::yes, VoteBehavior::DefaultNo); +REGISTER_FIX (fixInnerObjTemplate2, Supported::yes, VoteBehavior::DefaultNo); // The following amendments are obsolete, but must remain supported // because they could potentially get enabled. diff --git a/src/libxrpl/protocol/STObject.cpp b/src/libxrpl/protocol/STObject.cpp index a369974c2d6..bde83ec31a1 100644 --- a/src/libxrpl/protocol/STObject.cpp +++ b/src/libxrpl/protocol/STObject.cpp @@ -61,10 +61,19 @@ STObject::STObject(SerialIter& sit, SField const& name, int depth) noexcept( } STObject -STObject::makeInnerObject(SField const& name, Rules const& rules) +STObject::makeInnerObject(SField const& name) { STObject obj{name}; - if (rules.enabled(fixInnerObjTemplate)) + + // The if is complicated because inner object templates were added in + // two phases: + // 1. If there are no available Rules, then always apply the template. + // 2. fixInnerObjTemplate added templates to two AMM inner objects. + // 3. fixInnerObjTemplate2 added templates to all remaining inner objects. + std::optional const& rules = getCurrentTransactionRules(); + bool const isAMMObj = name == sfAuctionSlot || name == sfVoteEntry; + if (!rules || (rules->enabled(fixInnerObjTemplate) && isAMMObj) || + (rules->enabled(fixInnerObjTemplate2) && !isAMMObj)) { if (SOTemplate const* elements = InnerObjectFormats::getInstance().findSOTemplateBySField(name)) diff --git a/src/libxrpl/protocol/XChainAttestations.cpp b/src/libxrpl/protocol/XChainAttestations.cpp index f87f1c3e681..82e73445693 100644 --- a/src/libxrpl/protocol/XChainAttestations.cpp +++ b/src/libxrpl/protocol/XChainAttestations.cpp @@ -203,7 +203,8 @@ AttestationClaim::AttestationClaim(Json::Value const& v) STObject AttestationClaim::toSTObject() const { - STObject o{sfXChainClaimAttestationCollectionElement}; + STObject o = + STObject::makeInnerObject(sfXChainClaimAttestationCollectionElement); addHelper(o); o[sfXChainClaimID] = claimID; if (dst) @@ -345,7 +346,8 @@ AttestationCreateAccount::AttestationCreateAccount( STObject AttestationCreateAccount::toSTObject() const { - STObject o{sfXChainCreateAccountAttestationCollectionElement}; + STObject o = STObject::makeInnerObject( + sfXChainCreateAccountAttestationCollectionElement); addHelper(o); o[sfXChainAccountCreateCount] = createCount; @@ -497,7 +499,7 @@ XChainClaimAttestation::XChainClaimAttestation( STObject XChainClaimAttestation::toSTObject() const { - STObject o{sfXChainClaimProofSig}; + STObject o = STObject::makeInnerObject(sfXChainClaimProofSig); o[sfAttestationSignerAccount] = STAccount{sfAttestationSignerAccount, keyAccount}; o[sfPublicKey] = publicKey; @@ -609,7 +611,7 @@ XChainCreateAccountAttestation::XChainCreateAccountAttestation( STObject XChainCreateAccountAttestation::toSTObject() const { - STObject o{sfXChainCreateAccountProofSig}; + STObject o = STObject::makeInnerObject(sfXChainCreateAccountProofSig); o[sfAttestationSignerAccount] = STAccount{sfAttestationSignerAccount, keyAccount}; diff --git a/src/test/rpc/LedgerData_test.cpp b/src/test/rpc/LedgerData_test.cpp index 34dfb3e011b..1e4f97a935f 100644 --- a/src/test/rpc/LedgerData_test.cpp +++ b/src/test/rpc/LedgerData_test.cpp @@ -300,201 +300,214 @@ class LedgerData_test : public beast::unit_test::suite { // Put a bunch of different LedgerEntryTypes into a ledger using namespace test::jtx; - using namespace std::chrono; - Env env{*this, envconfig(validator, "")}; - Account const gw{"gateway"}; - auto const USD = gw["USD"]; - env.fund(XRP(100000), gw); - - auto makeRequest = [&env](Json::StaticString const& type) { - Json::Value jvParams; - jvParams[jss::ledger_index] = "current"; - jvParams[jss::type] = type; - return env.rpc( - "json", - "ledger_data", - boost::lexical_cast(jvParams))[jss::result]; - }; - - // Assert that state is an empty array. - for (auto const& type : - {jss::amendments, - jss::check, - jss::directory, - jss::offer, - jss::signer_list, - jss::state, - jss::ticket, - jss::escrow, - jss::payment_channel, - jss::deposit_preauth}) + // Make sure fixInnerObjTemplate2 doesn't break amendments. + for (FeatureBitset const& features : + {supported_amendments() - fixInnerObjTemplate2, + supported_amendments() | fixInnerObjTemplate2}) { - auto const jrr = makeRequest(type); - BEAST_EXPECT(checkArraySize(jrr[jss::state], 0)); - } + using namespace std::chrono; + Env env{*this, envconfig(validator, ""), features}; + + Account const gw{"gateway"}; + auto const USD = gw["USD"]; + env.fund(XRP(100000), gw); + + auto makeRequest = [&env](Json::StaticString const& type) { + Json::Value jvParams; + jvParams[jss::ledger_index] = "current"; + jvParams[jss::type] = type; + return env.rpc( + "json", + "ledger_data", + boost::lexical_cast(jvParams))[jss::result]; + }; + + // Assert that state is an empty array. + for (auto const& type : + {jss::amendments, + jss::check, + jss::directory, + jss::offer, + jss::signer_list, + jss::state, + jss::ticket, + jss::escrow, + jss::payment_channel, + jss::deposit_preauth}) + { + auto const jrr = makeRequest(type); + BEAST_EXPECT(checkArraySize(jrr[jss::state], 0)); + } - int const num_accounts = 10; + int const num_accounts = 10; - for (auto i = 0; i < num_accounts; i++) - { - Account const bob{std::string("bob") + std::to_string(i)}; - env.fund(XRP(1000), bob); - } - env(offer(Account{"bob0"}, USD(100), XRP(100))); - env.trust(Account{"bob2"}["USD"](100), Account{"bob3"}); + for (auto i = 0; i < num_accounts; i++) + { + Account const bob{std::string("bob") + std::to_string(i)}; + env.fund(XRP(1000), bob); + } + env(offer(Account{"bob0"}, USD(100), XRP(100))); + env.trust(Account{"bob2"}["USD"](100), Account{"bob3"}); - auto majorities = getMajorityAmendments(*env.closed()); - for (int i = 0; i <= 256; ++i) - { - env.close(); - majorities = getMajorityAmendments(*env.closed()); - if (!majorities.empty()) - break; - } - env(signers( - Account{"bob0"}, 1, {{Account{"bob1"}, 1}, {Account{"bob2"}, 1}})); - env(ticket::create(env.master, 1)); + auto majorities = getMajorityAmendments(*env.closed()); + for (int i = 0; i <= 256; ++i) + { + env.close(); + majorities = getMajorityAmendments(*env.closed()); + if (!majorities.empty()) + break; + } - { - Json::Value jv; - jv[jss::TransactionType] = jss::EscrowCreate; - jv[jss::Flags] = tfUniversal; - jv[jss::Account] = Account{"bob5"}.human(); - jv[jss::Destination] = Account{"bob6"}.human(); - jv[jss::Amount] = XRP(50).value().getJson(JsonOptions::none); - jv[sfFinishAfter.fieldName] = NetClock::time_point{env.now() + 10s} - .time_since_epoch() - .count(); - env(jv); - } + env(signers( + Account{"bob0"}, + 1, + {{Account{"bob1"}, 1}, {Account{"bob2"}, 1}})); + env(ticket::create(env.master, 1)); - { - Json::Value jv; - jv[jss::TransactionType] = jss::PaymentChannelCreate; - jv[jss::Flags] = tfUniversal; - jv[jss::Account] = Account{"bob6"}.human(); - jv[jss::Destination] = Account{"bob7"}.human(); - jv[jss::Amount] = XRP(100).value().getJson(JsonOptions::none); - jv[jss::SettleDelay] = NetClock::duration{10s}.count(); - jv[sfPublicKey.fieldName] = strHex(Account{"bob6"}.pk().slice()); - jv[sfCancelAfter.fieldName] = NetClock::time_point{env.now() + 300s} - .time_since_epoch() - .count(); - env(jv); - } + { + Json::Value jv; + jv[jss::TransactionType] = jss::EscrowCreate; + jv[jss::Flags] = tfUniversal; + jv[jss::Account] = Account{"bob5"}.human(); + jv[jss::Destination] = Account{"bob6"}.human(); + jv[jss::Amount] = XRP(50).value().getJson(JsonOptions::none); + jv[sfFinishAfter.fieldName] = + NetClock::time_point{env.now() + 10s} + .time_since_epoch() + .count(); + env(jv); + } - env(check::create("bob6", "bob7", XRP(100))); + { + Json::Value jv; + jv[jss::TransactionType] = jss::PaymentChannelCreate; + jv[jss::Flags] = tfUniversal; + jv[jss::Account] = Account{"bob6"}.human(); + jv[jss::Destination] = Account{"bob7"}.human(); + jv[jss::Amount] = XRP(100).value().getJson(JsonOptions::none); + jv[jss::SettleDelay] = NetClock::duration{10s}.count(); + jv[sfPublicKey.fieldName] = + strHex(Account{"bob6"}.pk().slice()); + jv[sfCancelAfter.fieldName] = + NetClock::time_point{env.now() + 300s} + .time_since_epoch() + .count(); + env(jv); + } - // bob9 DepositPreauths bob4 and bob8. - env(deposit::auth(Account{"bob9"}, Account{"bob4"})); - env(deposit::auth(Account{"bob9"}, Account{"bob8"})); - env.close(); + env(check::create("bob6", "bob7", XRP(100))); - // Now fetch each type + // bob9 DepositPreauths bob4 and bob8. + env(deposit::auth(Account{"bob9"}, Account{"bob4"})); + env(deposit::auth(Account{"bob9"}, Account{"bob8"})); + env.close(); - { // jvParams[jss::type] = "account"; - auto const jrr = makeRequest(jss::account); - BEAST_EXPECT(checkArraySize(jrr[jss::state], 12)); - for (auto const& j : jrr[jss::state]) - BEAST_EXPECT(j["LedgerEntryType"] == jss::AccountRoot); - } + // Now fetch each type - { // jvParams[jss::type] = "amendments"; - auto const jrr = makeRequest(jss::amendments); - BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); - for (auto const& j : jrr[jss::state]) - BEAST_EXPECT(j["LedgerEntryType"] == jss::Amendments); - } + { // jvParams[jss::type] = "account"; + auto const jrr = makeRequest(jss::account); + BEAST_EXPECT(checkArraySize(jrr[jss::state], 12)); + for (auto const& j : jrr[jss::state]) + BEAST_EXPECT(j["LedgerEntryType"] == jss::AccountRoot); + } - { // jvParams[jss::type] = "check"; - auto const jrr = makeRequest(jss::check); - BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); - for (auto const& j : jrr[jss::state]) - BEAST_EXPECT(j["LedgerEntryType"] == jss::Check); - } + { // jvParams[jss::type] = "amendments"; + auto const jrr = makeRequest(jss::amendments); + BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); + for (auto const& j : jrr[jss::state]) + BEAST_EXPECT(j["LedgerEntryType"] == jss::Amendments); + } - { // jvParams[jss::type] = "directory"; - auto const jrr = makeRequest(jss::directory); - BEAST_EXPECT(checkArraySize(jrr[jss::state], 9)); - for (auto const& j : jrr[jss::state]) - BEAST_EXPECT(j["LedgerEntryType"] == jss::DirectoryNode); - } + { // jvParams[jss::type] = "check"; + auto const jrr = makeRequest(jss::check); + BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); + for (auto const& j : jrr[jss::state]) + BEAST_EXPECT(j["LedgerEntryType"] == jss::Check); + } - { // jvParams[jss::type] = "fee"; - auto const jrr = makeRequest(jss::fee); - BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); - for (auto const& j : jrr[jss::state]) - BEAST_EXPECT(j["LedgerEntryType"] == jss::FeeSettings); - } + { // jvParams[jss::type] = "directory"; + auto const jrr = makeRequest(jss::directory); + BEAST_EXPECT(checkArraySize(jrr[jss::state], 9)); + for (auto const& j : jrr[jss::state]) + BEAST_EXPECT(j["LedgerEntryType"] == jss::DirectoryNode); + } - { // jvParams[jss::type] = "hashes"; - auto const jrr = makeRequest(jss::hashes); - BEAST_EXPECT(checkArraySize(jrr[jss::state], 2)); - for (auto const& j : jrr[jss::state]) - BEAST_EXPECT(j["LedgerEntryType"] == jss::LedgerHashes); - } + { // jvParams[jss::type] = "fee"; + auto const jrr = makeRequest(jss::fee); + BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); + for (auto const& j : jrr[jss::state]) + BEAST_EXPECT(j["LedgerEntryType"] == jss::FeeSettings); + } - { // jvParams[jss::type] = "offer"; - auto const jrr = makeRequest(jss::offer); - BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); - for (auto const& j : jrr[jss::state]) - BEAST_EXPECT(j["LedgerEntryType"] == jss::Offer); - } + { // jvParams[jss::type] = "hashes"; + auto const jrr = makeRequest(jss::hashes); + BEAST_EXPECT(checkArraySize(jrr[jss::state], 2)); + for (auto const& j : jrr[jss::state]) + BEAST_EXPECT(j["LedgerEntryType"] == jss::LedgerHashes); + } - { // jvParams[jss::type] = "signer_list"; - auto const jrr = makeRequest(jss::signer_list); - BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); - for (auto const& j : jrr[jss::state]) - BEAST_EXPECT(j["LedgerEntryType"] == jss::SignerList); - } + { // jvParams[jss::type] = "offer"; + auto const jrr = makeRequest(jss::offer); + BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); + for (auto const& j : jrr[jss::state]) + BEAST_EXPECT(j["LedgerEntryType"] == jss::Offer); + } - { // jvParams[jss::type] = "state"; - auto const jrr = makeRequest(jss::state); - BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); - for (auto const& j : jrr[jss::state]) - BEAST_EXPECT(j["LedgerEntryType"] == jss::RippleState); - } + { // jvParams[jss::type] = "signer_list"; + auto const jrr = makeRequest(jss::signer_list); + BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); + for (auto const& j : jrr[jss::state]) + BEAST_EXPECT(j["LedgerEntryType"] == jss::SignerList); + } - { // jvParams[jss::type] = "ticket"; - auto const jrr = makeRequest(jss::ticket); - BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); - for (auto const& j : jrr[jss::state]) - BEAST_EXPECT(j["LedgerEntryType"] == jss::Ticket); - } + { // jvParams[jss::type] = "state"; + auto const jrr = makeRequest(jss::state); + BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); + for (auto const& j : jrr[jss::state]) + BEAST_EXPECT(j["LedgerEntryType"] == jss::RippleState); + } - { // jvParams[jss::type] = "escrow"; - auto const jrr = makeRequest(jss::escrow); - BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); - for (auto const& j : jrr[jss::state]) - BEAST_EXPECT(j["LedgerEntryType"] == jss::Escrow); - } + { // jvParams[jss::type] = "ticket"; + auto const jrr = makeRequest(jss::ticket); + BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); + for (auto const& j : jrr[jss::state]) + BEAST_EXPECT(j["LedgerEntryType"] == jss::Ticket); + } - { // jvParams[jss::type] = "payment_channel"; - auto const jrr = makeRequest(jss::payment_channel); - BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); - for (auto const& j : jrr[jss::state]) - BEAST_EXPECT(j["LedgerEntryType"] == jss::PayChannel); - } + { // jvParams[jss::type] = "escrow"; + auto const jrr = makeRequest(jss::escrow); + BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); + for (auto const& j : jrr[jss::state]) + BEAST_EXPECT(j["LedgerEntryType"] == jss::Escrow); + } - { // jvParams[jss::type] = "deposit_preauth"; - auto const jrr = makeRequest(jss::deposit_preauth); - BEAST_EXPECT(checkArraySize(jrr[jss::state], 2)); - for (auto const& j : jrr[jss::state]) - BEAST_EXPECT(j["LedgerEntryType"] == jss::DepositPreauth); - } + { // jvParams[jss::type] = "payment_channel"; + auto const jrr = makeRequest(jss::payment_channel); + BEAST_EXPECT(checkArraySize(jrr[jss::state], 1)); + for (auto const& j : jrr[jss::state]) + BEAST_EXPECT(j["LedgerEntryType"] == jss::PayChannel); + } - { // jvParams[jss::type] = "misspelling"; - Json::Value jvParams; - jvParams[jss::ledger_index] = "current"; - jvParams[jss::type] = "misspelling"; - auto const jrr = env.rpc( - "json", - "ledger_data", - boost::lexical_cast(jvParams))[jss::result]; - BEAST_EXPECT(jrr.isMember("error")); - BEAST_EXPECT(jrr["error"] == "invalidParams"); - BEAST_EXPECT(jrr["error_message"] == "Invalid field 'type'."); + { // jvParams[jss::type] = "deposit_preauth"; + auto const jrr = makeRequest(jss::deposit_preauth); + BEAST_EXPECT(checkArraySize(jrr[jss::state], 2)); + for (auto const& j : jrr[jss::state]) + BEAST_EXPECT(j["LedgerEntryType"] == jss::DepositPreauth); + } + + { // jvParams[jss::type] = "misspelling"; + Json::Value jvParams; + jvParams[jss::ledger_index] = "current"; + jvParams[jss::type] = "misspelling"; + auto const jrr = env.rpc( + "json", + "ledger_data", + boost::lexical_cast(jvParams))[jss::result]; + BEAST_EXPECT(jrr.isMember("error")); + BEAST_EXPECT(jrr["error"] == "invalidParams"); + BEAST_EXPECT(jrr["error_message"] == "Invalid field 'type'."); + } } } diff --git a/src/xrpld/app/ledger/Ledger.cpp b/src/xrpld/app/ledger/Ledger.cpp index afed8f4870b..bcd3b6d4ba7 100644 --- a/src/xrpld/app/ledger/Ledger.cpp +++ b/src/xrpld/app/ledger/Ledger.cpp @@ -793,7 +793,7 @@ Ledger::updateNegativeUNL() if (hasToDisable) { - newNUnl.emplace_back(sfDisabledValidator); + newNUnl.push_back(STObject::makeInnerObject(sfDisabledValidator)); newNUnl.back().setFieldVL( sfPublicKey, sle->getFieldVL(sfValidatorToDisable)); newNUnl.back().setFieldU32(sfFirstLedgerSequence, seq()); diff --git a/src/xrpld/app/misc/detail/AMMUtils.cpp b/src/xrpld/app/misc/detail/AMMUtils.cpp index 0014ab01118..efc80cf17b6 100644 --- a/src/xrpld/app/misc/detail/AMMUtils.cpp +++ b/src/xrpld/app/misc/detail/AMMUtils.cpp @@ -312,7 +312,7 @@ initializeFeeAuctionVote( auto const& rules = view.rules(); // AMM creator gets the voting slot. STArray voteSlots; - STObject voteEntry = STObject::makeInnerObject(sfVoteEntry, rules); + STObject voteEntry = STObject::makeInnerObject(sfVoteEntry); if (tfee != 0) voteEntry.setFieldU16(sfTradingFee, tfee); voteEntry.setFieldU32(sfVoteWeight, VOTE_WEIGHT_SCALE_FACTOR); @@ -325,7 +325,7 @@ initializeFeeAuctionVote( if (rules.enabled(fixInnerObjTemplate) && !ammSle->isFieldPresent(sfAuctionSlot)) { - STObject auctionSlot = STObject::makeInnerObject(sfAuctionSlot, rules); + STObject auctionSlot = STObject::makeInnerObject(sfAuctionSlot); ammSle->set(std::move(auctionSlot)); } STObject& auctionSlot = ammSle->peekFieldObject(sfAuctionSlot); diff --git a/src/xrpld/app/tx/detail/AMMVote.cpp b/src/xrpld/app/tx/detail/AMMVote.cpp index 6da320f83e2..c4b6c612c63 100644 --- a/src/xrpld/app/tx/detail/AMMVote.cpp +++ b/src/xrpld/app/tx/detail/AMMVote.cpp @@ -104,7 +104,7 @@ applyVote( Number den{0}; // Account already has vote entry bool foundAccount = false; - auto const& rules = ctx_.view().rules(); + // Iterate over the current vote entries and update each entry // per current total tokens balance and each LP tokens balance. // Find the entry with the least tokens and whether the account @@ -120,7 +120,7 @@ applyVote( continue; } auto feeVal = entry[sfTradingFee]; - STObject newEntry = STObject::makeInnerObject(sfVoteEntry, rules); + STObject newEntry = STObject::makeInnerObject(sfVoteEntry); // The account already has the vote entry. if (account == account_) { @@ -159,7 +159,7 @@ applyVote( { auto update = [&](std::optional const& minPos = std::nullopt) { - STObject newEntry = STObject::makeInnerObject(sfVoteEntry, rules); + STObject newEntry = STObject::makeInnerObject(sfVoteEntry); if (feeNew != 0) newEntry.setFieldU16(sfTradingFee, feeNew); newEntry.setFieldU32( diff --git a/src/xrpld/app/tx/detail/Change.cpp b/src/xrpld/app/tx/detail/Change.cpp index 0ebdb1e93ba..909f35fc799 100644 --- a/src/xrpld/app/tx/detail/Change.cpp +++ b/src/xrpld/app/tx/detail/Change.cpp @@ -300,11 +300,11 @@ Change::applyAmendment() if (gotMajority) { // This amendment now has a majority - newMajorities.push_back(STObject(sfMajority)); + newMajorities.push_back(STObject::makeInnerObject(sfMajority)); auto& entry = newMajorities.back(); - entry.emplace_back(STUInt256(sfAmendment, amendment)); - entry.emplace_back(STUInt32( - sfCloseTime, view().parentCloseTime().time_since_epoch().count())); + entry[sfAmendment] = amendment; + entry[sfCloseTime] = + view().parentCloseTime().time_since_epoch().count(); if (!ctx_.app.getAmendmentTable().isSupported(amendment)) { diff --git a/src/xrpld/app/tx/detail/SetSignerList.cpp b/src/xrpld/app/tx/detail/SetSignerList.cpp index 37790f14f40..0949fbbe775 100644 --- a/src/xrpld/app/tx/detail/SetSignerList.cpp +++ b/src/xrpld/app/tx/detail/SetSignerList.cpp @@ -416,11 +416,11 @@ SetSignerList::writeSignersToSLE( STArray toLedger(signers_.size()); for (auto const& entry : signers_) { - toLedger.emplace_back(sfSignerEntry); + toLedger.push_back(STObject::makeInnerObject(sfSignerEntry)); STObject& obj = toLedger.back(); obj.reserve(2); - obj.setAccountID(sfAccount, entry.account); - obj.setFieldU16(sfSignerWeight, entry.weight); + obj[sfAccount] = entry.account; + obj[sfSignerWeight] = entry.weight; // This is a defensive check to make absolutely sure we will never write // a tag into the ledger while featureExpandedSignerList is not enabled diff --git a/src/xrpld/rpc/detail/TransactionSign.cpp b/src/xrpld/rpc/detail/TransactionSign.cpp index 5ea895b60e4..1fee84c683b 100644 --- a/src/xrpld/rpc/detail/TransactionSign.cpp +++ b/src/xrpld/rpc/detail/TransactionSign.cpp @@ -1051,7 +1051,7 @@ transactionSignFor( auto& sttx = preprocResult.second; { // Make the signer object that we'll inject. - STObject signer(sfSigner); + STObject signer = STObject::makeInnerObject(sfSigner); signer[sfAccount] = *signerAccountID; signer.setFieldVL(sfTxnSignature, signForParams.getSignature()); signer.setFieldVL( From e1534a3200834ac8ed66f0413dee94b20f2250d6 Mon Sep 17 00:00:00 2001 From: yinyiqian1 Date: Tue, 2 Jul 2024 14:58:03 -0400 Subject: [PATCH 22/82] fix "account_nfts" with unassociated marker returning issue (#5045) * fix "account_nfts" with unassociated marker returning issue * create unit test for fixing nft page invalid marker not returning error add more test change test name create unit test * fix "account_nfts" with unassociated marker returning issue * fix "account_nfts" with unassociated marker returning issue * fix "account_nfts" with unassociated marker returning issue * fix "account_nfts" with unassociated marker returning issue * fix "account_nfts" with unassociated marker returning issue * fix "account_nfts" with unassociated marker returning issue * fix "account_nfts" with unassociated marker returning issue * fix "account_nfts" with unassociated marker returning issue * [FOLD] accumulated review suggestions * move BEAST check out of lambda function --------- Authored-by: Scott Schurr --- src/test/rpc/AccountObjects_test.cpp | 125 ++++++++++++++++++++++ src/xrpld/app/tx/detail/NFTokenMint.h | 1 + src/xrpld/rpc/handlers/AccountObjects.cpp | 28 +++-- 3 files changed, 148 insertions(+), 6 deletions(-) diff --git a/src/test/rpc/AccountObjects_test.cpp b/src/test/rpc/AccountObjects_test.cpp index 18291bf2b95..efa9e10cc34 100644 --- a/src/test/rpc/AccountObjects_test.cpp +++ b/src/test/rpc/AccountObjects_test.cpp @@ -20,10 +20,12 @@ #include #include #include +#include #include #include #include #include +#include #include @@ -1032,6 +1034,128 @@ class AccountObjects_test : public beast::unit_test::suite BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::hashes), 0)); } + void + testNFTsMarker() + { + // there's some bug found in account_nfts method that it did not + // return invalid params when providing unassociated nft marker. + // this test tests both situations when providing valid nft marker + // and unassociated nft marker. + testcase("NFTsMarker"); + + using namespace jtx; + Env env(*this); + + Account const bob{"bob"}; + env.fund(XRP(10000), bob); + + static constexpr unsigned nftsSize = 10; + for (unsigned i = 0; i < nftsSize; i++) + { + env(token::mint(bob, 0)); + } + + env.close(); + + // save the NFTokenIDs to use later + std::vector tokenIDs; + { + Json::Value params; + params[jss::account] = bob.human(); + params[jss::ledger_index] = "validated"; + Json::Value const resp = + env.rpc("json", "account_nfts", to_string(params)); + Json::Value const& nfts = resp[jss::result][jss::account_nfts]; + for (Json::Value const& nft : nfts) + tokenIDs.push_back(nft["NFTokenID"]); + } + + // this lambda function is used to check if the account_nfts method + // returns the correct token information. lastIndex is used to query the + // last marker. + auto compareNFTs = [&tokenIDs, &env, &bob]( + unsigned const limit, unsigned const lastIndex) { + Json::Value params; + params[jss::account] = bob.human(); + params[jss::limit] = limit; + params[jss::marker] = tokenIDs[lastIndex]; + params[jss::ledger_index] = "validated"; + Json::Value const resp = + env.rpc("json", "account_nfts", to_string(params)); + + if (resp[jss::result].isMember(jss::error)) + return false; + + Json::Value const& nfts = resp[jss::result][jss::account_nfts]; + unsigned const nftsCount = tokenIDs.size() - lastIndex - 1 < limit + ? tokenIDs.size() - lastIndex - 1 + : limit; + + if (nfts.size() != nftsCount) + return false; + + for (unsigned i = 0; i < nftsCount; i++) + { + if (nfts[i]["NFTokenID"] != tokenIDs[lastIndex + 1 + i]) + return false; + } + + return true; + }; + + // test a valid marker which is equal to the third tokenID + BEAST_EXPECT(compareNFTs(4, 2)); + + // test a valid marker which is equal to the 8th tokenID + BEAST_EXPECT(compareNFTs(4, 7)); + + // lambda that holds common code for invalid cases. + auto testInvalidMarker = [&env, &bob]( + auto marker, char const* errorMessage) { + Json::Value params; + params[jss::account] = bob.human(); + params[jss::limit] = 4; + params[jss::ledger_index] = jss::validated; + params[jss::marker] = marker; + Json::Value const resp = + env.rpc("json", "account_nfts", to_string(params)); + return resp[jss::result][jss::error_message] == errorMessage; + }; + + // test an invalid marker that is not a string + BEAST_EXPECT( + testInvalidMarker(17, "Invalid field \'marker\', not string.")); + + // test an invalid marker that has a non-hex character + BEAST_EXPECT(testInvalidMarker( + "00000000F51DFC2A09D62CBBA1DFBDD4691DAC96AD98B900000000000000000G", + "Invalid field \'marker\'.")); + + // this lambda function is used to create some fake marker using given + // taxon and sequence because we want to test some unassociated markers + // later + auto createFakeNFTMarker = [](AccountID const& issuer, + std::uint32_t taxon, + std::uint32_t tokenSeq, + std::uint16_t flags = 0, + std::uint16_t fee = 0) { + // the marker has the exact same format as an NFTokenID + return to_string(NFTokenMint::createNFTokenID( + flags, fee, issuer, nft::toTaxon(taxon), tokenSeq)); + }; + + // test an unassociated marker which does not exist in the NFTokenIDs + BEAST_EXPECT(testInvalidMarker( + createFakeNFTMarker(bob.id(), 0x000000000, 0x00000000), + "Invalid field \'marker\'.")); + + // test an unassociated marker which exceeds the maximum value of the + // existing NFTokenID + BEAST_EXPECT(testInvalidMarker( + createFakeNFTMarker(bob.id(), 0xFFFFFFFF, 0xFFFFFFFF), + "Invalid field \'marker\'.")); + } + void run() override { @@ -1039,6 +1163,7 @@ class AccountObjects_test : public beast::unit_test::suite testUnsteppedThenStepped(); testUnsteppedThenSteppedWithNFTs(); testObjectTypes(); + testNFTsMarker(); } }; diff --git a/src/xrpld/app/tx/detail/NFTokenMint.h b/src/xrpld/app/tx/detail/NFTokenMint.h index e0eb54bbc93..c95fd5944e4 100644 --- a/src/xrpld/app/tx/detail/NFTokenMint.h +++ b/src/xrpld/app/tx/detail/NFTokenMint.h @@ -22,6 +22,7 @@ #include #include +#include namespace ripple { diff --git a/src/xrpld/rpc/handlers/AccountObjects.cpp b/src/xrpld/rpc/handlers/AccountObjects.cpp index dfc4e9b3388..32fe15ec264 100644 --- a/src/xrpld/rpc/handlers/AccountObjects.cpp +++ b/src/xrpld/rpc/handlers/AccountObjects.cpp @@ -75,8 +75,9 @@ doAccountNFTs(RPC::JsonContext& context) return *err; uint256 marker; + bool const markerSet = params.isMember(jss::marker); - if (params.isMember(jss::marker)) + if (markerSet) { auto const& m = params[jss::marker]; if (!m.isString()) @@ -98,6 +99,7 @@ doAccountNFTs(RPC::JsonContext& context) // Continue iteration from the current page: bool pastMarker = marker.isZero(); + bool markerFound = false; uint256 const maskedMarker = marker & nft::pageMask; while (cp) { @@ -119,12 +121,23 @@ doAccountNFTs(RPC::JsonContext& context) uint256 const nftokenID = o[sfNFTokenID]; uint256 const maskedNftokenID = nftokenID & nft::pageMask; - if (!pastMarker && maskedNftokenID < maskedMarker) - continue; + if (!pastMarker) + { + if (maskedNftokenID < maskedMarker) + continue; - if (!pastMarker && maskedNftokenID == maskedMarker && - nftokenID <= marker) - continue; + if (maskedNftokenID == maskedMarker && nftokenID < marker) + continue; + + if (nftokenID == marker) + { + markerFound = true; + continue; + } + } + + if (markerSet && !markerFound) + return RPC::invalid_field_error(jss::marker); pastMarker = true; @@ -155,6 +168,9 @@ doAccountNFTs(RPC::JsonContext& context) cp = nullptr; } + if (markerSet && !markerFound) + return RPC::invalid_field_error(jss::marker); + result[jss::account] = toBase58(accountID); context.loadType = Resource::feeMediumBurdenRPC; return result; From 7a1b238035b4f798df3d931d323c8314bf1cb54c Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Tue, 2 Jul 2024 20:42:56 +0100 Subject: [PATCH 23/82] Bump codecov plugin version to version 4.5.0 (#5055) This version includes fix https://github.com/codecov/codecov-action/pull/1471 which should end the codecov upload errors due to throttling. --- .github/workflows/nix.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index da61963b3f2..77cd50d9d68 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -222,7 +222,7 @@ jobs: - name: upload coverage report uses: wandalen/wretry.action@v1.4.10 with: - action: codecov/codecov-action@v4.3.0 + action: codecov/codecov-action@v4.5.0 with: | files: coverage.xml fail_ci_if_error: true From a17ccca61559e451b7047df7bb129c79f5ad4e05 Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Fri, 5 Jul 2024 13:27:15 -0400 Subject: [PATCH 24/82] Invariant: prevent a deleted account from leaving (most) artifacts on the ledger. (#4663) * Add feature / amendment "InvariantsV1_1" * Adds invariant AccountRootsDeletedClean: * Checks that a deleted account doesn't leave any directly accessible artifacts behind. * Always tests, but only changes the transaction result if featureInvariantsV1_1 is enabled. * Unit tests. * Resolves #4638 * [FOLD] Review feedback from @gregtatcam: * Fix unused variable warning * Improve Invariant test const correctness * [FOLD] Review feedback from @mvadari: * Centralize the account keylet function list, and some optimization * [FOLD] Some structured binding doesn't work in clang * [FOLD] Review feedback 2 from @mvadari: * Clean up and clarify some comments. * [FOLD] Change InvariantsV1_1 to unsupported * Will allow multiple PRs to be merged over time using the same amendment. * fixup! [FOLD] Change InvariantsV1_1 to unsupported * [FOLD] Update and clarify some comments. No code changes. * Move CMake directory * Rearrange sources * Rewrite includes * Recompute loops * Fix merge issue and formatting --------- Co-authored-by: Pretty Printer --- cmake/RippledCore.cmake | 1 + include/xrpl/protocol/Feature.h | 3 +- include/xrpl/protocol/Indexes.h | 21 ++ src/libxrpl/protocol/Feature.cpp | 3 + src/test/ledger/Invariants_test.cpp | 216 +++++++++++++++++++-- src/xrpld/app/misc/FeeVoteImpl.cpp | 6 +- src/xrpld/app/tx/detail/InvariantCheck.cpp | 85 ++++++++ src/xrpld/app/tx/detail/InvariantCheck.h | 31 +++ src/xrpld/app/tx/detail/NFTokenUtils.cpp | 1 + 9 files changed, 350 insertions(+), 17 deletions(-) diff --git a/cmake/RippledCore.cmake b/cmake/RippledCore.cmake index 9af3303f662..cc483034714 100644 --- a/cmake/RippledCore.cmake +++ b/cmake/RippledCore.cmake @@ -142,5 +142,6 @@ if(tests) # these two seem to produce conflicts in beast teardown template methods src/test/rpc/ValidatorRPC_test.cpp src/test/rpc/ShardArchiveHandler_test.cpp + src/test/ledger/Invariants_test.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION TRUE) endif() diff --git a/include/xrpl/protocol/Feature.h b/include/xrpl/protocol/Feature.h index 49f94b88d86..7eec46e89eb 100644 --- a/include/xrpl/protocol/Feature.h +++ b/include/xrpl/protocol/Feature.h @@ -80,7 +80,7 @@ namespace detail { // Feature.cpp. Because it's only used to reserve storage, and determine how // large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than // the actual number of amendments. A LogicError on startup will verify this. -static constexpr std::size_t numFeatures = 77; +static constexpr std::size_t numFeatures = 78; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated @@ -370,6 +370,7 @@ extern uint256 const featureNFTokenMintOffer; extern uint256 const fixReducedOffersV2; extern uint256 const fixEnforceNFTokenTrustline; extern uint256 const fixInnerObjTemplate2; +extern uint256 const featureInvariantsV1_1; } // namespace ripple diff --git a/include/xrpl/protocol/Indexes.h b/include/xrpl/protocol/Indexes.h index d57525121de..f179bbacfab 100644 --- a/include/xrpl/protocol/Indexes.h +++ b/include/xrpl/protocol/Indexes.h @@ -29,6 +29,7 @@ #include #include #include +#include #include namespace ripple { @@ -306,6 +307,26 @@ getTicketIndex(AccountID const& account, std::uint32_t uSequence); uint256 getTicketIndex(AccountID const& account, SeqProxy ticketSeq); +template +struct keyletDesc +{ + std::function function; + Json::StaticString expectedLEName; + bool includeInTests; +}; + +// This list should include all of the keylet functions that take a single +// AccountID parameter. +std::array, 6> const directAccountKeylets{ + {{&keylet::account, jss::AccountRoot, false}, + {&keylet::ownerDir, jss::DirectoryNode, true}, + {&keylet::signers, jss::SignerList, true}, + // It's normally impossible to create an item at nftpage_min, but + // test it anyway, since the invariant checks for it. + {&keylet::nftpage_min, jss::NFTokenPage, true}, + {&keylet::nftpage_max, jss::NFTokenPage, true}, + {&keylet::did, jss::DID, true}}}; + } // namespace ripple #endif diff --git a/src/libxrpl/protocol/Feature.cpp b/src/libxrpl/protocol/Feature.cpp index 8a978955086..87395b7e189 100644 --- a/src/libxrpl/protocol/Feature.cpp +++ b/src/libxrpl/protocol/Feature.cpp @@ -497,6 +497,9 @@ REGISTER_FEATURE(NFTokenMintOffer, Supported::yes, VoteBehavior::De REGISTER_FIX (fixReducedOffersV2, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixEnforceNFTokenTrustline, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixInnerObjTemplate2, Supported::yes, VoteBehavior::DefaultNo); +// InvariantsV1_1 will be changes to Supported::yes when all the +// invariants expected to be included under it are complete. +REGISTER_FEATURE(InvariantsV1_1, Supported::no, VoteBehavior::DefaultNo); // The following amendments are obsolete, but must remain supported // because they could potentially get enabled. diff --git a/src/test/ledger/Invariants_test.cpp b/src/test/ledger/Invariants_test.cpp index 1fd1543f18b..66523700a88 100644 --- a/src/test/ledger/Invariants_test.cpp +++ b/src/test/ledger/Invariants_test.cpp @@ -18,6 +18,7 @@ //============================================================================== #include +#include #include #include #include @@ -30,6 +31,15 @@ namespace ripple { class Invariants_test : public beast::unit_test::suite { + // The optional Preclose function is used to process additional transactions + // on the ledger after creating two accounts, but before closing it, and + // before the Precheck function. These should only be valid functions, and + // not direct manipulations. Preclose is not commonly used. + using Preclose = std::function; + // this is common setup/method for running a failing invariant check. The // precheck function is used to manipulate the ApplyContext with view // changes that will cause the check to fail. @@ -38,22 +48,42 @@ class Invariants_test : public beast::unit_test::suite test::jtx::Account const& b, ApplyContext& ac)>; + /** Run a specific test case to put the ledger into a state that will be + * detected by an invariant. Simulates the actions of a transaction that + * would violate an invariant. + * + * @param expect_logs One or more messages related to the failing invariant + * that should be in the log output + * @precheck See "Precheck" above + * @fee If provided, the fee amount paid by the simulated transaction. + * @tx A mock transaction that took the actions to trigger the invariant. In + * most cases, only the type matters. + * @ters The TER results expected on the two passes of the invariant + * checker. + * @preclose See "Preclose" above. Note that @preclose runs *before* + * @precheck, but is the last parameter for historical reasons + * + */ void doInvariantCheck( std::vector const& expect_logs, Precheck const& precheck, XRPAmount fee = XRPAmount{}, STTx tx = STTx{ttACCOUNT_SET, [](STObject&) {}}, - std::initializer_list ters = { - tecINVARIANT_FAILED, - tefINVARIANT_FAILED}) + std::initializer_list ters = + {tecINVARIANT_FAILED, tefINVARIANT_FAILED}, + Preclose const& preclose = {}) { using namespace test::jtx; - Env env{*this}; + FeatureBitset amendments = + supported_amendments() | featureInvariantsV1_1; + Env env{*this, amendments}; - Account A1{"A1"}; - Account A2{"A2"}; + Account const A1{"A1"}; + Account const A2{"A2"}; env.fund(XRP(1000), A1, A2); + if (preclose) + BEAST_EXPECT(preclose(A1, A2, env)); env.close(); OpenView ov{*env.current()}; @@ -162,6 +192,165 @@ class Invariants_test : public beast::unit_test::suite STTx{ttACCOUNT_DELETE, [](STObject& tx) {}}); } + void + testAccountRootsDeletedClean() + { + using namespace test::jtx; + testcase << "account root deletion left artifact"; + + for (auto const& keyletInfo : directAccountKeylets) + { + // TODO: Use structured binding once LLVM 16 is the minimum + // supported version. See also: + // https://github.com/llvm/llvm-project/issues/48582 + // https://github.com/llvm/llvm-project/commit/127bf44385424891eb04cff8e52d3f157fc2cb7c + if (!keyletInfo.includeInTests) + continue; + auto const& keyletfunc = keyletInfo.function; + auto const& type = keyletInfo.expectedLEName; + + using namespace std::string_literals; + + doInvariantCheck( + {{"account deletion left behind a "s + type.c_str() + + " object"}}, + [&](Account const& A1, Account const& A2, ApplyContext& ac) { + // Add an object to the ledger for account A1, then delete + // A1 + auto const a1 = A1.id(); + auto const sleA1 = ac.view().peek(keylet::account(a1)); + if (!sleA1) + return false; + + auto const key = std::invoke(keyletfunc, a1); + auto const newSLE = std::make_shared(key); + ac.view().insert(newSLE); + ac.view().erase(sleA1); + + return true; + }, + XRPAmount{}, + STTx{ttACCOUNT_DELETE, [](STObject& tx) {}}); + }; + + // NFT special case + doInvariantCheck( + {{"account deletion left behind a NFTokenPage object"}}, + [&](Account const& A1, Account const&, ApplyContext& ac) { + // remove an account from the view + auto const sle = ac.view().peek(keylet::account(A1.id())); + if (!sle) + return false; + ac.view().erase(sle); + return true; + }, + XRPAmount{}, + STTx{ttACCOUNT_DELETE, [](STObject& tx) {}}, + {tecINVARIANT_FAILED, tefINVARIANT_FAILED}, + [&](Account const& A1, Account const&, Env& env) { + // Preclose callback to mint the NFT which will be deleted in + // the Precheck callback above. + env(token::mint(A1)); + + return true; + }); + + // AMM special cases + AccountID ammAcctID; + uint256 ammKey; + Issue ammIssue; + doInvariantCheck( + {{"account deletion left behind a DirectoryNode object"}}, + [&](Account const& A1, Account const& A2, ApplyContext& ac) { + // Delete the AMM account without cleaning up the directory or + // deleting the AMM object + auto const sle = ac.view().peek(keylet::account(ammAcctID)); + if (!sle) + return false; + + BEAST_EXPECT(sle->at(~sfAMMID)); + BEAST_EXPECT(sle->at(~sfAMMID) == ammKey); + + ac.view().erase(sle); + + return true; + }, + XRPAmount{}, + STTx{ttAMM_WITHDRAW, [](STObject& tx) {}}, + {tecINVARIANT_FAILED, tefINVARIANT_FAILED}, + [&](Account const& A1, Account const& A2, Env& env) { + // Preclose callback to create the AMM which will be partially + // deleted in the Precheck callback above. + AMM const amm(env, A1, XRP(100), A1["USD"](50)); + ammAcctID = amm.ammAccount(); + ammKey = amm.ammID(); + ammIssue = amm.lptIssue(); + return true; + }); + doInvariantCheck( + {{"account deletion left behind a AMM object"}}, + [&](Account const& A1, Account const& A2, ApplyContext& ac) { + // Delete all the AMM's trust lines, remove the AMM from the AMM + // account's directory (this deletes the directory), and delete + // the AMM account. Do not delete the AMM object. + auto const sle = ac.view().peek(keylet::account(ammAcctID)); + if (!sle) + return false; + + BEAST_EXPECT(sle->at(~sfAMMID)); + BEAST_EXPECT(sle->at(~sfAMMID) == ammKey); + + for (auto const& trustKeylet : + {keylet::line(ammAcctID, A1["USD"]), + keylet::line(A1, ammIssue)}) + { + if (auto const line = ac.view().peek(trustKeylet); !line) + { + return false; + } + else + { + STAmount const lowLimit = line->at(sfLowLimit); + STAmount const highLimit = line->at(sfHighLimit); + BEAST_EXPECT( + trustDelete( + ac.view(), + line, + lowLimit.getIssuer(), + highLimit.getIssuer(), + ac.journal) == tesSUCCESS); + } + } + + auto const ammSle = ac.view().peek(keylet::amm(ammKey)); + if (!BEAST_EXPECT(ammSle)) + return false; + auto const ownerDirKeylet = keylet::ownerDir(ammAcctID); + + BEAST_EXPECT(ac.view().dirRemove( + ownerDirKeylet, ammSle->at(sfOwnerNode), ammKey, false)); + BEAST_EXPECT( + !ac.view().exists(ownerDirKeylet) || + ac.view().emptyDirDelete(ownerDirKeylet)); + + ac.view().erase(sle); + + return true; + }, + XRPAmount{}, + STTx{ttAMM_WITHDRAW, [](STObject& tx) {}}, + {tecINVARIANT_FAILED, tefINVARIANT_FAILED}, + [&](Account const& A1, Account const& A2, Env& env) { + // Preclose callback to create the AMM which will be partially + // deleted in the Precheck callback above. + AMM const amm(env, A1, XRP(100), A1["USD"](50)); + ammAcctID = amm.ammAccount(); + ammKey = amm.ammID(); + ammIssue = amm.lptIssue(); + return true; + }); + } + void testTypesMatch() { @@ -175,7 +364,7 @@ class Invariants_test : public beast::unit_test::suite auto const sle = ac.view().peek(keylet::account(A1.id())); if (!sle) return false; - auto sleNew = std::make_shared(ltTICKET, sle->key()); + auto const sleNew = std::make_shared(ltTICKET, sle->key()); ac.rawView().rawReplace(sleNew); return true; }); @@ -191,7 +380,7 @@ class Invariants_test : public beast::unit_test::suite // make a dummy escrow ledger entry, then change the type to an // unsupported value so that the valid type invariant check // will fail. - auto sleNew = std::make_shared( + auto const sleNew = std::make_shared( keylet::escrow(A1, (*sle)[sfSequence] + 2)); // We don't use ltNICKNAME directly since it's marked deprecated @@ -231,7 +420,7 @@ class Invariants_test : public beast::unit_test::suite auto const sle = ac.view().peek(keylet::account(A1.id())); if (!sle) return false; - STAmount nonNative(A2["USD"](51)); + STAmount const nonNative(A2["USD"](51)); sle->setFieldAmount(sfBalance, nonNative); ac.view().update(sle); return true; @@ -420,7 +609,7 @@ class Invariants_test : public beast::unit_test::suite [](Account const&, Account const&, ApplyContext& ac) { // Insert a new account root created by a non-payment into // the view. - const Account A3{"A3"}; + Account const A3{"A3"}; Keylet const acctKeylet = keylet::account(A3); auto const sleNew = std::make_shared(acctKeylet); ac.view().insert(sleNew); @@ -432,13 +621,13 @@ class Invariants_test : public beast::unit_test::suite [](Account const&, Account const&, ApplyContext& ac) { // Insert two new account roots into the view. { - const Account A3{"A3"}; + Account const A3{"A3"}; Keylet const acctKeylet = keylet::account(A3); auto const sleA3 = std::make_shared(acctKeylet); ac.view().insert(sleA3); } { - const Account A4{"A4"}; + Account const A4{"A4"}; Keylet const acctKeylet = keylet::account(A4); auto const sleA4 = std::make_shared(acctKeylet); ac.view().insert(sleA4); @@ -450,7 +639,7 @@ class Invariants_test : public beast::unit_test::suite {{"account created with wrong starting sequence number"}}, [](Account const&, Account const&, ApplyContext& ac) { // Insert a new account root with the wrong starting sequence. - const Account A3{"A3"}; + Account const A3{"A3"}; Keylet const acctKeylet = keylet::account(A3); auto const sleNew = std::make_shared(acctKeylet); sleNew->setFieldU32(sfSequence, ac.view().seq() + 1); @@ -467,6 +656,7 @@ class Invariants_test : public beast::unit_test::suite { testXRPNotCreated(); testAccountRootsNotRemoved(); + testAccountRootsDeletedClean(); testTypesMatch(); testNoXRPTrustLine(); testXRPBalanceCheck(); diff --git a/src/xrpld/app/misc/FeeVoteImpl.cpp b/src/xrpld/app/misc/FeeVoteImpl.cpp index af57314ef6d..cb4e57b0f73 100644 --- a/src/xrpld/app/misc/FeeVoteImpl.cpp +++ b/src/xrpld/app/misc/FeeVoteImpl.cpp @@ -277,9 +277,9 @@ FeeVoteImpl::doVoting( } // choose our positions - // TODO: Use structured binding once LLVM issue - // https://github.com/llvm/llvm-project/issues/48582 - // is fixed. + // TODO: Use structured binding once LLVM 16 is the minimum supported + // version. See also: https://github.com/llvm/llvm-project/issues/48582 + // https://github.com/llvm/llvm-project/commit/127bf44385424891eb04cff8e52d3f157fc2cb7c auto const baseFee = baseFeeVote.getVotes(); auto const baseReserve = baseReserveVote.getVotes(); auto const incReserve = incReserveVote.getVotes(); diff --git a/src/xrpld/app/tx/detail/InvariantCheck.cpp b/src/xrpld/app/tx/detail/InvariantCheck.cpp index d1d5890bec3..70210b90d75 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.cpp +++ b/src/xrpld/app/tx/detail/InvariantCheck.cpp @@ -358,6 +358,91 @@ AccountRootsNotDeleted::finalize( //------------------------------------------------------------------------------ +void +AccountRootsDeletedClean::visitEntry( + bool isDelete, + std::shared_ptr const& before, + std::shared_ptr const&) +{ + if (isDelete && before && before->getType() == ltACCOUNT_ROOT) + accountsDeleted_.emplace_back(before); +} + +bool +AccountRootsDeletedClean::finalize( + STTx const& tx, + TER const result, + XRPAmount const, + ReadView const& view, + beast::Journal const& j) +{ + // Always check for objects in the ledger, but to prevent differing + // transaction processing results, however unlikely, only fail if the + // feature is enabled. Enabled, or not, though, a fatal-level message will + // be logged + bool const enforce = view.rules().enabled(featureInvariantsV1_1); + + auto const objectExists = [&view, enforce, &j](auto const& keylet) { + if (auto const sle = view.read(keylet)) + { + // Finding the object is bad + auto const typeName = [&sle]() { + auto item = + LedgerFormats::getInstance().findByType(sle->getType()); + + if (item != nullptr) + return item->getName(); + return std::to_string(sle->getType()); + }(); + + JLOG(j.fatal()) + << "Invariant failed: account deletion left behind a " + << typeName << " object"; + (void)enforce; + assert(enforce); + return true; + } + return false; + }; + + for (auto const& accountSLE : accountsDeleted_) + { + auto const accountID = accountSLE->getAccountID(sfAccount); + // Simple types + for (auto const& [keyletfunc, _, __] : directAccountKeylets) + { + if (objectExists(std::invoke(keyletfunc, accountID)) && enforce) + return false; + } + + { + // NFT pages. ntfpage_min and nftpage_max were already explicitly + // checked above as entries in directAccountKeylets. This uses + // view.succ() to check for any NFT pages in between the two + // endpoints. + Keylet const first = keylet::nftpage_min(accountID); + Keylet const last = keylet::nftpage_max(accountID); + + std::optional key = view.succ(first.key, last.key.next()); + + // current page + if (key && objectExists(Keylet{ltNFTOKEN_PAGE, *key}) && enforce) + return false; + } + + // Keys directly stored in the AccountRoot object + if (auto const ammKey = accountSLE->at(~sfAMMID)) + { + if (objectExists(keylet::amm(*ammKey)) && enforce) + return false; + } + } + + return true; +} + +//------------------------------------------------------------------------------ + void LedgerEntryTypesMatch::visitEntry( bool, diff --git a/src/xrpld/app/tx/detail/InvariantCheck.h b/src/xrpld/app/tx/detail/InvariantCheck.h index ef89569cb7c..6a83f5c9b7b 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.h +++ b/src/xrpld/app/tx/detail/InvariantCheck.h @@ -164,6 +164,36 @@ class AccountRootsNotDeleted beast::Journal const&); }; +/** + * @brief Invariant: a deleted account must not have any objects left + * + * We iterate all deleted account roots, and ensure that there are no + * objects left that are directly accessible with that account's ID. + * + * There should only be one deleted account, but that's checked by + * AccountRootsNotDeleted. This invariant will handle multiple deleted account + * roots without a problem. + */ +class AccountRootsDeletedClean +{ + std::vector> accountsDeleted_; + +public: + void + visitEntry( + bool, + std::shared_ptr const&, + std::shared_ptr const&); + + bool + finalize( + STTx const&, + TER const, + XRPAmount const, + ReadView const&, + beast::Journal const&); +}; + /** * @brief Invariant: An account XRP balance must be in XRP and take a value * between 0 and INITIAL_XRP drops, inclusive. @@ -423,6 +453,7 @@ class ValidClawback using InvariantChecks = std::tuple< TransactionFeeCheck, AccountRootsNotDeleted, + AccountRootsDeletedClean, LedgerEntryTypesMatch, XRPBalanceChecks, XRPNotCreated, diff --git a/src/xrpld/app/tx/detail/NFTokenUtils.cpp b/src/xrpld/app/tx/detail/NFTokenUtils.cpp index b2ed29714df..342b3805a0e 100644 --- a/src/xrpld/app/tx/detail/NFTokenUtils.cpp +++ b/src/xrpld/app/tx/detail/NFTokenUtils.cpp @@ -191,6 +191,7 @@ getPageForToken( : carr[0].getFieldH256(sfNFTokenID); auto np = std::make_shared(keylet::nftpage(base, tokenIDForNewPage)); + assert(np->key() > base.key); np->setFieldArray(sfNFTokens, narr); np->setFieldH256(sfNextPageMin, cp->key()); From 0f32109993eb819f4f17ca2d4fcb4de2cf23660b Mon Sep 17 00:00:00 2001 From: yinyiqian1 Date: Fri, 5 Jul 2024 14:10:54 -0400 Subject: [PATCH 25/82] fix CTID in tx command returns invalidParams on lowercase hex (#5049) * fix CTID in tx command returns invalidParams on lowercase hex * test mixed case and change auto to explicit type * add header cctype because std::tolower is called * remove unused local variable * change test case comment from 'lowercase' to 'mixed case' --------- Co-authored-by: Zack Brunson --- src/test/rpc/Transaction_test.cpp | 42 +++++++++++++++++++++++++++++++ src/xrpld/rpc/CTID.h | 2 +- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/test/rpc/Transaction_test.cpp b/src/test/rpc/Transaction_test.cpp index 72a7681ce97..2bd20eb3707 100644 --- a/src/test/rpc/Transaction_test.cpp +++ b/src/test/rpc/Transaction_test.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -671,6 +672,47 @@ class Transaction_test : public beast::unit_test::suite BEAST_EXPECT(jrr[jss::hash]); } + // test querying with mixed case ctid + { + Env env{*this, makeNetworkConfig(11111)}; + std::uint32_t const netID = env.app().config().NETWORK_ID; + + Account const alice = Account("alice"); + Account const bob = Account("bob"); + + std::uint32_t const startLegSeq = env.current()->info().seq; + env.fund(XRP(10000), alice, bob); + env(pay(alice, bob, XRP(10))); + env.close(); + + std::string const ctid = *RPC::encodeCTID(startLegSeq, 0, netID); + auto isUpper = [](char c) { return std::isupper(c) != 0; }; + + // Verify that there are at least two upper case letters in ctid and + // test a mixed case + if (BEAST_EXPECT( + std::count_if(ctid.begin(), ctid.end(), isUpper) > 1)) + { + // Change the first upper case letter to lower case. + std::string mixedCase = ctid; + { + auto const iter = std::find_if( + mixedCase.begin(), mixedCase.end(), isUpper); + *iter = std::tolower(*iter); + } + BEAST_EXPECT(ctid != mixedCase); + + Json::Value jsonTx; + jsonTx[jss::binary] = false; + jsonTx[jss::ctid] = mixedCase; + jsonTx[jss::id] = 1; + Json::Value const jrr = + env.rpc("json", "tx", to_string(jsonTx))[jss::result]; + BEAST_EXPECT(jrr[jss::ctid] == ctid); + BEAST_EXPECT(jrr[jss::hash]); + } + } + // test that if the network is 65535 the ctid is not in the response { Env env{*this, makeNetworkConfig(65535)}; diff --git a/src/xrpld/rpc/CTID.h b/src/xrpld/rpc/CTID.h index 8f6c64bc028..8cac8d63171 100644 --- a/src/xrpld/rpc/CTID.h +++ b/src/xrpld/rpc/CTID.h @@ -63,7 +63,7 @@ decodeCTID(const T ctid) noexcept if (ctidString.length() != 16) return {}; - if (!boost::regex_match(ctidString, boost::regex("^[0-9A-F]+$"))) + if (!boost::regex_match(ctidString, boost::regex("^[0-9A-Fa-f]+$"))) return {}; ctidValue = std::stoull(ctidString, nullptr, 16); From e8602b81faada84ba85d63520c529ffe756fc90f Mon Sep 17 00:00:00 2001 From: dashangcun <907225865@qq.com> Date: Wed, 10 Jul 2024 06:05:14 +0900 Subject: [PATCH 26/82] chore: remove repeat words (#5053) Signed-off-by: dashangcun Co-authored-by: dashangcun Co-authored-by: Zack Brunson --- external/secp256k1/src/secp256k1.c | 2 +- src/test/csf/CollectorRef.h | 2 +- src/test/csf/Digraph.h | 2 +- src/xrpld/shamap/detail/TaggedPointer.h | 2 +- src/xrpld/shamap/detail/TaggedPointer.ipp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/external/secp256k1/src/secp256k1.c b/external/secp256k1/src/secp256k1.c index bdbd97cc408..a95992c5dd2 100644 --- a/external/secp256k1/src/secp256k1.c +++ b/external/secp256k1/src/secp256k1.c @@ -526,7 +526,7 @@ static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_sc break; } is_nonce_valid = secp256k1_scalar_set_b32_seckey(&non, nonce32); - /* The nonce is still secret here, but it being invalid is is less likely than 1:2^255. */ + /* The nonce is still secret here, but it being invalid is less likely than 1:2^255. */ secp256k1_declassify(ctx, &is_nonce_valid, sizeof(is_nonce_valid)); if (is_nonce_valid) { ret = secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, r, s, &sec, &msg, &non, recid); diff --git a/src/test/csf/CollectorRef.h b/src/test/csf/CollectorRef.h index 0f8d90c8ec9..72d1e9545d8 100644 --- a/src/test/csf/CollectorRef.h +++ b/src/test/csf/CollectorRef.h @@ -40,7 +40,7 @@ namespace csf { level when adding to the simulation. The example code below demonstrates the reason for storing the collector - as a reference. The collector's lifetime will generally be be longer than + as a reference. The collector's lifetime will generally be longer than the simulation; perhaps several simulations are run for a single collector instance. The collector potentially stores lots of data as well, so the simulation needs to point to the single instance, rather than requiring diff --git a/src/test/csf/Digraph.h b/src/test/csf/Digraph.h index 2c6b356bf02..3f079eac17c 100644 --- a/src/test/csf/Digraph.h +++ b/src/test/csf/Digraph.h @@ -220,7 +220,7 @@ class Digraph @param fileName The output file (creates) @param vertexName A invokable T vertexName(Vertex const &) that returns the name target use for the vertex in the file - T must be be ostream-able + T must be ostream-able */ template void diff --git a/src/xrpld/shamap/detail/TaggedPointer.h b/src/xrpld/shamap/detail/TaggedPointer.h index 58271f59c01..48534076548 100644 --- a/src/xrpld/shamap/detail/TaggedPointer.h +++ b/src/xrpld/shamap/detail/TaggedPointer.h @@ -37,7 +37,7 @@ namespace ripple { low bits. When dereferencing the pointer, these low "tag" bits are set to zero. When accessing the tag bits, the high "pointer" bits are set to zero. - The "pointer" part points to to the equivalent to an array of + The "pointer" part points to the equivalent to an array of `SHAMapHash` followed immediately by an array of `shared_ptr`. The sizes of these arrays are determined by the tag. The tag is an index into an array (`boundaries`, diff --git a/src/xrpld/shamap/detail/TaggedPointer.ipp b/src/xrpld/shamap/detail/TaggedPointer.ipp index 6770b53021e..309913c79c0 100644 --- a/src/xrpld/shamap/detail/TaggedPointer.ipp +++ b/src/xrpld/shamap/detail/TaggedPointer.ipp @@ -258,7 +258,7 @@ TaggedPointer::getChildIndex(std::uint16_t isBranch, int i) const // of a child in the array is the number of non-empty children // before it. Since `isBranch_` is a bitset of the stored // children, we simply need to mask out (and set to zero) all - // the bits in `isBranch_` equal to to higher than `i` and count + // the bits in `isBranch_` equal to higher than `i` and count // the bits. // mask sets all the bits >=i to zero and all the bits Date: Thu, 11 Jul 2024 17:04:30 -0500 Subject: [PATCH 27/82] Add xrpld build option and Conan package test (#5052) * Make xrpld target optional * Add job to test Conan recipe * [fold] address review comments * [fold] Enable tests in workflows * [fold] Rename with_xrpld option * [fold] Fix grep expression --- .github/actions/build/action.yml | 2 + .github/actions/dependencies/action.yml | 2 + .github/workflows/nix.yml | 50 +++++++++++++ cmake/RippledCore.cmake | 96 +++++++++++++------------ cmake/RippledInstall.cmake | 38 +++++----- cmake/RippledSettings.cmake | 2 + conanfile.py | 5 +- examples/example/CMakeLists.txt | 16 +++++ examples/example/conanfile.py | 59 +++++++++++++++ examples/example/src/example.cpp | 8 +++ 10 files changed, 211 insertions(+), 67 deletions(-) create mode 100644 examples/example/CMakeLists.txt create mode 100644 examples/example/conanfile.py create mode 100644 examples/example/src/example.cpp diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 79bbe9af075..6714369155f 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -20,6 +20,8 @@ runs: ${{ inputs.generator && format('-G "{0}"', inputs.generator) || '' }} \ -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \ -DCMAKE_BUILD_TYPE=${{ inputs.configuration }} \ + -Dtests=TRUE \ + -Dxrpld=TRUE \ ${{ inputs.cmake-args }} \ .. - name: build diff --git a/.github/actions/dependencies/action.yml b/.github/actions/dependencies/action.yml index d9687ff121e..50e2999018a 100644 --- a/.github/actions/dependencies/action.yml +++ b/.github/actions/dependencies/action.yml @@ -50,6 +50,8 @@ runs: conan install \ --output-folder . \ --build missing \ + --options tests=True \ + --options xrpld=True \ --settings build_type=${{ inputs.configuration }} \ .. - name: upload dependencies to remote diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 77cd50d9d68..6b8261c5d69 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -232,3 +232,53 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} attempt_limit: 5 attempt_delay: 210000 # in milliseconds + + conan: + needs: dependencies + runs-on: [self-hosted, heavy] + container: rippleci/rippled-build-ubuntu:aaf5e3e + env: + build_dir: .build + configuration: Release + steps: + - name: download cache + uses: actions/download-artifact@v3 + with: + name: linux-gcc-${{ env.configuration }} + - name: extract cache + run: | + mkdir -p ~/.conan + tar -xzf conan.tar -C ~/.conan + - name: check environment + run: | + env | sort + echo ${PATH} | tr ':' '\n' + conan --version + cmake --version + - name: checkout + uses: actions/checkout@v4 + - name: dependencies + uses: ./.github/actions/dependencies + env: + CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod + with: + configuration: ${{ env.configuration }} + - name: export + run: | + version=$(conan inspect --raw version .) + reference="xrpl/${version}@local/test" + conan remove -f ${reference} || true + conan export . local/test + echo "reference=${reference}" >> "${GITHUB_ENV}" + - name: build + run: | + cd examples/example + mkdir ${build_dir} + cd ${build_dir} + conan install .. --output-folder . \ + --require-override ${reference} --build missing + cmake .. \ + -DCMAKE_TOOLCHAIN_FILE:FILEPATH=./build/${configuration}/generators/conan_toolchain.cmake \ + -DCMAKE_BUILD_TYPE=${configuration} + cmake --build . + ./example | grep '^[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+' diff --git a/cmake/RippledCore.cmake b/cmake/RippledCore.cmake index cc483034714..6a0060f7b32 100644 --- a/cmake/RippledCore.cmake +++ b/cmake/RippledCore.cmake @@ -91,57 +91,59 @@ target_link_libraries(xrpl.libxrpl xxHash::xxhash ) -add_executable(rippled) -if(unity) - set_target_properties(rippled PROPERTIES UNITY_BUILD ON) -endif() -if(tests) - target_compile_definitions(rippled PUBLIC ENABLE_TESTS) -endif() -target_include_directories(rippled - PRIVATE - $ -) - -file(GLOB_RECURSE sources CONFIGURE_DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/src/xrpld/*.cpp" -) -target_sources(rippled PRIVATE ${sources}) +if(xrpld) + add_executable(rippled) + if(unity) + set_target_properties(rippled PROPERTIES UNITY_BUILD ON) + endif() + if(tests) + target_compile_definitions(rippled PUBLIC ENABLE_TESTS) + endif() + target_include_directories(rippled + PRIVATE + $ + ) -if(tests) file(GLOB_RECURSE sources CONFIGURE_DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/src/test/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/xrpld/*.cpp" ) target_sources(rippled PRIVATE ${sources}) -endif() -target_link_libraries(rippled - Ripple::boost - Ripple::opts - Ripple::libs - xrpl.libxrpl -) -exclude_if_included(rippled) -# define a macro for tests that might need to -# be exluded or run differently in CI environment -if(is_ci) - target_compile_definitions(rippled PRIVATE RIPPLED_RUNNING_IN_CI) -endif () - -if(reporting) - set(suffix -reporting) - set_target_properties(rippled PROPERTIES OUTPUT_NAME rippled-reporting) - get_target_property(BIN_NAME rippled OUTPUT_NAME) - message(STATUS "Reporting mode build: rippled renamed ${BIN_NAME}") - target_compile_definitions(rippled PRIVATE RIPPLED_REPORTING) -endif() + if(tests) + file(GLOB_RECURSE sources CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/src/test/*.cpp" + ) + target_sources(rippled PRIVATE ${sources}) + endif() -# any files that don't play well with unity should be added here -if(tests) - set_source_files_properties( - # these two seem to produce conflicts in beast teardown template methods - src/test/rpc/ValidatorRPC_test.cpp - src/test/rpc/ShardArchiveHandler_test.cpp - src/test/ledger/Invariants_test.cpp - PROPERTIES SKIP_UNITY_BUILD_INCLUSION TRUE) + target_link_libraries(rippled + Ripple::boost + Ripple::opts + Ripple::libs + xrpl.libxrpl + ) + exclude_if_included(rippled) + # define a macro for tests that might need to + # be exluded or run differently in CI environment + if(is_ci) + target_compile_definitions(rippled PRIVATE RIPPLED_RUNNING_IN_CI) + endif () + + if(reporting) + set(suffix -reporting) + set_target_properties(rippled PROPERTIES OUTPUT_NAME rippled-reporting) + get_target_property(BIN_NAME rippled OUTPUT_NAME) + message(STATUS "Reporting mode build: rippled renamed ${BIN_NAME}") + target_compile_definitions(rippled PRIVATE RIPPLED_REPORTING) + endif() + + # any files that don't play well with unity should be added here + if(tests) + set_source_files_properties( + # these two seem to produce conflicts in beast teardown template methods + src/test/rpc/ValidatorRPC_test.cpp + src/test/rpc/ShardArchiveHandler_test.cpp + src/test/ledger/Invariants_test.cpp + PROPERTIES SKIP_UNITY_BUILD_INCLUSION TRUE) + endif() endif() diff --git a/cmake/RippledInstall.cmake b/cmake/RippledInstall.cmake index d92cecc24eb..3199c9a19b8 100644 --- a/cmake/RippledInstall.cmake +++ b/cmake/RippledInstall.cmake @@ -21,6 +21,13 @@ install( DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" ) +if(NOT WIN32) + install( + CODE "file(CREATE_LINK xrpl \ + \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/ripple SYMBOLIC)" + ) +endif() + install (EXPORT RippleExports FILE RippleTargets.cmake NAMESPACE Ripple:: @@ -31,14 +38,9 @@ write_basic_package_version_file ( VERSION ${rippled_version} COMPATIBILITY SameMajorVersion) -if (is_root_project) +if (is_root_project AND TARGET rippled) install (TARGETS rippled RUNTIME DESTINATION bin) set_target_properties(rippled PROPERTIES INSTALL_RPATH_USE_LINK_PATH ON) - install ( - FILES - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/RippleConfig.cmake - ${CMAKE_CURRENT_BINARY_DIR}/RippleConfigVersion.cmake - DESTINATION lib/cmake/ripple) # sample configs should not overwrite existing files # install if-not-exists workaround as suggested by # https://cmake.org/Bug/view.php?id=12646 @@ -53,18 +55,16 @@ if (is_root_project) copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/rippled-example.cfg\" etc rippled.cfg) copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/validators-example.txt\" etc validators.txt) ") + if(NOT WIN32) + install( + CODE "file(CREATE_LINK rippled${suffix} \ + \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/xrpld${suffix} SYMBOLIC)" + ) + endif() endif () -if(NOT WIN32) - install( - CODE "file(CREATE_LINK xrpl \ - \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/ripple SYMBOLIC)" - ) -endif() - -if(NOT WIN32) - install( - CODE "file(CREATE_LINK rippled${suffix} \ - \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/xrpld${suffix} SYMBOLIC)" - ) -endif() +install ( + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/RippleConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/RippleConfigVersion.cmake + DESTINATION lib/cmake/ripple) diff --git a/cmake/RippledSettings.cmake b/cmake/RippledSettings.cmake index fae09cc5d3f..a431bb61389 100644 --- a/cmake/RippledSettings.cmake +++ b/cmake/RippledSettings.cmake @@ -8,6 +8,8 @@ ProcessorCount(PROCESSOR_COUNT) option(assert "Enables asserts, even in release builds" OFF) +option(xrpld "Build xrpld" ON) + option(reporting "Build rippled with reporting mode enabled" OFF) option(tests "Build tests" ON) diff --git a/conanfile.py b/conanfile.py index 68b0a7cd405..425fee8b682 100644 --- a/conanfile.py +++ b/conanfile.py @@ -21,6 +21,7 @@ class Xrpl(ConanFile): 'static': [True, False], 'tests': [True, False], 'unity': [True, False], + 'xrpld': [True, False], } requires = [ @@ -47,8 +48,9 @@ class Xrpl(ConanFile): 'rocksdb': True, 'shared': False, 'static': True, - 'tests': True, + 'tests': False, 'unity': False, + 'xrpld': False, 'cassandra-cpp-driver/*:shared': False, 'cassandra-cpp-driver/*:use_atomic': None, @@ -142,6 +144,7 @@ def generate(self): tc.variables['BUILD_SHARED_LIBS'] = self.options.shared tc.variables['static'] = self.options.static tc.variables['unity'] = self.options.unity + tc.variables['xrpld'] = self.options.xrpld tc.generate() def build(self): diff --git a/examples/example/CMakeLists.txt b/examples/example/CMakeLists.txt new file mode 100644 index 00000000000..83aa24880d1 --- /dev/null +++ b/examples/example/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.21) + +set(name example) +set(version 0.1.0) + +project( + ${name} + VERSION ${version} + LANGUAGES CXX +) + +find_package(xrpl REQUIRED) + +add_executable(example) +target_sources(example PRIVATE src/example.cpp) +target_link_libraries(example PRIVATE xrpl::libxrpl) diff --git a/examples/example/conanfile.py b/examples/example/conanfile.py new file mode 100644 index 00000000000..be3750bf9e9 --- /dev/null +++ b/examples/example/conanfile.py @@ -0,0 +1,59 @@ +from conan import ConanFile, conan_version +from conan.tools.cmake import CMake, cmake_layout + +class Example(ConanFile): + + def set_name(self): + if self.name is None: + self.name = 'example' + + def set_version(self): + if self.version is None: + self.version = '0.1.0' + + license = 'ISC' + author = 'John Freeman ' + + settings = 'os', 'compiler', 'build_type', 'arch' + options = {'shared': [True, False], 'fPIC': [True, False]} + default_options = { + 'shared': False, + 'fPIC': True, + 'xrpl:xrpld': False, + } + + requires = ['xrpl/2.2.0-rc1@jfreeman/nodestore'] + generators = ['CMakeDeps', 'CMakeToolchain'] + + exports_sources = [ + 'CMakeLists.txt', + 'cmake/*', + 'external/*', + 'include/*', + 'src/*', + ] + + # For out-of-source build. + # https://docs.conan.io/en/latest/reference/build_helpers/cmake.html#configure + no_copy_source = True + + def layout(self): + cmake_layout(self) + + def config_options(self): + if self.settings.os == 'Windows': + del self.options.fPIC + + def build(self): + cmake = CMake(self) + cmake.configure(variables={'BUILD_TESTING': 'NO'}) + cmake.build() + + def package(self): + cmake = CMake(self) + cmake.install() + + def package_info(self): + path = f'{self.package_folder}/share/{self.name}/cpp_info.py' + with open(path, 'r') as file: + exec(file.read(), {}, {'self': self.cpp_info}) diff --git a/examples/example/src/example.cpp b/examples/example/src/example.cpp new file mode 100644 index 00000000000..7ff07f6ea4d --- /dev/null +++ b/examples/example/src/example.cpp @@ -0,0 +1,8 @@ +#include + +#include + +int main(int argc, char const** argv) { + std::printf("%s\n", ripple::BuildInfo::getVersionString().c_str()); + return 0; +} From ad14d09a2b6de8d8847124476485682433f2e235 Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Tue, 23 Jul 2024 22:49:16 +0200 Subject: [PATCH 28/82] Update BUILD.md after PR #5052 (#5067) * Document the need to specify "xrpld" and "tests" to build and test rippled. --- BUILD.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BUILD.md b/BUILD.md index 0b9ef40e61b..1d82a9f66fa 100644 --- a/BUILD.md +++ b/BUILD.md @@ -242,7 +242,7 @@ It patches their CMake to correctly import its dependencies. Single-config generators: ``` - cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release .. + cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release -Dxrpld=ON -Dtests=ON .. ``` Pass the CMake variable [`CMAKE_BUILD_TYPE`][build_type] @@ -252,7 +252,7 @@ It patches their CMake to correctly import its dependencies. Multi-config generators: ``` - cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake .. + cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -Dxrpld=ON -Dtests=ON .. ``` **Note:** You can pass build options for `rippled` in this step. @@ -343,7 +343,7 @@ Example use with some cmake variables set: ``` cd .build conan install .. --output-folder . --build missing --settings build_type=Debug -cmake -DCMAKE_BUILD_TYPE=Debug -Dcoverage=ON -Dcoverage_test_parallelism=2 -Dcoverage_format=html-details -Dcoverage_extra_args="--json coverage.json" -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake .. +cmake -DCMAKE_BUILD_TYPE=Debug -Dcoverage=ON -Dxrpld=ON -Dtests=ON -Dcoverage_test_parallelism=2 -Dcoverage_format=html-details -Dcoverage_extra_args="--json coverage.json" -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake .. cmake --build . --target coverage ``` From 20707fac4a0a52e47f989b79dd2f351bf344a438 Mon Sep 17 00:00:00 2001 From: Scott Schurr Date: Thu, 25 Jul 2024 11:50:27 -0700 Subject: [PATCH 29/82] chore: Rename two files from Directory* to Dir*: (#5058) The names of the files should reflect the name of the Dir class. Co-authored-by: Zack Brunson Co-authored-by: Ed Hennis --- src/test/app/Escrow_test.cpp | 2 +- src/test/app/PayChan_test.cpp | 2 +- src/test/ledger/Directory_test.cpp | 1 - src/xrpld/app/paths/detail/BookStep.cpp | 1 - src/xrpld/app/tx/detail/NFTokenBurn.cpp | 1 - src/xrpld/app/tx/detail/NFTokenUtils.cpp | 2 +- src/xrpld/ledger/{Directory.h => Dir.h} | 12 ++++++++++++ src/xrpld/ledger/detail/{Directory.cpp => Dir.cpp} | 2 +- 8 files changed, 16 insertions(+), 7 deletions(-) rename src/xrpld/ledger/{Directory.h => Dir.h} (86%) rename src/xrpld/ledger/detail/{Directory.cpp => Dir.cpp} (98%) diff --git a/src/test/app/Escrow_test.cpp b/src/test/app/Escrow_test.cpp index 813f26da736..0f465a14f4d 100644 --- a/src/test/app/Escrow_test.cpp +++ b/src/test/app/Escrow_test.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/test/app/PayChan_test.cpp b/src/test/app/PayChan_test.cpp index a8eae4a25ec..0dffe5e388f 100644 --- a/src/test/app/PayChan_test.cpp +++ b/src/test/app/PayChan_test.cpp @@ -18,7 +18,7 @@ //============================================================================== #include -#include +#include #include #include #include diff --git a/src/test/ledger/Directory_test.cpp b/src/test/ledger/Directory_test.cpp index 1a14feff061..4904b6e6fbf 100644 --- a/src/test/ledger/Directory_test.cpp +++ b/src/test/ledger/Directory_test.cpp @@ -17,7 +17,6 @@ #include #include -#include #include #include #include diff --git a/src/xrpld/app/paths/detail/BookStep.cpp b/src/xrpld/app/paths/detail/BookStep.cpp index 4fa6f140aae..96971a516fc 100644 --- a/src/xrpld/app/paths/detail/BookStep.cpp +++ b/src/xrpld/app/paths/detail/BookStep.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/src/xrpld/app/tx/detail/NFTokenBurn.cpp b/src/xrpld/app/tx/detail/NFTokenBurn.cpp index f43dda71f59..725e35791f9 100644 --- a/src/xrpld/app/tx/detail/NFTokenBurn.cpp +++ b/src/xrpld/app/tx/detail/NFTokenBurn.cpp @@ -19,7 +19,6 @@ #include #include -#include #include #include #include diff --git a/src/xrpld/app/tx/detail/NFTokenUtils.cpp b/src/xrpld/app/tx/detail/NFTokenUtils.cpp index 342b3805a0e..279bf6b9816 100644 --- a/src/xrpld/app/tx/detail/NFTokenUtils.cpp +++ b/src/xrpld/app/tx/detail/NFTokenUtils.cpp @@ -18,7 +18,7 @@ //============================================================================== #include -#include +#include #include #include #include diff --git a/src/xrpld/ledger/Directory.h b/src/xrpld/ledger/Dir.h similarity index 86% rename from src/xrpld/ledger/Directory.h rename to src/xrpld/ledger/Dir.h index cc8b3c13a3a..0e92d7dbca6 100644 --- a/src/xrpld/ledger/Directory.h +++ b/src/xrpld/ledger/Dir.h @@ -25,6 +25,18 @@ namespace ripple { +/** A class that simplifies iterating ledger directory pages + + The Dir class provides a forward iterator for walking through + the uint256 values contained in ledger directories. + + The Dir class also allows accelerated directory walking by + stepping directly from one page to the next using the next_page() + member function. + + As of July 2024, the Dir class is only being used with NFTokenOffer + directories and for unit tests. +*/ class Dir { private: diff --git a/src/xrpld/ledger/detail/Directory.cpp b/src/xrpld/ledger/detail/Dir.cpp similarity index 98% rename from src/xrpld/ledger/detail/Directory.cpp rename to src/xrpld/ledger/detail/Dir.cpp index 9153d013fd8..6004a73095c 100644 --- a/src/xrpld/ledger/detail/Directory.cpp +++ b/src/xrpld/ledger/detail/Dir.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { From 21a0a64648949372841f5edde8eef7771d7b7d9f Mon Sep 17 00:00:00 2001 From: Scott Schurr Date: Thu, 25 Jul 2024 14:12:59 -0700 Subject: [PATCH 30/82] chore: Add comments to SignerEntries.h (#5059) --- src/xrpld/app/tx/detail/SignerEntries.cpp | 2 +- src/xrpld/app/tx/detail/SignerEntries.h | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/xrpld/app/tx/detail/SignerEntries.cpp b/src/xrpld/app/tx/detail/SignerEntries.cpp index f6a42120d11..cab362a8e3b 100644 --- a/src/xrpld/app/tx/detail/SignerEntries.cpp +++ b/src/xrpld/app/tx/detail/SignerEntries.cpp @@ -30,7 +30,7 @@ Expected, NotTEC> SignerEntries::deserialize( STObject const& obj, beast::Journal journal, - std::string const& annotation) + std::string_view annotation) { std::pair, NotTEC> s; diff --git a/src/xrpld/app/tx/detail/SignerEntries.h b/src/xrpld/app/tx/detail/SignerEntries.h index c64e106ae9e..2227aa98109 100644 --- a/src/xrpld/app/tx/detail/SignerEntries.h +++ b/src/xrpld/app/tx/detail/SignerEntries.h @@ -27,18 +27,27 @@ #include // STTx::maxMultiSigners #include // temMALFORMED #include // AccountID + #include +#include namespace ripple { // Forward declarations class STObject; -// Support for SignerEntries that is needed by a few Transactors +// Support for SignerEntries that is needed by a few Transactors. +// +// SignerEntries is represented as a std::vector. +// There is no direct constructor for SignerEntries. +// +// o A std::vector is a SignerEntries. +// o More commonly, SignerEntries are extracted from an STObject by +// calling SignerEntries::deserialize(). class SignerEntries { public: - explicit SignerEntries() = default; + explicit SignerEntries() = delete; struct SignerEntry { @@ -69,11 +78,15 @@ class SignerEntries }; // Deserialize a SignerEntries array from the network or from the ledger. + // + // obj Contains a SignerEntries field that is an STArray. + // journal For reporting error conditions. + // annotation Source of SignerEntries, like "ledger" or "transaction". static Expected, NotTEC> deserialize( STObject const& obj, beast::Journal journal, - std::string const& annotation); + std::string_view annotation); }; } // namespace ripple From d54151e7c4cf47cb1640f45a6019db87b0d0daf7 Mon Sep 17 00:00:00 2001 From: yinyiqian1 Date: Mon, 29 Jul 2024 16:30:02 -0400 Subject: [PATCH 31/82] Disallow filtering account_objects by unsupported types (#5056) * `account_objects` returns an invalid field error if `type` is not supported. This includes objects an account can't own, or which are unsupported by `account_objects` * Includes: * Amendments * Directory Node * Fee Settings * Ledger Hashes * Negative UNL --- src/test/rpc/AccountObjects_test.cpp | 147 ++++++++++++---------- src/xrpld/rpc/detail/RPCHelpers.cpp | 16 +++ src/xrpld/rpc/detail/RPCHelpers.h | 9 ++ src/xrpld/rpc/handlers/AccountObjects.cpp | 3 + 4 files changed, 108 insertions(+), 67 deletions(-) diff --git a/src/test/rpc/AccountObjects_test.cpp b/src/test/rpc/AccountObjects_test.cpp index efa9e10cc34..0757ca40bf0 100644 --- a/src/test/rpc/AccountObjects_test.cpp +++ b/src/test/rpc/AccountObjects_test.cpp @@ -558,11 +558,11 @@ class AccountObjects_test : public beast::unit_test::suite Env env(*this, features); // Make a lambda we can use to get "account_objects" easily. - auto acct_objs = [&env]( - AccountID const& acct, - std::optional const& type, - std::optional limit = std::nullopt, - std::optional marker = std::nullopt) { + auto acctObjs = [&env]( + AccountID const& acct, + std::optional const& type, + std::optional limit = std::nullopt, + std::optional marker = std::nullopt) { Json::Value params; params[jss::account] = to_string(acct); if (type) @@ -576,32 +576,42 @@ class AccountObjects_test : public beast::unit_test::suite }; // Make a lambda that easily identifies the size of account objects. - auto acct_objs_is_size = [](Json::Value const& resp, unsigned size) { + auto acctObjsIsSize = [](Json::Value const& resp, unsigned size) { return resp[jss::result][jss::account_objects].isArray() && (resp[jss::result][jss::account_objects].size() == size); }; + // Make a lambda that checks if the response has error for invalid type + auto acctObjsTypeIsInvalid = [](Json::Value const& resp) { + return resp[jss::result].isMember(jss::error) && + resp[jss::result][jss::error_message] == + "Invalid field \'type\'."; + }; + env.fund(XRP(10000), gw, alice); env.close(); // Since the account is empty now, all account objects should come // back empty. - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::account), 0)); - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::amendments), 0)); - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::check), 0)); - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::deposit_preauth), 0)); - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::directory), 0)); - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::escrow), 0)); - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::fee), 0)); - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::hashes), 0)); - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::nft_page), 0)); - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::offer), 0)); - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::payment_channel), 0)); - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::signer_list), 0)); - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::state), 0)); - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::ticket), 0)); - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::amm), 0)); - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::did), 0)); + BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::account), 0)); + BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::check), 0)); + BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::deposit_preauth), 0)); + BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::escrow), 0)); + BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::nft_page), 0)); + BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::offer), 0)); + BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::payment_channel), 0)); + BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::signer_list), 0)); + BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::state), 0)); + BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::ticket), 0)); + BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::amm), 0)); + BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::did), 0)); + + // we expect invalid field type reported for the following types + BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::amendments))); + BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::directory))); + BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::fee))); + BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::hashes))); + BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::NegativeUNL))); // gw mints an NFT so we can find it. uint256 const nftID{token::getNextID(env, gw, 0u, tfTransferable)}; @@ -609,8 +619,8 @@ class AccountObjects_test : public beast::unit_test::suite env.close(); { // Find the NFToken page and make sure it's the right one. - Json::Value const resp = acct_objs(gw, jss::nft_page); - BEAST_EXPECT(acct_objs_is_size(resp, 1)); + Json::Value const resp = acctObjs(gw, jss::nft_page); + BEAST_EXPECT(acctObjsIsSize(resp, 1)); auto const& nftPage = resp[jss::result][jss::account_objects][0u]; BEAST_EXPECT(nftPage[sfNFTokens.jsonName].size() == 1); @@ -626,8 +636,8 @@ class AccountObjects_test : public beast::unit_test::suite env.close(); { // Find the trustline and make sure it's the right one. - Json::Value const resp = acct_objs(gw, jss::state); - BEAST_EXPECT(acct_objs_is_size(resp, 1)); + Json::Value const resp = acctObjs(gw, jss::state); + BEAST_EXPECT(acctObjsIsSize(resp, 1)); auto const& state = resp[jss::result][jss::account_objects][0u]; BEAST_EXPECT(state[sfBalance.jsonName][jss::value].asInt() == -5); @@ -639,8 +649,8 @@ class AccountObjects_test : public beast::unit_test::suite env.close(); { // Find the check. - Json::Value const resp = acct_objs(gw, jss::check); - BEAST_EXPECT(acct_objs_is_size(resp, 1)); + Json::Value const resp = acctObjs(gw, jss::check); + BEAST_EXPECT(acctObjsIsSize(resp, 1)); auto const& check = resp[jss::result][jss::account_objects][0u]; BEAST_EXPECT(check[sfAccount.jsonName] == gw.human()); @@ -652,8 +662,8 @@ class AccountObjects_test : public beast::unit_test::suite env.close(); { // Find the preauthorization. - Json::Value const resp = acct_objs(gw, jss::deposit_preauth); - BEAST_EXPECT(acct_objs_is_size(resp, 1)); + Json::Value const resp = acctObjs(gw, jss::deposit_preauth); + BEAST_EXPECT(acctObjsIsSize(resp, 1)); auto const& preauth = resp[jss::result][jss::account_objects][0u]; BEAST_EXPECT(preauth[sfAccount.jsonName] == gw.human()); @@ -674,8 +684,8 @@ class AccountObjects_test : public beast::unit_test::suite } { // Find the escrow. - Json::Value const resp = acct_objs(gw, jss::escrow); - BEAST_EXPECT(acct_objs_is_size(resp, 1)); + Json::Value const resp = acctObjs(gw, jss::escrow); + BEAST_EXPECT(acctObjsIsSize(resp, 1)); auto const& escrow = resp[jss::result][jss::account_objects][0u]; BEAST_EXPECT(escrow[sfAccount.jsonName] == gw.human()); @@ -688,7 +698,7 @@ class AccountObjects_test : public beast::unit_test::suite Env scEnv(*this, envconfig(port_increment, 3), features); x.createScBridgeObjects(scEnv); - auto scenv_acct_objs = [&](Account const& acct, char const* type) { + auto scEnvAcctObjs = [&](Account const& acct, char const* type) { Json::Value params; params[jss::account] = acct.human(); params[jss::type] = type; @@ -697,9 +707,9 @@ class AccountObjects_test : public beast::unit_test::suite }; Json::Value const resp = - scenv_acct_objs(Account::master, jss::bridge); + scEnvAcctObjs(Account::master, jss::bridge); - BEAST_EXPECT(acct_objs_is_size(resp, 1)); + BEAST_EXPECT(acctObjsIsSize(resp, 1)); auto const& acct_bridge = resp[jss::result][jss::account_objects][0u]; BEAST_EXPECT( @@ -735,7 +745,7 @@ class AccountObjects_test : public beast::unit_test::suite scEnv(xchain_create_claim_id(x.scBob, x.jvb, x.reward, x.mcBob)); scEnv.close(); - auto scenv_acct_objs = [&](Account const& acct, char const* type) { + auto scEnvAcctObjs = [&](Account const& acct, char const* type) { Json::Value params; params[jss::account] = acct.human(); params[jss::type] = type; @@ -746,8 +756,8 @@ class AccountObjects_test : public beast::unit_test::suite { // Find the xchain sequence number for Andrea. Json::Value const resp = - scenv_acct_objs(x.scAlice, jss::xchain_owned_claim_id); - BEAST_EXPECT(acct_objs_is_size(resp, 1)); + scEnvAcctObjs(x.scAlice, jss::xchain_owned_claim_id); + BEAST_EXPECT(acctObjsIsSize(resp, 1)); auto const& xchain_seq = resp[jss::result][jss::account_objects][0u]; @@ -759,8 +769,8 @@ class AccountObjects_test : public beast::unit_test::suite { // and the one for Bob Json::Value const resp = - scenv_acct_objs(x.scBob, jss::xchain_owned_claim_id); - BEAST_EXPECT(acct_objs_is_size(resp, 1)); + scEnvAcctObjs(x.scBob, jss::xchain_owned_claim_id); + BEAST_EXPECT(acctObjsIsSize(resp, 1)); auto const& xchain_seq = resp[jss::result][jss::account_objects][0u]; @@ -792,7 +802,7 @@ class AccountObjects_test : public beast::unit_test::suite x.signers[0])); scEnv.close(); - auto scenv_acct_objs = [&](Account const& acct, char const* type) { + auto scEnvAcctObjs = [&](Account const& acct, char const* type) { Json::Value params; params[jss::account] = acct.human(); params[jss::type] = type; @@ -802,9 +812,9 @@ class AccountObjects_test : public beast::unit_test::suite { // Find the xchain_create_account_claim_id - Json::Value const resp = scenv_acct_objs( + Json::Value const resp = scEnvAcctObjs( Account::master, jss::xchain_owned_create_account_claim_id); - BEAST_EXPECT(acct_objs_is_size(resp, 1)); + BEAST_EXPECT(acctObjsIsSize(resp, 1)); auto const& xchain_create_account_claim_id = resp[jss::result][jss::account_objects][0u]; @@ -823,8 +833,8 @@ class AccountObjects_test : public beast::unit_test::suite env.close(); { // Find the offer. - Json::Value const resp = acct_objs(gw, jss::offer); - BEAST_EXPECT(acct_objs_is_size(resp, 1)); + Json::Value const resp = acctObjs(gw, jss::offer); + BEAST_EXPECT(acctObjsIsSize(resp, 1)); auto const& offer = resp[jss::result][jss::account_objects][0u]; BEAST_EXPECT(offer[sfAccount.jsonName] == gw.human()); @@ -848,8 +858,8 @@ class AccountObjects_test : public beast::unit_test::suite } { // Find the payment channel. - Json::Value const resp = acct_objs(gw, jss::payment_channel); - BEAST_EXPECT(acct_objs_is_size(resp, 1)); + Json::Value const resp = acctObjs(gw, jss::payment_channel); + BEAST_EXPECT(acctObjsIsSize(resp, 1)); auto const& payChan = resp[jss::result][jss::account_objects][0u]; BEAST_EXPECT(payChan[sfAccount.jsonName] == gw.human()); @@ -870,8 +880,8 @@ class AccountObjects_test : public beast::unit_test::suite } { // Find the DID. - Json::Value const resp = acct_objs(gw, jss::did); - BEAST_EXPECT(acct_objs_is_size(resp, 1)); + Json::Value const resp = acctObjs(gw, jss::did); + BEAST_EXPECT(acctObjsIsSize(resp, 1)); auto const& did = resp[jss::result][jss::account_objects][0u]; BEAST_EXPECT(did[sfAccount.jsonName] == gw.human()); @@ -882,8 +892,8 @@ class AccountObjects_test : public beast::unit_test::suite env.close(); { // Find the signer list. - Json::Value const resp = acct_objs(gw, jss::signer_list); - BEAST_EXPECT(acct_objs_is_size(resp, 1)); + Json::Value const resp = acctObjs(gw, jss::signer_list); + BEAST_EXPECT(acctObjsIsSize(resp, 1)); auto const& signerList = resp[jss::result][jss::account_objects][0u]; @@ -898,8 +908,8 @@ class AccountObjects_test : public beast::unit_test::suite env.close(); { // Find the ticket. - Json::Value const resp = acct_objs(gw, jss::ticket); - BEAST_EXPECT(acct_objs_is_size(resp, 1)); + Json::Value const resp = acctObjs(gw, jss::ticket); + BEAST_EXPECT(acctObjsIsSize(resp, 1)); auto const& ticket = resp[jss::result][jss::account_objects][0u]; BEAST_EXPECT(ticket[sfAccount.jsonName] == gw.human()); @@ -927,7 +937,7 @@ class AccountObjects_test : public beast::unit_test::suite std::uint32_t const expectedAccountObjects{ static_cast(std::size(expectedLedgerTypes))}; - if (BEAST_EXPECT(acct_objs_is_size(resp, expectedAccountObjects))) + if (BEAST_EXPECT(acctObjsIsSize(resp, expectedAccountObjects))) { auto const& aobjs = resp[jss::result][jss::account_objects]; std::vector gotLedgerTypes; @@ -950,7 +960,7 @@ class AccountObjects_test : public beast::unit_test::suite params[jss::type] = jss::escrow; auto resp = env.rpc("json", "account_objects", to_string(params)); - if (BEAST_EXPECT(acct_objs_is_size(resp, 1u))) + if (BEAST_EXPECT(acctObjsIsSize(resp, 1u))) { auto const& aobjs = resp[jss::result][jss::account_objects]; BEAST_EXPECT(aobjs[0u]["LedgerEntryType"] == jss::Escrow); @@ -971,7 +981,7 @@ class AccountObjects_test : public beast::unit_test::suite auto expectObjects = [&](Json::Value const& resp, std::vector const& types) -> bool { - if (!acct_objs_is_size(resp, types.size())) + if (!acctObjsIsSize(resp, types.size())) return false; std::vector typesOut; getTypes(resp, typesOut); @@ -985,13 +995,13 @@ class AccountObjects_test : public beast::unit_test::suite BEAST_EXPECT(lines[jss::lines].size() == 3); // request AMM only, doesn't depend on the limit BEAST_EXPECT( - acct_objs_is_size(acct_objs(amm.ammAccount(), jss::amm), 1)); + acctObjsIsSize(acctObjs(amm.ammAccount(), jss::amm), 1)); // request first two objects - auto resp = acct_objs(amm.ammAccount(), std::nullopt, 2); + auto resp = acctObjs(amm.ammAccount(), std::nullopt, 2); std::vector typesOut; getTypes(resp, typesOut); // request next two objects - resp = acct_objs( + resp = acctObjs( amm.ammAccount(), std::nullopt, 10, @@ -1005,7 +1015,7 @@ class AccountObjects_test : public beast::unit_test::suite jss::RippleState.c_str(), jss::RippleState.c_str()})); // filter by state: there are three trustlines - resp = acct_objs(amm.ammAccount(), jss::state, 10); + resp = acctObjs(amm.ammAccount(), jss::state, 10); BEAST_EXPECT(expectObjects( resp, {jss::RippleState.c_str(), @@ -1013,11 +1023,18 @@ class AccountObjects_test : public beast::unit_test::suite jss::RippleState.c_str()})); // AMM account doesn't own offers BEAST_EXPECT( - acct_objs_is_size(acct_objs(amm.ammAccount(), jss::offer), 0)); + acctObjsIsSize(acctObjs(amm.ammAccount(), jss::offer), 0)); // gw account doesn't own AMM object - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::amm), 0)); + BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::amm), 0)); } + // we still expect invalid field type reported for the following types + BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::amendments))); + BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::directory))); + BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::fee))); + BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::hashes))); + BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::NegativeUNL))); + // Run up the number of directory entries so gw has two // directory nodes. for (int d = 1'000'032; d >= 1'000'000; --d) @@ -1027,11 +1044,7 @@ class AccountObjects_test : public beast::unit_test::suite } // Verify that the non-returning types still don't return anything. - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::account), 0)); - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::amendments), 0)); - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::directory), 0)); - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::fee), 0)); - BEAST_EXPECT(acct_objs_is_size(acct_objs(gw, jss::hashes), 0)); + BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::account), 0)); } void diff --git a/src/xrpld/rpc/detail/RPCHelpers.cpp b/src/xrpld/rpc/detail/RPCHelpers.cpp index 42bd4faded5..71513ddcd5c 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.cpp +++ b/src/xrpld/rpc/detail/RPCHelpers.cpp @@ -986,6 +986,22 @@ chooseLedgerEntryType(Json::Value const& params) return result; } +bool +isAccountObjectsValidType(LedgerEntryType const& type) +{ + switch (type) + { + case LedgerEntryType::ltAMENDMENTS: + case LedgerEntryType::ltDIR_NODE: + case LedgerEntryType::ltFEE_SETTINGS: + case LedgerEntryType::ltLEDGER_HASHES: + case LedgerEntryType::ltNEGATIVE_UNL: + return false; + default: + return true; + } +} + beast::SemanticVersion const firstVersion("1.0.0"); beast::SemanticVersion const goodVersion("1.0.0"); beast::SemanticVersion const lastVersion("1.0.0"); diff --git a/src/xrpld/rpc/detail/RPCHelpers.h b/src/xrpld/rpc/detail/RPCHelpers.h index 30b48807fcd..54c426b17c3 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.h +++ b/src/xrpld/rpc/detail/RPCHelpers.h @@ -232,6 +232,15 @@ setVersion(Object& parent, unsigned int apiVersion, bool betaEnabled) std::pair chooseLedgerEntryType(Json::Value const& params); +/** + * Check if the type is a valid filtering type for account_objects method + * + * Since Amendments, DirectoryNode, FeeSettings, LedgerHashes can not be + * owned by an account, this function will return false in these situations. + */ +bool +isAccountObjectsValidType(LedgerEntryType const& type); + /** * Retrieve the api version number from the json value * diff --git a/src/xrpld/rpc/handlers/AccountObjects.cpp b/src/xrpld/rpc/handlers/AccountObjects.cpp index 32fe15ec264..d2eb2eacde6 100644 --- a/src/xrpld/rpc/handlers/AccountObjects.cpp +++ b/src/xrpld/rpc/handlers/AccountObjects.cpp @@ -236,6 +236,9 @@ doAccountObjects(RPC::JsonContext& context) { auto [rpcStatus, type] = RPC::chooseLedgerEntryType(params); + if (!RPC::isAccountObjectsValidType(type)) + return RPC::invalid_field_error(jss::type); + if (rpcStatus) { result.clear(); From 8fc805d2e226195572801ee4dbeda8b16cffc029 Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Mon, 29 Jul 2024 18:14:41 -0400 Subject: [PATCH 32/82] fix: Fix NuDB build error via Conan patch (#5061) * Includes updated instructions in BUILD.md. --- BUILD.md | 17 +++++ external/nudb/conandata.yml | 10 +++ external/nudb/conanfile.py | 72 +++++++++++++++++++ ...-0001-add-include-stdexcept-for-msvc.patch | 24 +++++++ 4 files changed, 123 insertions(+) create mode 100644 external/nudb/conandata.yml create mode 100644 external/nudb/conanfile.py create mode 100644 external/nudb/patches/2.0.8-0001-add-include-stdexcept-for-msvc.patch diff --git a/BUILD.md b/BUILD.md index 1d82a9f66fa..b4201ef0437 100644 --- a/BUILD.md +++ b/BUILD.md @@ -98,6 +98,12 @@ Update the compiler settings: conan profile update settings.compiler.cppstd=20 default ``` +Configure Conan (1.x only) to use recipe revisions: + + ``` + conan config set general.revisions_enabled=1 + ``` + **Linux** developers will commonly have a default Conan [profile][] that compiles with GCC and links with libstdc++. If you are linking with libstdc++ (see profile setting `compiler.libcxx`), @@ -187,6 +193,17 @@ It patches their CMake to correctly import its dependencies. conan export --version 4.0.3 external/soci ``` +Export our [Conan recipe for NuDB](./external/nudb). +It fixes some source files to add missing `#include`s. + + + ``` + # Conan 1.x + conan export external/nudb nudb/2.0.8@ + # Conan 2.x + conan export --version 2.0.8 external/nudb + ``` + ### Build and Test 1. Create a build directory and move into it. diff --git a/external/nudb/conandata.yml b/external/nudb/conandata.yml new file mode 100644 index 00000000000..721129f88e7 --- /dev/null +++ b/external/nudb/conandata.yml @@ -0,0 +1,10 @@ +sources: + "2.0.8": + url: "https://github.com/CPPAlliance/NuDB/archive/2.0.8.tar.gz" + sha256: "9b71903d8ba111cd893ab064b9a8b6ac4124ed8bd6b4f67250205bc43c7f13a8" +patches: + "2.0.8": + - patch_file: "patches/2.0.8-0001-add-include-stdexcept-for-msvc.patch" + patch_description: "Fix build for MSVC by including stdexcept" + patch_type: "portability" + patch_source: "https://github.com/cppalliance/NuDB/pull/100/files" diff --git a/external/nudb/conanfile.py b/external/nudb/conanfile.py new file mode 100644 index 00000000000..a046e2ba898 --- /dev/null +++ b/external/nudb/conanfile.py @@ -0,0 +1,72 @@ +import os + +from conan import ConanFile +from conan.tools.build import check_min_cppstd +from conan.tools.files import apply_conandata_patches, copy, export_conandata_patches, get +from conan.tools.layout import basic_layout + +required_conan_version = ">=1.52.0" + + +class NudbConan(ConanFile): + name = "nudb" + description = "A fast key/value insert-only database for SSD drives in C++11" + license = "BSL-1.0" + url = "https://github.com/conan-io/conan-center-index" + homepage = "https://github.com/CPPAlliance/NuDB" + topics = ("header-only", "KVS", "insert-only") + + package_type = "header-library" + settings = "os", "arch", "compiler", "build_type" + no_copy_source = True + + @property + def _min_cppstd(self): + return 11 + + def export_sources(self): + export_conandata_patches(self) + + def layout(self): + basic_layout(self, src_folder="src") + + def requirements(self): + self.requires("boost/1.83.0") + + def package_id(self): + self.info.clear() + + def validate(self): + if self.settings.compiler.cppstd: + check_min_cppstd(self, self._min_cppstd) + + def source(self): + get(self, **self.conan_data["sources"][self.version], strip_root=True) + + def build(self): + apply_conandata_patches(self) + + def package(self): + copy(self, "LICENSE*", + dst=os.path.join(self.package_folder, "licenses"), + src=self.source_folder) + copy(self, "*", + dst=os.path.join(self.package_folder, "include"), + src=os.path.join(self.source_folder, "include")) + + def package_info(self): + self.cpp_info.bindirs = [] + self.cpp_info.libdirs = [] + + self.cpp_info.set_property("cmake_target_name", "NuDB") + self.cpp_info.set_property("cmake_target_aliases", ["NuDB::nudb"]) + self.cpp_info.set_property("cmake_find_mode", "both") + + self.cpp_info.components["core"].set_property("cmake_target_name", "nudb") + self.cpp_info.components["core"].names["cmake_find_package"] = "nudb" + self.cpp_info.components["core"].names["cmake_find_package_multi"] = "nudb" + self.cpp_info.components["core"].requires = ["boost::thread", "boost::system"] + + # TODO: to remove in conan v2 once cmake_find_package_* generators removed + self.cpp_info.names["cmake_find_package"] = "NuDB" + self.cpp_info.names["cmake_find_package_multi"] = "NuDB" diff --git a/external/nudb/patches/2.0.8-0001-add-include-stdexcept-for-msvc.patch b/external/nudb/patches/2.0.8-0001-add-include-stdexcept-for-msvc.patch new file mode 100644 index 00000000000..2d5264f3ce4 --- /dev/null +++ b/external/nudb/patches/2.0.8-0001-add-include-stdexcept-for-msvc.patch @@ -0,0 +1,24 @@ +diff --git a/include/nudb/detail/stream.hpp b/include/nudb/detail/stream.hpp +index 6c07bf1..e0ce8ed 100644 +--- a/include/nudb/detail/stream.hpp ++++ b/include/nudb/detail/stream.hpp +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + namespace nudb { + namespace detail { +diff --git a/include/nudb/impl/context.ipp b/include/nudb/impl/context.ipp +index beb7058..ffde0b3 100644 +--- a/include/nudb/impl/context.ipp ++++ b/include/nudb/impl/context.ipp +@@ -9,6 +9,7 @@ + #define NUDB_IMPL_CONTEXT_IPP + + #include ++#include + + namespace nudb { + From 2820feb02a42414c7cfdcd97535e9ae4837d9fa6 Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Mon, 29 Jul 2024 19:02:12 -0400 Subject: [PATCH 33/82] Ensure levelization sorting is ASCII-order across platforms (#5072) --- Builds/levelization/levelization.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Builds/levelization/levelization.sh b/Builds/levelization/levelization.sh index f8f21bb9d23..3c43a23092f 100755 --- a/Builds/levelization/levelization.sh +++ b/Builds/levelization/levelization.sh @@ -13,6 +13,9 @@ then git clean -ix fi +# Ensure all sorting is ASCII-order consistently across platforms. +export LANG=C + rm -rfv results mkdir results includes="$( pwd )/results/rawincludes.txt" From a39720e94a3fb5be07d0b526c840f2e607db42cb Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 30 Jul 2024 11:18:25 -0400 Subject: [PATCH 34/82] fix: change error for invalid `feature` param in `feature` RPC (#5063) * Returns an "Invalid parameters" error if the `feature` parameter is provided and is not a string. --- src/test/rpc/Feature_test.cpp | 25 ++++++++++++++++++++++--- src/xrpld/rpc/handlers/Feature1.cpp | 9 +++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/test/rpc/Feature_test.cpp b/src/test/rpc/Feature_test.cpp index 488255542f2..12d4b27745c 100644 --- a/src/test/rpc/Feature_test.cpp +++ b/src/test/rpc/Feature_test.cpp @@ -229,9 +229,28 @@ class Feature_test : public beast::unit_test::suite using namespace test::jtx; Env env{*this}; - auto jrr = env.rpc("feature", "AllTheThings")[jss::result]; - BEAST_EXPECT(jrr[jss::error] == "badFeature"); - BEAST_EXPECT(jrr[jss::error_message] == "Feature unknown or invalid."); + auto testInvalidParam = [&](auto const& param) { + Json::Value params; + params[jss::feature] = param; + auto jrr = + env.rpc("json", "feature", to_string(params))[jss::result]; + BEAST_EXPECT(jrr[jss::error] == "invalidParams"); + BEAST_EXPECT(jrr[jss::error_message] == "Invalid parameters."); + }; + + testInvalidParam(1); + testInvalidParam(1.1); + testInvalidParam(true); + testInvalidParam(Json::Value(Json::nullValue)); + testInvalidParam(Json::Value(Json::objectValue)); + testInvalidParam(Json::Value(Json::arrayValue)); + + { + auto jrr = env.rpc("feature", "AllTheThings")[jss::result]; + BEAST_EXPECT(jrr[jss::error] == "badFeature"); + BEAST_EXPECT( + jrr[jss::error_message] == "Feature unknown or invalid."); + } } void diff --git a/src/xrpld/rpc/handlers/Feature1.cpp b/src/xrpld/rpc/handlers/Feature1.cpp index d4499f120ef..c06756ca00a 100644 --- a/src/xrpld/rpc/handlers/Feature1.cpp +++ b/src/xrpld/rpc/handlers/Feature1.cpp @@ -38,6 +38,15 @@ doFeature(RPC::JsonContext& context) if (context.app.config().reporting()) return rpcError(rpcREPORTING_UNSUPPORTED); + if (context.params.isMember(jss::feature)) + { + // ensure that the `feature` param is a string + if (!context.params[jss::feature].isString()) + { + return rpcError(rpcINVALID_PARAMS); + } + } + bool const isAdmin = context.role == Role::ADMIN; // Get majority amendment status majorityAmendments_t majorities; From b9b75ddcf5bd5dfda98c34480326e4304694a731 Mon Sep 17 00:00:00 2001 From: Scott Schurr Date: Tue, 30 Jul 2024 09:47:04 -0700 Subject: [PATCH 35/82] Remove unused constants from resource/Fees.h (#4856) --- include/xrpl/resource/Fees.h | 41 ++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/include/xrpl/resource/Fees.h b/include/xrpl/resource/Fees.h index d3750ec8282..1eb1a9bd725 100644 --- a/include/xrpl/resource/Fees.h +++ b/include/xrpl/resource/Fees.h @@ -25,43 +25,38 @@ namespace ripple { namespace Resource { +// clang-format off /** Schedule of fees charged for imposing load on the server. */ /** @{ */ -extern Charge const - feeInvalidRequest; // A request that we can immediately tell is invalid +extern Charge const feeInvalidRequest; // A request that we can immediately + // tell is invalid extern Charge const feeRequestNoReply; // A request that we cannot satisfy -extern Charge const feeInvalidSignature; // An object whose signature we had to - // check and it failed +extern Charge const feeInvalidSignature; // An object whose signature we had + // to check and it failed extern Charge const feeUnwantedData; // Data we have no use for -extern Charge const feeBadData; // Data we have to verify before rejecting +extern Charge const feeBadData; // Data we have to verify before + // rejecting // RPC loads -extern Charge const - feeInvalidRPC; // An RPC request that we can immediately tell is invalid. -extern Charge const feeReferenceRPC; // A default "reference" unspecified load -extern Charge const feeExceptionRPC; // An RPC load that causes an exception -extern Charge const feeLightRPC; // A normal RPC command -extern Charge const feeLowBurdenRPC; // A slightly burdensome RPC load -extern Charge const feeMediumBurdenRPC; // A somewhat burdensome RPC load -extern Charge const feeHighBurdenRPC; // A very burdensome RPC load -extern Charge const feePathFindUpdate; // An update to an existing PF request +extern Charge const feeInvalidRPC; // An RPC request that we can + // immediately tell is invalid. +extern Charge const feeReferenceRPC; // A default "reference" unspecified + // load +extern Charge const feeExceptionRPC; // RPC load that causes an exception +extern Charge const feeMediumBurdenRPC; // A somewhat burdensome RPC load +extern Charge const feeHighBurdenRPC; // A very burdensome RPC load // Peer loads extern Charge const feeLightPeer; // Requires no reply -extern Charge const feeLowBurdenPeer; // Quick/cheap, slight reply extern Charge const feeMediumBurdenPeer; // Requires some work extern Charge const feeHighBurdenPeer; // Extensive work -// Good things -extern Charge const - feeNewTrustedNote; // A new transaction/validation/proposal we trust -extern Charge const feeNewValidTx; // A new, valid transaction -extern Charge const feeSatisfiedRequest; // Data we requested - // Administrative -extern Charge const feeWarning; // The cost of receiving a warning -extern Charge const feeDrop; // The cost of being dropped for excess load +extern Charge const feeWarning; // The cost of receiving a warning +extern Charge const feeDrop; // The cost of being dropped for + // excess load /** @} */ +// clang-format on } // namespace Resource } // namespace ripple From f5a349558e0854078917b731ad1cba316ae71650 Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Tue, 30 Jul 2024 20:19:03 -0400 Subject: [PATCH 36/82] docs: Document the process for merging pull requests (#5010) --- CONTRIBUTING.md | 220 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 214 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5355878fa79..ceca1eaa6fc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -73,27 +73,235 @@ The source must be formatted according to the style guide below. Header includes must be [levelized](./Builds/levelization). +Changes should be usually squashed down into a single commit. +Some larger or more complicated change sets make more sense, +and are easier to review if organized into multiple logical commits. +Either way, all commits should fit the following criteria: +* Changes should be presented in a single commit or a logical + sequence of commits. + Specifically, chronological commits that simply + reflect the history of how the author implemented + the change, "warts and all", are not useful to + reviewers. +* Every commit should have a [good message](#good-commit-messages). + to explain a specific aspects of the change. +* Every commit should be signed. +* Every commit should be well-formed (builds successfully, + unit tests passing), as this helps to resolve merge + conflicts, and makes it easier to use `git bisect` + to find bugs. + +### Good commit messages + +Refer to +["How to Write a Git Commit Message"](https://cbea.ms/git-commit/) +for general rules on writing a good commit message. + +In addition to those guidelines, please add one of the following +prefixes to the subject line if appropriate. +* `fix:` - The primary purpose is to fix an existing bug. +* `perf:` - The primary purpose is performance improvements. +* `refactor:` - The changes refactor code without affecting + functionality. +* `test:` - The changes _only_ affect unit tests. +* `docs:` - The changes _only_ affect documentation. This can + include code comments in addition to `.md` files like this one. +* `build:` - The changes _only_ affect the build process, + including CMake and/or Conan settings. +* `chore:` - Other tasks that don't affect the binary, but don't fit + any of the other cases. e.g. formatting, git settings, updating + Github Actions jobs. + +Whenever possible, when updating commits after the PR is open, please +add the PR number to the end of the subject line. e.g. `test: Add +unit tests for Feature X (#1234)`. ## Pull requests In general, pull requests use `develop` as the base branch. - (Hotfixes are an exception.) -Changes to pull requests must be added as new commits. -Once code reviewers have started looking at your code, please avoid -force-pushing a branch in a pull request. +If your changes are not quite ready, but you want to make it easily available +for preliminary examination or review, you can create a "Draft" pull request. +While a pull request is marked as a "Draft", you can rebase or reorganize the +commits in the pull request as desired. + +Github pull requests are created as "Ready" by default, or you can mark +a "Draft" pull request as "Ready". +Once a pull request is marked as "Ready", +any changes must be added as new commits. Do not +force-push to a branch in a pull request under review. +(This includes rebasing your branch onto the updated base branch. +Use a merge operation, instead or hit the "Update branch" button +at the bottom of the Github PR page.) This preserves the ability for reviewers to filter changes since their last review. -A pull request must obtain **approvals from at least two reviewers** before it -can be considered for merge by a Maintainer. +A pull request must obtain **approvals from at least two reviewers** +before it can be considered for merge by a Maintainer. Maintainers retain discretion to require more approvals if they feel the credibility of the existing approvals is insufficient. Pull requests must be merged by [squash-and-merge][2] to preserve a linear history for the `develop` branch. +### When and how to merge pull requests + +#### "Passed" + +A pull request should only have the "Passed" label added when it +meets a few criteria: + +1. It must have two approving reviews [as described + above](#pull-requests). (Exception: PRs that are deemed "trivial" + only need one approval.) +2. All CI checks must be complete and passed. (One-off failures may + be acceptable if they are related to a known issue.) +3. The PR must have a [good commit message](#good-commit-messages). + * If the PR started with a good commit message, and it doesn't + need to be updated, the author can indicate that in a comment. + * Any contributor, preferably the author, can leave a comment + suggesting a commit message. + * If the author squashes and rebases the code in preparation for + merge, they should also ensure the commit message(s) are updated + as well. +4. The PR branch must be up to date with the base branch (usually + `develop`). This is usually accomplised by merging the base branch + into the feature branch, but if the other criteria are met, the + changes can be squashed and rebased on top of the base branch. +5. Finally, and most importantly, the author of the PR must + positively indicate that the PR is ready to merge. That can be + accomplished by adding the "Passed" label if their role allows, + or by leaving a comment to the effect that the PR is ready to + merge. + +Once the "Passed" label is added, a maintainer may merge the PR at +any time, so don't use it lightly. + +#### Instructions for maintainers + +The maintainer should double-check that the PR has met all the +necessary criteria, and can request additional information from the +owner, or additional reviews, and can always feel free to remove the +"Passed" label if appropriate. The maintainer has final say on +whether a PR gets merged, and are encouraged to communicate and +issues or concerns to other maintainers. + +##### Most pull requests: "Squash and merge" + +Most pull requests don't need special handling, and can simply be +merged using the "Squash and merge" button on the Github UI. Update +the suggested commit message if necessary. + +##### Slightly more complicated pull requests + +Some pull requests need to be pushed to `develop` as more than one +commit. There are multiple ways to accomplish this. If the author +describes a process, and it is reasonable, follow it. Otherwise, do +a fast forward only merge (`--ff-only`) on the command line and push. + +Either way, check that: +* The commits are based on the current tip of `develop`. +* The commits are clean: No merge commits (except when reverse + merging), no "[FOLD]" or "fixup!" messages. +* All commits are signed. If the commits are not signed by the author, use + `git commit --amend -S` to sign them yourself. +* At least one (but preferably all) of the commits has the PR number + in the commit message. + +**Never use the "Create a merge commit" or "Rebase and merge" + functions!** + +##### Releases, release candidates, and betas + +All releases, including release candidates and betas, are handled +differently from typical PRs. Most importantly, never use +the Github UI to merge a release. + +1. There are two possible conditions that the `develop` branch will + be in when preparing a release. + 1. Ready or almost ready to go: There may be one or two PRs that + need to be merged, but otherwise, the only change needed is to + update the version number in `BuildInfo.cpp`. In this case, + merge those PRs as appropriate, updating the second one, and + waiting for CI to finish in between. Then update + `BuildInfo.cpp`. + 2. Several pending PRs: In this case, do not use the Github UI, + because the delays waiting for CI in between each merge will be + unnecessarily onerous. Instead, create a working branch (e.g. + `develop-next`) based off of `develop`. Squash the changes + from each PR onto the branch, one commit each (unless + more are needed), being sure to sign each commit and update + the commit message to include the PR number. You may be able + to use a fast-forward merge for the first PR. The workflow may + look something like: +``` +git fetch upstream +git checkout upstream/develop +git checkout -b develop-next +# Use -S on the ff-only merge if prbranch1 isn't signed. +# Or do another branch first. +git merge --ff-only user1/prbranch1 +git merge --squash user2/prbranch2 +git commit -S +git merge --squash user3/prbranch3 +git commit -S +[...] +git push --set-upstream origin develop-next + +``` +2. Create the Pull Request with `release` as the base branch. If any + of the included PRs are still open, + [use closing keywords](https://docs.github.com/articles/closing-issues-using-keywords) + in the description to ensure they are closed when the code is + released. e.g. "Closes #1234" +3. Instead of the default template, reuse and update the message from + the previous release. Include the following verbiage somewhere in + the description: +``` +The base branch is release. All releases (including betas) go in +release. This PR will be merged with --ff-only (not squashed or +rebased, and not using the GitHub UI) to both release and develop. +``` +4. Sign-offs for the three platforms usually occur offline, but at + least one approval will be needed on the PR. +5. Once everything is ready to go, open a terminal, and do the + fast-forward merges manually. Do not push any branches until you + verify that all of them update correctly. +``` +git fetch upstream +git checkout -b upstream--develop -t upstream/develop || git checkout upstream--develop +git reset --hard upstream/develop +# develop-next must be signed already! +git merge --ff-only origin/develop-next +git checkout -b upstream--release -t upstream/release || git checkout upstream--release +git reset --hard upstream/release +git merge --ff-only origin/develop-next +# Only do these 3 steps if pushing a release. No betas or RCs +git checkout -b upstream--master -t upstream/master || git checkout upstream--master +git reset --hard upstream/master +git merge --ff-only origin/develop-next +# Check that all of the branches are updated +git log -1 --oneline +# The output should look like: +# 02ec8b7962 (HEAD -> upstream--master, origin/develop-next, upstream--release, upstream--develop, develop-next) Set version to 2.2.0-rc1 +# Note that all of the upstream--develop/release/master are on this commit. +# (Master will be missing for betas, etc.) +# Just to be safe, do a dry run first: +git push --dry-run upstream-push HEAD:develop +git push --dry-run upstream-push HEAD:release +# git push --dry-run upstream-push HEAD:master +# Now push +git push upstream-push HEAD:develop +git push upstream-push HEAD:release +# git push upstream-push HEAD:master +# Don't forget to tag the release, too. +git tag +git push upstream-push +``` +6. Finally +[create a new release on Github](https://github.com/XRPLF/rippled/releases). + # Style guide From e5aa605742befe585309cb380796fa6d56bb6f04 Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Wed, 31 Jul 2024 17:14:04 -0400 Subject: [PATCH 37/82] Set version to 2.3.0-b2 --- src/libxrpl/protocol/BuildInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libxrpl/protocol/BuildInfo.cpp b/src/libxrpl/protocol/BuildInfo.cpp index b0a7bcc9ed7..3a05f512455 100644 --- a/src/libxrpl/protocol/BuildInfo.cpp +++ b/src/libxrpl/protocol/BuildInfo.cpp @@ -33,7 +33,7 @@ namespace BuildInfo { // and follow the format described at http://semver.org/ //------------------------------------------------------------------------------ // clang-format off -char const* const versionString = "2.3.0-b1" +char const* const versionString = "2.3.0-b2" // clang-format on #if defined(DEBUG) || defined(SANITIZER) From ffc343a2bc274ee81db9a3cef050e4fd674507a6 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Fri, 2 Aug 2024 21:58:05 +0100 Subject: [PATCH 38/82] Fix crash inside `OverlayImpl` loops over `ids_` (#5071) --- src/test/overlay/tx_reduce_relay_test.cpp | 3 +++ src/xrpld/overlay/detail/OverlayImpl.cpp | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/test/overlay/tx_reduce_relay_test.cpp b/src/test/overlay/tx_reduce_relay_test.cpp index 074976e8586..3065bcbb685 100644 --- a/src/test/overlay/tx_reduce_relay_test.cpp +++ b/src/test/overlay/tx_reduce_relay_test.cpp @@ -189,7 +189,10 @@ class tx_reduce_relay_test : public beast::unit_test::suite consumer, std::move(stream_ptr), overlay); + BEAST_EXPECT( + overlay.findPeerByPublicKey(key) == std::shared_ptr{}); overlay.add_active(peer); + BEAST_EXPECT(overlay.findPeerByPublicKey(key) == peer); peers.emplace_back(peer); // overlay stores week ptr to PeerImp lid_ += 2; rid_ += 2; diff --git a/src/xrpld/overlay/detail/OverlayImpl.cpp b/src/xrpld/overlay/detail/OverlayImpl.cpp index f033ad4e9f9..1978a2617aa 100644 --- a/src/xrpld/overlay/detail/OverlayImpl.cpp +++ b/src/xrpld/overlay/detail/OverlayImpl.cpp @@ -1163,9 +1163,11 @@ OverlayImpl::getActivePeers( disabled = enabledInSkip = 0; ret.reserve(ids_.size()); + // NOTE The purpose of p is to delay the destruction of PeerImp + std::shared_ptr p; for (auto& [id, w] : ids_) { - if (auto p = w.lock()) + if (p = w.lock(); p != nullptr) { bool const reduceRelayEnabled = p->txReduceRelayEnabled(); // tx reduced relay feature disabled @@ -1205,9 +1207,11 @@ std::shared_ptr OverlayImpl::findPeerByPublicKey(PublicKey const& pubKey) { std::lock_guard lock(mutex_); + // NOTE The purpose of peer is to delay the destruction of PeerImp + std::shared_ptr peer; for (auto const& e : ids_) { - if (auto peer = e.second.lock()) + if (peer = e.second.lock(); peer != nullptr) { if (peer->getNodePublic() == pubKey) return peer; From eedfec015eec9e13d0f96da0db08d7cc38805f8b Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Fri, 2 Aug 2024 22:25:44 +0100 Subject: [PATCH 39/82] Update gcovr EXCLUDE (#5084) --- cmake/RippledCov.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/RippledCov.cmake b/cmake/RippledCov.cmake index ce7536e8eeb..3c48bb1c145 100644 --- a/cmake/RippledCov.cmake +++ b/cmake/RippledCov.cmake @@ -33,6 +33,6 @@ setup_target_for_coverage_gcovr( FORMAT ${coverage_format} EXECUTABLE rippled EXECUTABLE_ARGS --unittest$<$:=${coverage_test}> --unittest-jobs ${coverage_test_parallelism} --quiet --unittest-log - EXCLUDE "src/test" "${CMAKE_BINARY_DIR}/proto_gen" "${CMAKE_BINARY_DIR}/proto_gen_grpc" + EXCLUDE "src/test" "include/xrpl/beast/test" "include/xrpl/beast/unit_test" "${CMAKE_BINARY_DIR}/pb-xrpl.libpb" DEPENDENCIES rippled ) From 7d27b1119092e3195238a1897d6012c3372e6c53 Mon Sep 17 00:00:00 2001 From: John Freeman Date: Fri, 2 Aug 2024 19:03:05 -0500 Subject: [PATCH 40/82] Remove shards (#5066) --- Builds/levelization/results/loops.txt | 10 +- Builds/levelization/results/ordering.txt | 11 +- cfg/rippled-example.cfg | 47 +- cfg/rippled-reporting.cfg | 47 +- cmake/RippledCore.cmake | 1 - include/xrpl/basics/ThreadSafetyAnalysis.h | 63 - include/xrpl/proto/ripple.proto | 65 - include/xrpl/protocol/HashPrefix.h | 3 - include/xrpl/protocol/SystemParameters.h | 3 - include/xrpl/protocol/jss.h | 12 +- src/test/net/DatabaseDownloader_test.cpp | 315 --- src/test/nodestore/DatabaseShard_test.cpp | 1894 -------------- src/test/nodestore/Database_test.cpp | 31 - src/test/rpc/NodeToShardRPC_test.cpp | 414 --- src/test/rpc/RPCCall_test.cpp | 294 --- src/test/rpc/ShardArchiveHandler_test.cpp | 705 ------ src/test/shamap/common.h | 13 +- src/xrpld/app/consensus/RCLConsensus.cpp | 1 - src/xrpld/app/ledger/InboundLedger.h | 1 - src/xrpld/app/ledger/LedgerMaster.h | 3 - src/xrpld/app/ledger/detail/InboundLedger.cpp | 52 +- .../app/ledger/detail/InboundLedgers.cpp | 25 +- src/xrpld/app/ledger/detail/LedgerMaster.cpp | 101 +- src/xrpld/app/main/Application.cpp | 194 +- src/xrpld/app/main/Application.h | 10 - src/xrpld/app/main/DBInit.h | 120 - src/xrpld/app/main/Main.cpp | 6 - src/xrpld/app/misc/NetworkOPs.cpp | 6 +- src/xrpld/app/misc/SHAMapStoreImp.cpp | 25 +- src/xrpld/app/rdb/Download.h | 79 - src/xrpld/app/rdb/README.md | 33 +- src/xrpld/app/rdb/ShardArchive.h | 78 - src/xrpld/app/rdb/State.h | 1 - src/xrpld/app/rdb/UnitaryShard.h | 155 -- .../rdb/backend/detail/{detail => }/Node.cpp | 97 +- src/xrpld/app/rdb/backend/detail/Node.h | 26 +- .../rdb/backend/detail/PostgresDatabase.cpp | 1 - .../app/rdb/backend/detail/SQLiteDatabase.cpp | 893 +------ src/xrpld/app/rdb/backend/detail/Shard.h | 90 - .../app/rdb/backend/detail/detail/Shard.cpp | 147 -- src/xrpld/app/rdb/detail/Download.cpp | 152 -- .../app/rdb/detail/RelationalDatabase.cpp | 1 - src/xrpld/app/rdb/detail/ShardArchive.cpp | 68 - src/xrpld/app/rdb/detail/UnitaryShard.cpp | 320 --- src/xrpld/core/Config.h | 1 - src/xrpld/core/ConfigSections.h | 6 - src/xrpld/core/Job.h | 1 - src/xrpld/core/JobTypes.h | 1 - src/xrpld/net/DatabaseBody.h | 179 -- src/xrpld/net/DatabaseDownloader.h | 76 - src/xrpld/net/HTTPDownloader.h | 130 - src/xrpld/net/HTTPStream.h | 165 -- src/xrpld/net/ShardDownloader.md | 311 --- src/xrpld/net/detail/DatabaseBody.ipp | 231 -- src/xrpld/net/detail/DatabaseDownloader.cpp | 92 - src/xrpld/net/detail/HTTPDownloader.cpp | 340 --- src/xrpld/net/detail/HTTPStream.cpp | 203 -- src/xrpld/net/detail/RPCCall.cpp | 42 - src/xrpld/net/uml/interrupt_sequence.pu | 233 -- src/xrpld/net/uml/states.pu | 69 - src/xrpld/nodestore/Database.h | 96 +- src/xrpld/nodestore/DatabaseShard.h | 298 --- src/xrpld/nodestore/DeterministicShard.md | 162 -- src/xrpld/nodestore/Manager.h | 1 - src/xrpld/nodestore/README.md | 194 -- src/xrpld/nodestore/ShardInfo.h | 122 - src/xrpld/nodestore/ShardPool.md | 43 - src/xrpld/nodestore/ShardSizeTuning.md | 213 -- src/xrpld/nodestore/Types.h | 9 - src/xrpld/nodestore/backend/NuDBFactory.cpp | 23 +- src/xrpld/nodestore/detail/Database.cpp | 121 - .../nodestore/detail/DatabaseNodeImp.cpp | 1 - src/xrpld/nodestore/detail/DatabaseNodeImp.h | 6 - .../nodestore/detail/DatabaseRotatingImp.cpp | 12 - .../nodestore/detail/DatabaseRotatingImp.h | 3 - .../nodestore/detail/DatabaseShardImp.cpp | 2253 ----------------- src/xrpld/nodestore/detail/DatabaseShardImp.h | 429 ---- .../nodestore/detail/DeterministicShard.cpp | 216 -- .../nodestore/detail/DeterministicShard.h | 174 -- src/xrpld/nodestore/detail/Shard.cpp | 1272 ---------- src/xrpld/nodestore/detail/Shard.h | 432 ---- src/xrpld/nodestore/detail/ShardInfo.cpp | 136 - src/xrpld/nodestore/detail/TaskQueue.cpp | 76 - src/xrpld/nodestore/detail/TaskQueue.h | 64 - src/xrpld/overlay/Overlay.h | 9 - src/xrpld/overlay/Peer.h | 3 - src/xrpld/overlay/detail/Message.cpp | 4 - src/xrpld/overlay/detail/OverlayImpl.cpp | 109 - src/xrpld/overlay/detail/OverlayImpl.h | 16 - src/xrpld/overlay/detail/PeerImp.cpp | 385 +-- src/xrpld/overlay/detail/PeerImp.h | 17 - src/xrpld/overlay/detail/ProtocolMessage.h | 24 - src/xrpld/overlay/detail/TrafficCount.cpp | 6 - src/xrpld/overlay/detail/TrafficCount.h | 2 - src/xrpld/perflog/detail/PerfLogImp.cpp | 6 +- src/xrpld/rpc/ShardArchiveHandler.h | 176 -- src/xrpld/rpc/ShardVerificationScheduler.h | 84 - src/xrpld/rpc/detail/Handler.cpp | 3 - src/xrpld/rpc/detail/ShardArchiveHandler.cpp | 585 ----- .../rpc/detail/ShardVerificationScheduler.cpp | 68 - src/xrpld/rpc/handlers/CrawlShards.cpp | 73 - src/xrpld/rpc/handlers/DownloadShard.cpp | 176 -- src/xrpld/rpc/handlers/GetCounts.cpp | 30 +- src/xrpld/rpc/handlers/Handlers.h | 6 - src/xrpld/rpc/handlers/NodeToShard.cpp | 86 - src/xrpld/rpc/handlers/Tx.cpp | 1 - src/xrpld/shamap/Family.h | 19 +- src/xrpld/shamap/NodeFamily.h | 12 +- src/xrpld/shamap/ShardFamily.h | 125 - src/xrpld/shamap/detail/SHAMap.cpp | 5 +- src/xrpld/shamap/detail/SHAMapSync.cpp | 13 +- src/xrpld/shamap/detail/ShardFamily.cpp | 198 -- 112 files changed, 115 insertions(+), 17175 deletions(-) delete mode 100644 include/xrpl/basics/ThreadSafetyAnalysis.h delete mode 100644 src/test/net/DatabaseDownloader_test.cpp delete mode 100644 src/test/nodestore/DatabaseShard_test.cpp delete mode 100644 src/test/rpc/NodeToShardRPC_test.cpp delete mode 100644 src/test/rpc/ShardArchiveHandler_test.cpp delete mode 100644 src/xrpld/app/rdb/Download.h delete mode 100644 src/xrpld/app/rdb/ShardArchive.h delete mode 100644 src/xrpld/app/rdb/UnitaryShard.h rename src/xrpld/app/rdb/backend/detail/{detail => }/Node.cpp (93%) delete mode 100644 src/xrpld/app/rdb/backend/detail/Shard.h delete mode 100644 src/xrpld/app/rdb/backend/detail/detail/Shard.cpp delete mode 100644 src/xrpld/app/rdb/detail/Download.cpp delete mode 100644 src/xrpld/app/rdb/detail/ShardArchive.cpp delete mode 100644 src/xrpld/app/rdb/detail/UnitaryShard.cpp delete mode 100644 src/xrpld/net/DatabaseBody.h delete mode 100644 src/xrpld/net/DatabaseDownloader.h delete mode 100644 src/xrpld/net/HTTPDownloader.h delete mode 100644 src/xrpld/net/HTTPStream.h delete mode 100644 src/xrpld/net/ShardDownloader.md delete mode 100644 src/xrpld/net/detail/DatabaseBody.ipp delete mode 100644 src/xrpld/net/detail/DatabaseDownloader.cpp delete mode 100644 src/xrpld/net/detail/HTTPDownloader.cpp delete mode 100644 src/xrpld/net/detail/HTTPStream.cpp delete mode 100644 src/xrpld/net/uml/interrupt_sequence.pu delete mode 100644 src/xrpld/net/uml/states.pu delete mode 100644 src/xrpld/nodestore/DatabaseShard.h delete mode 100644 src/xrpld/nodestore/DeterministicShard.md delete mode 100644 src/xrpld/nodestore/ShardInfo.h delete mode 100644 src/xrpld/nodestore/ShardPool.md delete mode 100644 src/xrpld/nodestore/ShardSizeTuning.md delete mode 100644 src/xrpld/nodestore/detail/DatabaseShardImp.cpp delete mode 100644 src/xrpld/nodestore/detail/DatabaseShardImp.h delete mode 100644 src/xrpld/nodestore/detail/DeterministicShard.cpp delete mode 100644 src/xrpld/nodestore/detail/DeterministicShard.h delete mode 100644 src/xrpld/nodestore/detail/Shard.cpp delete mode 100644 src/xrpld/nodestore/detail/Shard.h delete mode 100644 src/xrpld/nodestore/detail/ShardInfo.cpp delete mode 100644 src/xrpld/nodestore/detail/TaskQueue.cpp delete mode 100644 src/xrpld/nodestore/detail/TaskQueue.h delete mode 100644 src/xrpld/rpc/ShardArchiveHandler.h delete mode 100644 src/xrpld/rpc/ShardVerificationScheduler.h delete mode 100644 src/xrpld/rpc/detail/ShardArchiveHandler.cpp delete mode 100644 src/xrpld/rpc/detail/ShardVerificationScheduler.cpp delete mode 100644 src/xrpld/rpc/handlers/CrawlShards.cpp delete mode 100644 src/xrpld/rpc/handlers/DownloadShard.cpp delete mode 100644 src/xrpld/rpc/handlers/NodeToShard.cpp delete mode 100644 src/xrpld/shamap/ShardFamily.h delete mode 100644 src/xrpld/shamap/detail/ShardFamily.cpp diff --git a/Builds/levelization/results/loops.txt b/Builds/levelization/results/loops.txt index ee7e6fd3bc6..f703a3a9d5d 100644 --- a/Builds/levelization/results/loops.txt +++ b/Builds/levelization/results/loops.txt @@ -16,11 +16,8 @@ Loop: xrpld.app xrpld.ledger Loop: xrpld.app xrpld.net xrpld.app > xrpld.net -Loop: xrpld.app xrpld.nodestore - xrpld.app > xrpld.nodestore - Loop: xrpld.app xrpld.overlay - xrpld.overlay ~= xrpld.app + xrpld.overlay == xrpld.app Loop: xrpld.app xrpld.peerfinder xrpld.app > xrpld.peerfinder @@ -38,10 +35,7 @@ Loop: xrpld.core xrpld.perflog xrpld.perflog ~= xrpld.core Loop: xrpld.net xrpld.rpc - xrpld.rpc > xrpld.net - -Loop: xrpld.nodestore xrpld.overlay - xrpld.overlay ~= xrpld.nodestore + xrpld.rpc ~= xrpld.net Loop: xrpld.overlay xrpld.rpc xrpld.rpc ~= xrpld.overlay diff --git a/Builds/levelization/results/ordering.txt b/Builds/levelization/results/ordering.txt index 87f9b03a54e..2856d783a1f 100644 --- a/Builds/levelization/results/ordering.txt +++ b/Builds/levelization/results/ordering.txt @@ -74,19 +74,13 @@ test.ledger > xrpld.app test.ledger > xrpld.core test.ledger > xrpld.ledger test.ledger > xrpl.protocol -test.net > test.jtx -test.net > test.toplevel -test.net > test.unit_test -test.net > xrpld.net test.nodestore > test.jtx test.nodestore > test.toplevel test.nodestore > test.unit_test test.nodestore > xrpl.basics -test.nodestore > xrpld.app test.nodestore > xrpld.core test.nodestore > xrpld.nodestore test.nodestore > xrpld.unity -test.nodestore > xrpl.protocol test.overlay > test.jtx test.overlay > test.unit_test test.overlay > xrpl.basics @@ -109,13 +103,11 @@ test.resource > test.unit_test test.resource > xrpl.basics test.resource > xrpl.resource test.rpc > test.jtx -test.rpc > test.nodestore test.rpc > test.toplevel test.rpc > xrpl.basics test.rpc > xrpld.app test.rpc > xrpld.core test.rpc > xrpld.net -test.rpc > xrpld.nodestore test.rpc > xrpld.overlay test.rpc > xrpld.rpc test.rpc > xrpl.json @@ -150,6 +142,7 @@ xrpld.app > test.unit_test xrpld.app > xrpl.basics xrpld.app > xrpld.conditions xrpld.app > xrpld.consensus +xrpld.app > xrpld.nodestore xrpld.app > xrpld.perflog xrpld.app > xrpl.json xrpld.app > xrpl.protocol @@ -186,14 +179,12 @@ xrpld.peerfinder > xrpl.basics xrpld.peerfinder > xrpld.core xrpld.peerfinder > xrpl.protocol xrpld.perflog > xrpl.basics -xrpld.perflog > xrpld.nodestore xrpld.perflog > xrpl.json xrpld.perflog > xrpl.protocol xrpld.rpc > xrpl.basics xrpld.rpc > xrpld.core xrpld.rpc > xrpld.ledger xrpld.rpc > xrpld.nodestore -xrpld.rpc > xrpld.shamap xrpld.rpc > xrpl.json xrpld.rpc > xrpl.protocol xrpld.rpc > xrpl.resource diff --git a/cfg/rippled-example.cfg b/cfg/rippled-example.cfg index 2ba2afa727d..b283900d013 100644 --- a/cfg/rippled-example.cfg +++ b/cfg/rippled-example.cfg @@ -1094,7 +1094,7 @@ # default value for the unspecified parameter. # # Note: the cache will not be created if online_delete -# is specified, or if shards are used. +# is specified. # # fast_load Boolean. If set, load the last persisted ledger # from disk upon process start before syncing to @@ -1107,10 +1107,6 @@ # earliest_seq The default is 32570 to match the XRP ledger # network's earliest allowed sequence. Alternate # networks may set this value. Minimum value of 1. -# If a [shard_db] section is defined, and this -# value is present either [node_db] or [shard_db], -# it must be defined with the same value in both -# sections. # # online_delete Minimum value of 256. Enable automatic purging # of older ledger information. Maintain at least this @@ -1192,32 +1188,6 @@ # your rippled.cfg file. # Partial pathnames are relative to the location of the rippled executable. # -# [shard_db] Settings for the Shard Database (optional) -# -# Format (without spaces): -# One or more lines of case-insensitive key / value pairs: -# '=' -# ... -# -# Example: -# path=db/shards/nudb -# -# Required keys: -# path Location to store the database -# -# Optional keys: -# max_historical_shards -# The maximum number of historical shards -# to store. -# -# [historical_shard_paths] Additional storage paths for the Shard Database (optional) -# -# Format (without spaces): -# One or more lines, each expressing a full path for storing historical shards: -# /mnt/disk1 -# /mnt/disk2 -# ... -# # [sqlite] Tuning settings for the SQLite databases (optional) # # Format (without spaces): @@ -1674,21 +1644,6 @@ path=/var/lib/rippled/db/nudb online_delete=512 advisory_delete=0 -# This is the persistent datastore for shards. It is important for the health -# of the ripple network that rippled operators shard as much as practical. -# NuDB requires SSD storage. Helpful information can be found at -# https://xrpl.org/history-sharding.html -#[shard_db] -#path=/var/lib/rippled/db/shards/nudb -#max_historical_shards=50 -# -# This optional section can be configured with a list -# of paths to use for storing historical shards. Each -# path must correspond to a unique filesystem. -#[historical_shard_paths] -#/path/1 -#/path/2 - [database_path] /var/lib/rippled/db diff --git a/cfg/rippled-reporting.cfg b/cfg/rippled-reporting.cfg index 290bcc5418a..9776ef5ee45 100644 --- a/cfg/rippled-reporting.cfg +++ b/cfg/rippled-reporting.cfg @@ -1039,17 +1039,13 @@ # default value for the unspecified parameter. # # Note: the cache will not be created if online_delete -# is specified, or if shards are used. +# is specified. # # Optional keys for NuDB or RocksDB: # # earliest_seq The default is 32570 to match the XRP ledger # network's earliest allowed sequence. Alternate # networks may set this value. Minimum value of 1. -# If a [shard_db] section is defined, and this -# value is present either [node_db] or [shard_db], -# it must be defined with the same value in both -# sections. # # online_delete Minimum value of 256. Enable automatic purging # of older ledger information. Maintain at least this @@ -1135,32 +1131,6 @@ # your rippled.cfg file. # Partial pathnames are relative to the location of the rippled executable. # -# [shard_db] Settings for the Shard Database (optional) -# -# Format (without spaces): -# One or more lines of case-insensitive key / value pairs: -# '=' -# ... -# -# Example: -# path=db/shards/nudb -# -# Required keys: -# path Location to store the database -# -# Optional keys: -# max_historical_shards -# The maximum number of historical shards -# to store. -# -# [historical_shard_paths] Additional storage paths for the Shard Database (optional) -# -# Format (without spaces): -# One or more lines, each expressing a full path for storing historical shards: -# /mnt/disk1 -# /mnt/disk2 -# ... -# # [sqlite] Tuning settings for the SQLite databases (optional) # # Format (without spaces): @@ -1616,21 +1586,6 @@ path=/var/lib/rippled-reporting/db/nudb # online_delete=512 # advisory_delete=0 -# This is the persistent datastore for shards. It is important for the health -# of the ripple network that rippled operators shard as much as practical. -# NuDB requires SSD storage. Helpful information can be found at -# https://xrpl.org/history-sharding.html -#[shard_db] -#path=/var/lib/rippled/db/shards/nudb -#max_historical_shards=50 -# -# This optional section can be configured with a list -# of paths to use for storing historical shards. Each -# path must correspond to a unique filesystem. -#[historical_shard_paths] -#/path/1 -#/path/2 - [database_path] /var/lib/rippled-reporting/db diff --git a/cmake/RippledCore.cmake b/cmake/RippledCore.cmake index 6a0060f7b32..18a424c484b 100644 --- a/cmake/RippledCore.cmake +++ b/cmake/RippledCore.cmake @@ -142,7 +142,6 @@ if(xrpld) set_source_files_properties( # these two seem to produce conflicts in beast teardown template methods src/test/rpc/ValidatorRPC_test.cpp - src/test/rpc/ShardArchiveHandler_test.cpp src/test/ledger/Invariants_test.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION TRUE) endif() diff --git a/include/xrpl/basics/ThreadSafetyAnalysis.h b/include/xrpl/basics/ThreadSafetyAnalysis.h deleted file mode 100644 index b1889d5b4c6..00000000000 --- a/include/xrpl/basics/ThreadSafetyAnalysis.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef RIPPLE_BASICS_THREAD_SAFTY_ANALYSIS_H_INCLUDED -#define RIPPLE_BASICS_THREAD_SAFTY_ANALYSIS_H_INCLUDED - -#ifdef RIPPLE_ENABLE_THREAD_SAFETY_ANNOTATIONS -#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) -#else -#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op -#endif - -#define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(capability(x)) - -#define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) - -#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) - -#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) - -#define ACQUIRED_BEFORE(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) - -#define ACQUIRED_AFTER(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) - -#define REQUIRES(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__)) - -#define REQUIRES_SHARED(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__)) - -#define ACQUIRE(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__)) - -#define ACQUIRE_SHARED(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__)) - -#define RELEASE(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__)) - -#define RELEASE_SHARED(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__)) - -#define RELEASE_GENERIC(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(release_generic_capability(__VA_ARGS__)) - -#define TRY_ACQUIRE(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__)) - -#define TRY_ACQUIRE_SHARED(...) \ - THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__)) - -#define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) - -#define ASSERT_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x)) - -#define ASSERT_SHARED_CAPABILITY(x) \ - THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x)) - -#define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) - -#define NO_THREAD_SAFETY_ANALYSIS \ - THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) - -#endif diff --git a/include/xrpl/proto/ripple.proto b/include/xrpl/proto/ripple.proto index 74cbfe8f6cb..a06bbd9a311 100644 --- a/include/xrpl/proto/ripple.proto +++ b/include/xrpl/proto/ripple.proto @@ -18,10 +18,6 @@ enum MessageType mtHAVE_SET = 35; mtVALIDATION = 41; mtGET_OBJECTS = 42; - mtGET_SHARD_INFO = 50; - mtSHARD_INFO = 51; - mtGET_PEER_SHARD_INFO = 52; - mtPEER_SHARD_INFO = 53; mtVALIDATORLIST = 54; mtSQUELCH = 55; mtVALIDATORLISTCOLLECTION = 56; @@ -29,8 +25,6 @@ enum MessageType mtPROOF_PATH_RESPONSE = 58; mtREPLAY_DELTA_REQ = 59; mtREPLAY_DELTA_RESPONSE = 60; - mtGET_PEER_SHARD_INFO_V2 = 61; - mtPEER_SHARD_INFO_V2 = 62; mtHAVE_TRANSACTIONS = 63; mtTRANSACTIONS = 64; } @@ -89,71 +83,12 @@ message TMLink required bytes nodePubKey = 1 [deprecated=true]; // node public key } -// Request info on shards held -message TMGetPeerShardInfo -{ - required uint32 hops = 1 [deprecated=true]; // number of hops to travel - optional bool lastLink = 2 [deprecated=true]; // true if last link in the peer chain - repeated TMLink peerChain = 3 [deprecated=true]; // public keys used to route messages -} - -// Info about shards held -message TMPeerShardInfo -{ - required string shardIndexes = 1 [deprecated=true]; // rangeSet of shard indexes - optional bytes nodePubKey = 2 [deprecated=true]; // node public key - optional string endpoint = 3 [deprecated=true]; // ipv6 or ipv4 address - optional bool lastLink = 4 [deprecated=true]; // true if last link in the peer chain - repeated TMLink peerChain = 5 [deprecated=true]; // public keys used to route messages -} - // Peer public key message TMPublicKey { required bytes publicKey = 1; } -// Request peer shard information -message TMGetPeerShardInfoV2 -{ - // Peer public keys used to route messages - repeated TMPublicKey peerChain = 1; - - // Remaining times to relay - required uint32 relays = 2; -} - -// Peer shard information -message TMPeerShardInfoV2 -{ - message TMIncomplete - { - required uint32 shardIndex = 1; - required uint32 state = 2; - - // State completion percent, 1 - 100 - optional uint32 progress = 3; - } - - // Message creation time - required uint32 timestamp = 1; - - // Incomplete shards being acquired or verified - repeated TMIncomplete incomplete = 2; - - // Verified immutable shards (RangeSet) - optional string finalized = 3; - - // Public key of node that authored the shard info - required bytes publicKey = 4; - - // Digital signature of node that authored the shard info - required bytes signature = 5; - - // Peer public keys used to route messages - repeated TMPublicKey peerChain = 6; -} - // A transaction can have only one input and one output. // If you want to send an amount that is greater than any single address of yours // you must first combine coins from one address to another. diff --git a/include/xrpl/protocol/HashPrefix.h b/include/xrpl/protocol/HashPrefix.h index 0979756b6e1..bc9c23d1910 100644 --- a/include/xrpl/protocol/HashPrefix.h +++ b/include/xrpl/protocol/HashPrefix.h @@ -84,9 +84,6 @@ enum class HashPrefix : std::uint32_t { /** Payment Channel Claim */ paymentChannelClaim = detail::make_hash_prefix('C', 'L', 'M'), - - /** shard info for signing */ - shardInfo = detail::make_hash_prefix('S', 'H', 'D'), }; template diff --git a/include/xrpl/protocol/SystemParameters.h b/include/xrpl/protocol/SystemParameters.h index c99944193ae..7531a0d5fb9 100644 --- a/include/xrpl/protocol/SystemParameters.h +++ b/include/xrpl/protocol/SystemParameters.h @@ -72,9 +72,6 @@ static constexpr std::uint32_t XRP_LEDGER_EARLIEST_SEQ{32570u}; * used in asserts and tests. */ static constexpr std::uint32_t XRP_LEDGER_EARLIEST_FEES{562177u}; -/** The number of ledgers in a shard */ -static constexpr std::uint32_t DEFAULT_LEDGERS_PER_SHARD{16384u}; - /** The minimum amount of support an amendment should have. @note This value is used by legacy code and will become obsolete diff --git a/include/xrpl/protocol/jss.h b/include/xrpl/protocol/jss.h index a46e15f39ef..84628da286f 100644 --- a/include/xrpl/protocol/jss.h +++ b/include/xrpl/protocol/jss.h @@ -89,7 +89,6 @@ JSS(EscrowFinish); // transaction type. JSS(Fee); // in/out: TransactionSign; field. JSS(FeeSettings); // ledger type. JSS(Flags); // in/out: TransactionSign; field. -JSS(incomplete_shards); // out: OverlayImpl, PeerImp JSS(Invalid); // JSS(LastLedgerSequence); // in: TransactionSign; field JSS(LastUpdateTime); // field. @@ -260,7 +259,6 @@ JSS(code); // out: errors JSS(command); // in: RPCHandler JSS(complete); // out: NetworkOPs, InboundLedger JSS(complete_ledgers); // out: NetworkOPs, PeerImp -JSS(complete_shards); // out: OverlayImpl, PeerImp JSS(consensus); // out: NetworkOPs, LedgerConsensus JSS(converge_time); // out: NetworkOPs JSS(converge_time_s); // out: NetworkOPs @@ -270,8 +268,6 @@ JSS(counters); // in/out: retrieve counters JSS(ctid); // in/out: Tx RPC JSS(currency_a); // out: BookChanges JSS(currency_b); // out: BookChanges -JSS(currentShard); // out: NodeToShardStatus -JSS(currentShardIndex); // out: NodeToShardStatus JSS(currency); // in: paths/PathRequest, STAmount // out: STPathSet, STAmount, // AccountLines @@ -344,8 +340,6 @@ JSS(fetch_pack); // out: NetworkOPs JSS(FIELDS); // out: RPC server_definitions // matches definitions.json format JSS(first); // out: rpc/Version -JSS(firstSequence); // out: NodeToShardStatus -JSS(firstShardIndex); // out: NodeToShardStatus JSS(finished); JSS(fix_txns); // in: LedgerCleaner JSS(flags); // out: AccountOffers, @@ -376,7 +370,7 @@ JSS(ident); // in: AccountCurrencies, AccountInfo, JSS(ignore_default); // in: AccountLines JSS(inLedger); // out: tx/Transaction JSS(inbound); // out: PeerImp -JSS(index); // in: LedgerEntry, DownloadShard +JSS(index); // in: LedgerEntry // out: STLedgerEntry, // LedgerEntry, TxHistory, LedgerData JSS(info); // out: ServerInfo, ConsensusInfo, FetchInfo @@ -406,8 +400,6 @@ JSS(key); // out JSS(key_type); // in/out: WalletPropose, TransactionSign JSS(latency); // out: PeerImp JSS(last); // out: RPCVersion -JSS(lastSequence); // out: NodeToShardStatus -JSS(lastShardIndex); // out: NodeToShardStatus JSS(last_close); // out: NetworkOPs JSS(last_refresh_time); // out: ValidatorSite JSS(last_refresh_status); // out: ValidatorSite @@ -631,7 +623,6 @@ JSS(server_status); // out: NetworkOPs JSS(server_version); // out: NetworkOPs JSS(settle_delay); // out: AccountChannels JSS(severity); // in: LogLevel -JSS(shards); // in/out: GetCounts, DownloadShard JSS(signature); // out: NetworkOPs, ChannelAuthorize JSS(signature_verified); // out: ChannelVerify JSS(signing_key); // out: NetworkOPs @@ -655,7 +646,6 @@ JSS(state_now); // in: Subscribe JSS(status); // error JSS(stop); // in: LedgerCleaner JSS(stop_history_tx_only); // in: Unsubscribe, stop history tx stream -JSS(storedSeqs); // out: NodeToShardStatus JSS(streams); // in: Subscribe, Unsubscribe JSS(strict); // in: AccountCurrencies, AccountInfo JSS(sub_index); // in: LedgerEntry diff --git a/src/test/net/DatabaseDownloader_test.cpp b/src/test/net/DatabaseDownloader_test.cpp deleted file mode 100644 index 99e98dd3d01..00000000000 --- a/src/test/net/DatabaseDownloader_test.cpp +++ /dev/null @@ -1,315 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright 2019 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 -#include -#include -#include -#include -#include -#include - -namespace ripple { -namespace test { - -#define REPORT_FAILURE(D) reportFailure(D, __FILE__, __LINE__) - -class DatabaseDownloader_test : public beast::unit_test::suite -{ - std::shared_ptr - createServer(jtx::Env& env, bool ssl = true) - { - std::vector list; - list.push_back(TrustedPublisherServer::randomValidator()); - return make_TrustedPublisherServer( - env.app().getIOService(), - list, - env.timeKeeper().now() + std::chrono::seconds{3600}, - // No future VLs - {}, - ssl); - } - - struct DownloadCompleter - { - std::mutex m; - std::condition_variable cv; - bool called = false; - boost::filesystem::path dest; - - void - operator()(boost::filesystem::path dst) - { - std::unique_lock lk(m); - called = true; - dest = std::move(dst); - cv.notify_one(); - }; - - bool - waitComplete() - { - std::unique_lock lk(m); - - auto stat = cv.wait_for( - lk, std::chrono::seconds(10), [this] { return called; }); - - called = false; - return stat; - }; - }; - DownloadCompleter cb; - - struct Downloader - { - test::StreamSink sink_; - beast::Journal journal_; - std::shared_ptr ptr_; - - Downloader(jtx::Env& env) - : journal_{sink_} - , ptr_{make_DatabaseDownloader( - env.app().getIOService(), - env.app().config(), - journal_)} - { - } - - ~Downloader() - { - ptr_->stop(); - } - - DatabaseDownloader* - operator->() - { - return ptr_.get(); - } - - DatabaseDownloader const* - operator->() const - { - return ptr_.get(); - } - }; - - void - reportFailure(Downloader const& dl, char const* file, int line) - { - std::stringstream ss; - ss << "Failed. LOGS:\n" - << dl.sink_.messages().str() - << "\nDownloadCompleter failure." - "\nDatabaseDownloader session active? " - << std::boolalpha << dl->sessionIsActive() - << "\nDatabaseDownloader is stopping? " << std::boolalpha - << dl->isStopping(); - - fail(ss.str(), file, line); - } - - void - testDownload(bool verify) - { - testcase << std::string("Basic download - SSL ") + - (verify ? "Verify" : "No Verify"); - - using namespace jtx; - - ripple::test::detail::FileDirGuard cert{ - *this, "_cert", "ca.pem", TrustedPublisherServer::ca_cert()}; - - Env env{*this, envconfig([&cert, &verify](std::unique_ptr cfg) { - if ((cfg->SSL_VERIFY = verify)) // yes, this is assignment - cfg->SSL_VERIFY_FILE = cert.file().string(); - return cfg; - })}; - - Downloader dl{env}; - - // create a TrustedPublisherServer as a simple HTTP - // server to request from. Use the /textfile endpoint - // to get a simple text file sent as response. - auto server = createServer(env); - log << "Downloading DB from " << server->local_endpoint() << std::endl; - - ripple::test::detail::FileDirGuard const data{ - *this, "downloads", "data", "", false, false}; - // initiate the download and wait for the callback - // to be invoked - auto stat = dl->download( - server->local_endpoint().address().to_string(), - std::to_string(server->local_endpoint().port()), - "/textfile", - 11, - data.file(), - std::function{std::ref(cb)}); - if (!BEAST_EXPECT(stat)) - { - REPORT_FAILURE(dl); - return; - } - if (!BEAST_EXPECT(cb.waitComplete())) - { - REPORT_FAILURE(dl); - return; - } - BEAST_EXPECT(cb.dest == data.file()); - if (!BEAST_EXPECT(boost::filesystem::exists(data.file()))) - return; - BEAST_EXPECT(boost::filesystem::file_size(data.file()) > 0); - } - - void - testFailures() - { - testcase("Error conditions"); - - using namespace jtx; - - Env env{*this}; - - { - // bad hostname - boost::system::error_code ec; - boost::asio::ip::tcp::resolver resolver{env.app().getIOService()}; - auto const results = resolver.resolve("badhostname", "443", ec); - // we require an error in resolving this name in order - // for this test to pass. Some networks might have DNS hijacking - // that prevent NXDOMAIN, in which case the failure is not - // possible, so we skip the test. - if (ec) - { - Downloader dl{env}; - ripple::test::detail::FileDirGuard const datafile{ - *this, "downloads", "data", "", false, false}; - BEAST_EXPECT(dl->download( - "badhostname", - "443", - "", - 11, - datafile.file(), - std::function{ - std::ref(cb)})); - if (!BEAST_EXPECT(cb.waitComplete())) - { - REPORT_FAILURE(dl); - } - BEAST_EXPECT(!boost::filesystem::exists(datafile.file())); - BEAST_EXPECTS( - dl.sink_.messages().str().find("async_resolve") != - std::string::npos, - dl.sink_.messages().str()); - } - } - { - // can't connect - Downloader dl{env}; - ripple::test::detail::FileDirGuard const datafile{ - *this, "downloads", "data", "", false, false}; - auto server = createServer(env); - auto host = server->local_endpoint().address().to_string(); - auto port = std::to_string(server->local_endpoint().port()); - log << "Downloading DB from " << server->local_endpoint() - << std::endl; - server->stop(); - BEAST_EXPECT(dl->download( - host, - port, - "", - 11, - datafile.file(), - std::function{std::ref(cb)})); - if (!BEAST_EXPECT(cb.waitComplete())) - { - REPORT_FAILURE(dl); - } - BEAST_EXPECT(!boost::filesystem::exists(datafile.file())); - BEAST_EXPECTS( - dl.sink_.messages().str().find("async_connect") != - std::string::npos, - dl.sink_.messages().str()); - } - { - // not ssl (failed handlshake) - Downloader dl{env}; - ripple::test::detail::FileDirGuard const datafile{ - *this, "downloads", "data", "", false, false}; - auto server = createServer(env, false); - log << "Downloading DB from " << server->local_endpoint() - << std::endl; - BEAST_EXPECT(dl->download( - server->local_endpoint().address().to_string(), - std::to_string(server->local_endpoint().port()), - "", - 11, - datafile.file(), - std::function{std::ref(cb)})); - if (!BEAST_EXPECT(cb.waitComplete())) - { - REPORT_FAILURE(dl); - } - BEAST_EXPECT(!boost::filesystem::exists(datafile.file())); - BEAST_EXPECTS( - dl.sink_.messages().str().find("async_handshake") != - std::string::npos, - dl.sink_.messages().str()); - } - { - // huge file (content length) - Downloader dl{env}; - ripple::test::detail::FileDirGuard const datafile{ - *this, "downloads", "data", "", false, false}; - auto server = createServer(env); - log << "Downloading DB from " << server->local_endpoint() - << std::endl; - BEAST_EXPECT(dl->download( - server->local_endpoint().address().to_string(), - std::to_string(server->local_endpoint().port()), - "/textfile/huge", - 11, - datafile.file(), - std::function{std::ref(cb)})); - if (!BEAST_EXPECT(cb.waitComplete())) - { - REPORT_FAILURE(dl); - } - BEAST_EXPECT(!boost::filesystem::exists(datafile.file())); - BEAST_EXPECTS( - dl.sink_.messages().str().find("Insufficient disk space") != - std::string::npos, - dl.sink_.messages().str()); - } - } - -public: - void - run() override - { - testDownload(true); - testDownload(false); - testFailures(); - } -}; - -#undef REPORT_FAILURE - -BEAST_DEFINE_TESTSUITE(DatabaseDownloader, net, ripple); -} // namespace test -} // namespace ripple diff --git a/src/test/nodestore/DatabaseShard_test.cpp b/src/test/nodestore/DatabaseShard_test.cpp deleted file mode 100644 index e185c43d157..00000000000 --- a/src/test/nodestore/DatabaseShard_test.cpp +++ /dev/null @@ -1,1894 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace ripple { -namespace NodeStore { - -/** std::uniform_int_distribution is platform dependent. - * Unit test for deterministic shards is the following: it generates - * predictable accounts and transactions, packs them into ledgers - * and makes the shard. The hash of this shard should be equal to the - * given value. On different platforms (precisely, Linux and Mac) - * hashes of the resulting shard was different. It was unvestigated - * that the problem is in the class std::uniform_int_distribution - * which generates different pseudorandom sequences on different - * platforms, but we need predictable sequence. - */ -template -struct uniformIntDistribution -{ - using resultType = IntType; - - const resultType A, B; - - struct paramType - { - const resultType A, B; - - paramType(resultType aa, resultType bb) : A(aa), B(bb) - { - } - }; - - explicit uniformIntDistribution( - const resultType a = 0, - const resultType b = std::numeric_limits::max()) - : A(a), B(b) - { - } - - explicit uniformIntDistribution(const paramType& params) - : A(params.A), B(params.B) - { - } - - template - resultType - operator()(Generator& g) const - { - return rnd(g, A, B); - } - - template - resultType - operator()(Generator& g, const paramType& params) const - { - return rnd(g, params.A, params.B); - } - - resultType - a() const - { - return A; - } - - resultType - b() const - { - return B; - } - - resultType - min() const - { - return A; - } - - resultType - max() const - { - return B; - } - -private: - template - resultType - rnd(Generator& g, const resultType a, const resultType b) const - { - static_assert( - std::is_convertible:: - value, - "Ups..."); - static_assert( - Generator::min() == 0, "If non-zero we have handle the offset"); - const resultType range = b - a + 1; - assert(Generator::max() >= range); // Just for safety - const resultType rejectLim = g.max() % range; - resultType n; - do - n = g(); - while (n <= rejectLim); - return (n % range) + a; - } -}; - -template -Integral -randInt(Engine& engine, Integral min, Integral max) -{ - assert(max > min); - - // This should have no state and constructing it should - // be very cheap. If that turns out not to be the case - // it could be hand-optimized. - return uniformIntDistribution(min, max)(engine); -} - -template -Integral -randInt(Engine& engine, Integral max) -{ - return randInt(engine, Integral(0), max); -} - -// Tests DatabaseShard class -// -class DatabaseShard_test : public TestBase -{ - static constexpr std::uint32_t maxSizeGb = 10; - static constexpr std::uint32_t maxHistoricalShards = 100; - static constexpr std::uint32_t ledgersPerShard = 256; - static constexpr std::uint32_t earliestSeq = ledgersPerShard + 1; - static constexpr std::uint32_t dataSizeMax = 4; - static constexpr std::uint32_t iniAmount = 1000000; - static constexpr std::uint32_t nTestShards = 4; - static constexpr std::chrono::seconds shardStoreTimeout = - std::chrono::seconds(60); - test::SuiteJournal journal_; - beast::temp_dir defNodeDir; - - struct TestData - { - /* ring used to generate pseudo-random sequence */ - beast::xor_shift_engine rng_; - /* number of shards to generate */ - int numShards_; - /* vector of accounts used to send test transactions */ - std::vector accounts_; - /* nAccounts_[i] is the number of these accounts existed before i-th - * ledger */ - std::vector nAccounts_; - /* payAccounts_[i][j] = {from, to} is the pair which consists of two - * number of accounts: source and destinations, which participate in - * j-th payment on i-th ledger */ - std::vector>> payAccounts_; - /* xrpAmount_[i] is the amount for all payments on i-th ledger */ - std::vector xrpAmount_; - /* ledgers_[i] is the i-th ledger which contains the above described - * accounts and payments */ - std::vector> ledgers_; - - TestData( - std::uint64_t const seedValue, - int dataSize = dataSizeMax, - int numShards = 1) - : rng_(seedValue), numShards_(numShards) - { - std::uint32_t n = 0; - std::uint32_t nLedgers = ledgersPerShard * numShards; - - nAccounts_.reserve(nLedgers); - payAccounts_.reserve(nLedgers); - xrpAmount_.reserve(nLedgers); - - for (std::uint32_t i = 0; i < nLedgers; ++i) - { - int p; - if (n >= 2) - p = randInt(rng_, 2 * dataSize); - else - p = 0; - - std::vector> pay; - pay.reserve(p); - - for (int j = 0; j < p; ++j) - { - int from, to; - do - { - from = randInt(rng_, n - 1); - to = randInt(rng_, n - 1); - } while (from == to); - - pay.push_back(std::make_pair(from, to)); - } - - n += !randInt(rng_, nLedgers / dataSize); - - if (n > accounts_.size()) - { - char str[9]; - for (int j = 0; j < 8; ++j) - str[j] = 'a' + randInt(rng_, 'z' - 'a'); - str[8] = 0; - accounts_.emplace_back(str); - } - - nAccounts_.push_back(n); - payAccounts_.push_back(std::move(pay)); - xrpAmount_.push_back(randInt(rng_, 90) + 10); - } - } - - bool - isNewAccounts(int seq) - { - return nAccounts_[seq] > (seq ? nAccounts_[seq - 1] : 0); - } - - void - makeLedgerData(test::jtx::Env& env_, std::uint32_t seq) - { - using namespace test::jtx; - - // The local fee may go up, especially in the online delete tests - while (env_.app().getFeeTrack().lowerLocalFee()) - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - - if (isNewAccounts(seq)) - env_.fund(XRP(iniAmount), accounts_[nAccounts_[seq] - 1]); - - for (std::uint32_t i = 0; i < payAccounts_[seq].size(); ++i) - { - env_( - pay(accounts_[payAccounts_[seq][i].first], - accounts_[payAccounts_[seq][i].second], - XRP(xrpAmount_[seq]))); - } - } - - bool - makeLedgers(test::jtx::Env& env_, std::uint32_t startIndex = 0) - { - if (startIndex == 0) - { - for (std::uint32_t i = 3; i <= ledgersPerShard; ++i) - { - if (!env_.close()) - return false; - std::shared_ptr ledger = - env_.app().getLedgerMaster().getClosedLedger(); - if (ledger->info().seq != i) - return false; - } - } - - for (std::uint32_t i = 0; i < ledgersPerShard * numShards_; ++i) - { - auto const index = i + (startIndex * ledgersPerShard); - - makeLedgerData(env_, i); - if (!env_.close()) - return false; - std::shared_ptr ledger = - env_.app().getLedgerMaster().getClosedLedger(); - if (ledger->info().seq != index + ledgersPerShard + 1) - return false; - ledgers_.push_back(ledger); - } - - return true; - } - }; - - void - testLedgerData( - TestData& data, - std::shared_ptr ledger, - std::uint32_t seq) - { - using namespace test::jtx; - - auto rootCount{0}; - auto accCount{0}; - auto sothCount{0}; - for (auto const& sles : ledger->sles) - { - if (sles->getType() == ltACCOUNT_ROOT) - { - int sq = sles->getFieldU32(sfSequence); - int reqsq = -1; - const auto id = sles->getAccountID(sfAccount); - - for (int i = 0; i < data.accounts_.size(); ++i) - { - if (id == data.accounts_[i].id()) - { - reqsq = ledgersPerShard + 1; - for (int j = 0; j <= seq; ++j) - if (data.nAccounts_[j] > i + 1 || - (data.nAccounts_[j] == i + 1 && - !data.isNewAccounts(j))) - { - for (int k = 0; k < data.payAccounts_[j].size(); - ++k) - if (data.payAccounts_[j][k].first == i) - reqsq++; - } - else - reqsq++; - ++accCount; - break; - } - } - if (reqsq == -1) - { - reqsq = data.nAccounts_[seq] + 1; - ++rootCount; - } - BEAST_EXPECT(sq == reqsq); - } - else - ++sothCount; - } - BEAST_EXPECT(rootCount == 1); - BEAST_EXPECT(accCount == data.nAccounts_[seq]); - BEAST_EXPECT(sothCount == 3); - - auto iniCount{0}; - auto setCount{0}; - auto payCount{0}; - auto tothCount{0}; - for (auto const& tx : ledger->txs) - { - if (tx.first->getTxnType() == ttPAYMENT) - { - std::int64_t xrpAmount = - tx.first->getFieldAmount(sfAmount).xrp().decimalXRP(); - if (xrpAmount == iniAmount) - ++iniCount; - else - { - ++payCount; - BEAST_EXPECT(xrpAmount == data.xrpAmount_[seq]); - } - } - else if (tx.first->getTxnType() == ttACCOUNT_SET) - ++setCount; - else - ++tothCount; - } - int newacc = data.isNewAccounts(seq) ? 1 : 0; - BEAST_EXPECT(iniCount == newacc); - BEAST_EXPECT(setCount == newacc); - BEAST_EXPECT(payCount == data.payAccounts_[seq].size()); - BEAST_EXPECT(tothCount == !seq); - } - - bool - saveLedger( - Database& db, - Ledger const& ledger, - std::shared_ptr const& next = {}) - { - // Store header - { - Serializer s(sizeof(std::uint32_t) + sizeof(LedgerInfo)); - s.add32(HashPrefix::ledgerMaster); - addRaw(ledger.info(), s); - db.store( - hotLEDGER, - std::move(s.modData()), - ledger.info().hash, - ledger.info().seq); - } - - // Store the state map - auto visitAcc = [&](SHAMapTreeNode const& node) { - Serializer s; - node.serializeWithPrefix(s); - db.store( - node.getType() == SHAMapNodeType::tnINNER ? hotUNKNOWN - : hotACCOUNT_NODE, - std::move(s.modData()), - node.getHash().as_uint256(), - ledger.info().seq); - return true; - }; - - if (ledger.stateMap().getHash().isNonZero()) - { - if (!ledger.stateMap().isValid()) - return false; - if (next && next->info().parentHash == ledger.info().hash) - { - auto have = next->stateMap().snapShot(false); - ledger.stateMap().snapShot(false)->visitDifferences( - &(*have), visitAcc); - } - else - ledger.stateMap().snapShot(false)->visitNodes(visitAcc); - } - - // Store the transaction map - auto visitTx = [&](SHAMapTreeNode& node) { - Serializer s; - node.serializeWithPrefix(s); - db.store( - node.getType() == SHAMapNodeType::tnINNER ? hotUNKNOWN - : hotTRANSACTION_NODE, - std::move(s.modData()), - node.getHash().as_uint256(), - ledger.info().seq); - return true; - }; - - if (ledger.info().txHash.isNonZero()) - { - if (!ledger.txMap().isValid()) - return false; - ledger.txMap().snapShot(false)->visitNodes(visitTx); - } - - return true; - } - - void - checkLedger(TestData& data, DatabaseShard& db, Ledger const& ledger) - { - auto fetched = db.fetchLedger(ledger.info().hash, ledger.info().seq); - if (!BEAST_EXPECT(fetched)) - return; - - testLedgerData(data, fetched, ledger.info().seq - ledgersPerShard - 1); - - // verify the metadata/header info by serializing to json - BEAST_EXPECT( - getJson(LedgerFill{ - ledger, nullptr, LedgerFill::full | LedgerFill::expand}) == - getJson(LedgerFill{ - *fetched, nullptr, LedgerFill::full | LedgerFill::expand})); - - BEAST_EXPECT( - getJson(LedgerFill{ - ledger, nullptr, LedgerFill::full | LedgerFill::binary}) == - getJson(LedgerFill{ - *fetched, nullptr, LedgerFill::full | LedgerFill::binary})); - - // walk shamap and validate each node - auto fcompAcc = [&](SHAMapTreeNode& node) -> bool { - Serializer s; - node.serializeWithPrefix(s); - auto nSrc{NodeObject::createObject( - node.getType() == SHAMapNodeType::tnINNER ? hotUNKNOWN - : hotACCOUNT_NODE, - std::move(s.modData()), - node.getHash().as_uint256())}; - if (!BEAST_EXPECT(nSrc)) - return false; - - auto nDst = db.fetchNodeObject( - node.getHash().as_uint256(), ledger.info().seq); - if (!BEAST_EXPECT(nDst)) - return false; - - BEAST_EXPECT(isSame(nSrc, nDst)); - - return true; - }; - if (ledger.stateMap().getHash().isNonZero()) - ledger.stateMap().snapShot(false)->visitNodes(fcompAcc); - - auto fcompTx = [&](SHAMapTreeNode& node) -> bool { - Serializer s; - node.serializeWithPrefix(s); - auto nSrc{NodeObject::createObject( - node.getType() == SHAMapNodeType::tnINNER ? hotUNKNOWN - : hotTRANSACTION_NODE, - std::move(s.modData()), - node.getHash().as_uint256())}; - if (!BEAST_EXPECT(nSrc)) - return false; - - auto nDst = db.fetchNodeObject( - node.getHash().as_uint256(), ledger.info().seq); - if (!BEAST_EXPECT(nDst)) - return false; - - BEAST_EXPECT(isSame(nSrc, nDst)); - - return true; - }; - if (ledger.info().txHash.isNonZero()) - ledger.txMap().snapShot(false)->visitNodes(fcompTx); - } - - std::string - bitmask2Rangeset(std::uint64_t bitmask) - { - std::string set; - if (!bitmask) - return set; - bool empty = true; - - for (std::uint32_t i = 0; i < 64 && bitmask; i++) - { - if (bitmask & (1ll << i)) - { - if (!empty) - set += ","; - set += std::to_string(i); - empty = false; - } - } - - RangeSet rs; - BEAST_EXPECT(from_string(rs, set)); - return ripple::to_string(rs); - } - - std::unique_ptr - testConfig( - std::string const& shardDir, - std::string const& nodeDir = std::string()) - { - using namespace test::jtx; - - return envconfig([&](std::unique_ptr cfg) { - // Shard store configuration - cfg->overwrite(ConfigSection::shardDatabase(), "path", shardDir); - cfg->overwrite( - ConfigSection::shardDatabase(), - "max_historical_shards", - std::to_string(maxHistoricalShards)); - cfg->overwrite( - ConfigSection::shardDatabase(), - "ledgers_per_shard", - std::to_string(ledgersPerShard)); - cfg->overwrite( - ConfigSection::shardDatabase(), - "earliest_seq", - std::to_string(earliestSeq)); - - // Node store configuration - cfg->overwrite( - ConfigSection::nodeDatabase(), - "path", - nodeDir.empty() ? defNodeDir.path() : nodeDir); - cfg->overwrite( - ConfigSection::nodeDatabase(), - "ledgers_per_shard", - std::to_string(ledgersPerShard)); - cfg->overwrite( - ConfigSection::nodeDatabase(), - "earliest_seq", - std::to_string(earliestSeq)); - return cfg; - }); - } - - std::optional - waitShard( - DatabaseShard& shardStore, - std::uint32_t shardIndex, - std::chrono::seconds timeout = shardStoreTimeout) - { - auto const end{std::chrono::system_clock::now() + timeout}; - while (shardStore.getNumTasks() || - !boost::icl::contains( - shardStore.getShardInfo()->finalized(), shardIndex)) - { - if (!BEAST_EXPECT(std::chrono::system_clock::now() < end)) - return std::nullopt; - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } - - return shardIndex; - } - - std::optional - createShard( - TestData& data, - DatabaseShard& shardStore, - int maxShardIndex = 1, - int shardOffset = 0) - { - int shardIndex{-1}; - - for (std::uint32_t i = 0; i < ledgersPerShard; ++i) - { - auto const ledgerSeq{shardStore.prepareLedger( - (maxShardIndex + 1) * ledgersPerShard)}; - if (!BEAST_EXPECT(ledgerSeq != std::nullopt)) - return std::nullopt; - - shardIndex = shardStore.seqToShardIndex(*ledgerSeq); - - int const arrInd = *ledgerSeq - (ledgersPerShard * shardOffset) - - ledgersPerShard - 1; - BEAST_EXPECT( - arrInd >= 0 && arrInd < maxShardIndex * ledgersPerShard); - BEAST_EXPECT(saveLedger(shardStore, *data.ledgers_[arrInd])); - if (arrInd % ledgersPerShard == (ledgersPerShard - 1)) - { - uint256 const finalKey_{0}; - Serializer s; - s.add32(Shard::version); - s.add32(shardStore.firstLedgerSeq(shardIndex)); - s.add32(shardStore.lastLedgerSeq(shardIndex)); - s.addRaw(data.ledgers_[arrInd]->info().hash.data(), 256 / 8); - shardStore.store( - hotUNKNOWN, std::move(s.modData()), finalKey_, *ledgerSeq); - } - shardStore.setStored(data.ledgers_[arrInd]); - } - - return waitShard(shardStore, shardIndex); - } - - void - testStandalone() - { - testcase("Standalone"); - - using namespace test::jtx; - - beast::temp_dir shardDir; - DummyScheduler scheduler; - { - Env env{*this, testConfig(shardDir.path())}; - std::unique_ptr shardStore{ - make_ShardStore(env.app(), scheduler, 2, journal_)}; - - BEAST_EXPECT(shardStore); - BEAST_EXPECT(shardStore->init()); - BEAST_EXPECT(shardStore->ledgersPerShard() == ledgersPerShard); - BEAST_EXPECT(shardStore->seqToShardIndex(ledgersPerShard + 1) == 1); - BEAST_EXPECT(shardStore->seqToShardIndex(2 * ledgersPerShard) == 1); - BEAST_EXPECT( - shardStore->seqToShardIndex(2 * ledgersPerShard + 1) == 2); - BEAST_EXPECT( - shardStore->earliestShardIndex() == - (earliestSeq - 1) / ledgersPerShard); - BEAST_EXPECT(shardStore->firstLedgerSeq(1) == ledgersPerShard + 1); - BEAST_EXPECT(shardStore->lastLedgerSeq(1) == 2 * ledgersPerShard); - BEAST_EXPECT(shardStore->getRootDir().string() == shardDir.path()); - } - - { - Env env{*this, testConfig(shardDir.path())}; - std::unique_ptr shardStore{ - make_ShardStore(env.app(), scheduler, 2, journal_)}; - - env.app().config().overwrite( - ConfigSection::shardDatabase(), "ledgers_per_shard", "512"); - BEAST_EXPECT(!shardStore->init()); - } - - Env env{*this, testConfig(shardDir.path())}; - std::unique_ptr shardStore{ - make_ShardStore(env.app(), scheduler, 2, journal_)}; - - env.app().config().overwrite( - ConfigSection::shardDatabase(), - "earliest_seq", - std::to_string(std::numeric_limits::max())); - BEAST_EXPECT(!shardStore->init()); - } - - void - testCreateShard(std::uint64_t const seedValue) - { - testcase("Create shard"); - - using namespace test::jtx; - - beast::temp_dir shardDir; - Env env{*this, testConfig(shardDir.path())}; - DatabaseShard* db = env.app().getShardStore(); - BEAST_EXPECT(db); - - TestData data(seedValue); - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - if (!createShard(data, *db, 1)) - return; - - for (std::uint32_t i = 0; i < ledgersPerShard; ++i) - checkLedger(data, *db, *data.ledgers_[i]); - } - - void - testReopenDatabase(std::uint64_t const seedValue) - { - testcase("Reopen shard store"); - - using namespace test::jtx; - - beast::temp_dir shardDir; - { - Env env{*this, testConfig(shardDir.path())}; - DatabaseShard* db = env.app().getShardStore(); - BEAST_EXPECT(db); - - TestData data(seedValue, 4, 2); - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - for (auto i = 0; i < 2; ++i) - { - if (!createShard(data, *db, 2)) - return; - } - } - { - Env env{*this, testConfig(shardDir.path())}; - DatabaseShard* db = env.app().getShardStore(); - BEAST_EXPECT(db); - - TestData data(seedValue, 4, 2); - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - for (std::uint32_t i = 1; i <= 2; ++i) - waitShard(*db, i); - - for (std::uint32_t i = 0; i < 2 * ledgersPerShard; ++i) - checkLedger(data, *db, *data.ledgers_[i]); - } - } - - void - testGetFinalShards(std::uint64_t const seedValue) - { - testcase("Get final shards"); - - using namespace test::jtx; - - beast::temp_dir shardDir; - Env env{*this, testConfig(shardDir.path())}; - DatabaseShard* db = env.app().getShardStore(); - BEAST_EXPECT(db); - - TestData data(seedValue, 2, nTestShards); - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - BEAST_EXPECT(db->getShardInfo()->finalized().empty()); - - for (auto i = 0; i < nTestShards; ++i) - { - auto const shardIndex{createShard(data, *db, nTestShards)}; - if (!BEAST_EXPECT( - shardIndex && *shardIndex >= 1 && - *shardIndex <= nTestShards)) - { - return; - } - - BEAST_EXPECT(boost::icl::contains( - db->getShardInfo()->finalized(), *shardIndex)); - } - } - - void - testPrepareShards(std::uint64_t const seedValue) - { - testcase("Prepare shards"); - - using namespace test::jtx; - - beast::temp_dir shardDir; - Env env{*this, testConfig(shardDir.path())}; - DatabaseShard* db = env.app().getShardStore(); - BEAST_EXPECT(db); - - TestData data(seedValue, 1, nTestShards); - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - BEAST_EXPECT(db->getPreShards() == ""); - BEAST_EXPECT(!db->prepareShards({})); - - std::uint64_t bitMask = 0; - for (std::uint32_t i = 0; i < nTestShards * 2; ++i) - { - std::uint32_t const shardIndex{ - randInt(data.rng_, nTestShards - 1) + 1}; - if (bitMask & (1ll << shardIndex)) - { - db->removePreShard(shardIndex); - bitMask &= ~(1ll << shardIndex); - } - else - { - BEAST_EXPECT(db->prepareShards({shardIndex})); - bitMask |= 1ll << shardIndex; - } - BEAST_EXPECT(db->getPreShards() == bitmask2Rangeset(bitMask)); - } - - // test illegal cases - // adding shards with too large number - BEAST_EXPECT(!db->prepareShards({0})); - BEAST_EXPECT(db->getPreShards() == bitmask2Rangeset(bitMask)); - BEAST_EXPECT(!db->prepareShards({nTestShards + 1})); - BEAST_EXPECT(db->getPreShards() == bitmask2Rangeset(bitMask)); - BEAST_EXPECT(!db->prepareShards({nTestShards + 2})); - BEAST_EXPECT(db->getPreShards() == bitmask2Rangeset(bitMask)); - - // create shards which are not prepared for import - BEAST_EXPECT(db->getShardInfo()->finalized().empty()); - - std::uint64_t bitMask2 = 0; - for (auto i = 0; i < nTestShards; ++i) - { - auto const shardIndex{createShard(data, *db, nTestShards)}; - if (!BEAST_EXPECT( - shardIndex && *shardIndex >= 1 && - *shardIndex <= nTestShards)) - { - return; - } - - BEAST_EXPECT(boost::icl::contains( - db->getShardInfo()->finalized(), *shardIndex)); - - bitMask2 |= 1ll << *shardIndex; - BEAST_EXPECT((bitMask & bitMask2) == 0); - if ((bitMask | bitMask2) == ((1ll << nTestShards) - 1) << 1) - break; - } - - // try to create another shard - BEAST_EXPECT( - db->prepareLedger((nTestShards + 1) * ledgersPerShard) == - std::nullopt); - } - - void - testImportShard(std::uint64_t const seedValue) - { - testcase("Import shard"); - - using namespace test::jtx; - - beast::temp_dir importDir; - TestData data(seedValue, 2); - - { - Env env{*this, testConfig(importDir.path())}; - DatabaseShard* db = env.app().getShardStore(); - BEAST_EXPECT(db); - - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - if (!createShard(data, *db, 1)) - return; - - for (std::uint32_t i = 0; i < ledgersPerShard; ++i) - checkLedger(data, *db, *data.ledgers_[i]); - - data.ledgers_.clear(); - } - - boost::filesystem::path importPath(importDir.path()); - importPath /= "1"; - - { - beast::temp_dir shardDir; - Env env{*this, testConfig(shardDir.path())}; - DatabaseShard* db = env.app().getShardStore(); - BEAST_EXPECT(db); - - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - BEAST_EXPECT(!db->importShard(1, importPath / "not_exist")); - BEAST_EXPECT(db->prepareShards({1})); - BEAST_EXPECT(db->getPreShards() == "1"); - - using namespace boost::filesystem; - remove_all(importPath / LgrDBName); - remove_all(importPath / TxDBName); - - if (!BEAST_EXPECT(db->importShard(1, importPath))) - return; - - BEAST_EXPECT(db->getPreShards() == ""); - - auto n = waitShard(*db, 1); - if (!BEAST_EXPECT(n && *n == 1)) - return; - - for (std::uint32_t i = 0; i < ledgersPerShard; ++i) - checkLedger(data, *db, *data.ledgers_[i]); - } - } - - void - testCorruptedDatabase(std::uint64_t const seedValue) - { - testcase("Corrupted shard store"); - - using namespace test::jtx; - - beast::temp_dir shardDir; - { - TestData data(seedValue, 4, 2); - { - Env env{*this, testConfig(shardDir.path())}; - DatabaseShard* db = env.app().getShardStore(); - BEAST_EXPECT(db); - - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - for (auto i = 0; i < 2; ++i) - { - if (!BEAST_EXPECT(createShard(data, *db, 2))) - return; - } - } - - boost::filesystem::path path = shardDir.path(); - path /= std::string("2"); - path /= "nudb.dat"; - - FILE* f = fopen(path.string().c_str(), "r+b"); - if (!BEAST_EXPECT(f)) - return; - char buf[256]; - beast::rngfill(buf, sizeof(buf), data.rng_); - BEAST_EXPECT(fwrite(buf, 1, 256, f) == 256); - fclose(f); - } - - Env env{*this, testConfig(shardDir.path())}; - DatabaseShard* db = env.app().getShardStore(); - BEAST_EXPECT(db); - - TestData data(seedValue, 4, 2); - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - for (std::uint32_t shardIndex = 1; shardIndex <= 1; ++shardIndex) - waitShard(*db, shardIndex); - - BEAST_EXPECT(boost::icl::contains(db->getShardInfo()->finalized(), 1)); - - for (std::uint32_t i = 0; i < 1 * ledgersPerShard; ++i) - checkLedger(data, *db, *data.ledgers_[i]); - } - - void - testIllegalFinalKey(std::uint64_t const seedValue) - { - testcase("Illegal finalKey"); - - using namespace test::jtx; - - for (int i = 0; i < 5; ++i) - { - beast::temp_dir shardDir; - { - Env env{*this, testConfig(shardDir.path())}; - DatabaseShard* db = env.app().getShardStore(); - BEAST_EXPECT(db); - - TestData data(seedValue + i, 2); - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - int shardIndex{-1}; - for (std::uint32_t j = 0; j < ledgersPerShard; ++j) - { - auto const ledgerSeq{ - db->prepareLedger(2 * ledgersPerShard)}; - if (!BEAST_EXPECT(ledgerSeq != std::nullopt)) - return; - - shardIndex = db->seqToShardIndex(*ledgerSeq); - int arrInd = *ledgerSeq - ledgersPerShard - 1; - BEAST_EXPECT(arrInd >= 0 && arrInd < ledgersPerShard); - BEAST_EXPECT(saveLedger(*db, *data.ledgers_[arrInd])); - if (arrInd % ledgersPerShard == (ledgersPerShard - 1)) - { - uint256 const finalKey_{0}; - Serializer s; - s.add32(Shard::version + (i == 0)); - s.add32(db->firstLedgerSeq(shardIndex) + (i == 1)); - s.add32(db->lastLedgerSeq(shardIndex) - (i == 3)); - s.addRaw( - data.ledgers_[arrInd - (i == 4)] - ->info() - .hash.data(), - 256 / 8); - db->store( - hotUNKNOWN, - std::move(s.modData()), - finalKey_, - *ledgerSeq); - } - db->setStored(data.ledgers_[arrInd]); - } - - if (i == 2) - { - waitShard(*db, shardIndex); - BEAST_EXPECT(boost::icl::contains( - db->getShardInfo()->finalized(), 1)); - } - else - { - boost::filesystem::path path(shardDir.path()); - path /= "1"; - boost::system::error_code ec; - auto start = std::chrono::system_clock::now(); - auto end = start + shardStoreTimeout; - while (std::chrono::system_clock::now() < end && - boost::filesystem::exists(path, ec)) - { - std::this_thread::yield(); - } - - BEAST_EXPECT(db->getShardInfo()->finalized().empty()); - } - } - - { - Env env{*this, testConfig(shardDir.path())}; - DatabaseShard* db = env.app().getShardStore(); - BEAST_EXPECT(db); - - TestData data(seedValue + i, 2); - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - if (i == 2) - { - waitShard(*db, 1); - BEAST_EXPECT(boost::icl::contains( - db->getShardInfo()->finalized(), 1)); - - for (std::uint32_t j = 0; j < ledgersPerShard; ++j) - checkLedger(data, *db, *data.ledgers_[j]); - } - else - BEAST_EXPECT(db->getShardInfo()->finalized().empty()); - } - } - } - - std::string - ripemd160File(std::string filename) - { - using beast::hash_append; - std::ifstream input(filename, std::ios::in | std::ios::binary); - char buf[4096]; - ripemd160_hasher h; - - while (input.read(buf, 4096), input.gcount() > 0) - hash_append(h, buf, input.gcount()); - - auto const binResult = static_cast(h); - const auto charDigest = binResult.data(); - std::string result; - boost::algorithm::hex( - charDigest, - charDigest + sizeof(binResult), - std::back_inserter(result)); - - return result; - } - - void - testDeterministicShard(std::uint64_t const seedValue) - { - testcase("Deterministic shards"); - - using namespace test::jtx; - - for (int i = 0; i < 2; i++) - { - beast::temp_dir shardDir; - { - Env env{*this, testConfig(shardDir.path())}; - DatabaseShard* db = env.app().getShardStore(); - BEAST_EXPECT(db); - - TestData data(seedValue, 4); - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - if (!BEAST_EXPECT(createShard(data, *db) != std::nullopt)) - return; - } - - boost::filesystem::path path(shardDir.path()); - path /= "1"; - - auto static const ripemd160Key = - ripemd160File((path / "nudb.key").string()); - auto static const ripemd160Dat = - ripemd160File((path / "nudb.dat").string()); - - { - Env env{*this, testConfig(shardDir.path())}; - DatabaseShard* db = env.app().getShardStore(); - BEAST_EXPECT(db); - - TestData data(seedValue, 4); - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - if (!BEAST_EXPECT(waitShard(*db, 1) != std::nullopt)) - return; - - for (std::uint32_t j = 0; j < ledgersPerShard; ++j) - checkLedger(data, *db, *data.ledgers_[j]); - } - - BEAST_EXPECT( - ripemd160File((path / "nudb.key").string()) == ripemd160Key); - BEAST_EXPECT( - ripemd160File((path / "nudb.dat").string()) == ripemd160Dat); - } - } - - void - testImportNodeStore(std::uint64_t const seedValue) - { - testcase("Import node store"); - - using namespace test::jtx; - - beast::temp_dir shardDir; - { - beast::temp_dir nodeDir; - Env env{*this, testConfig(shardDir.path(), nodeDir.path())}; - DatabaseShard* db = env.app().getShardStore(); - Database& ndb = env.app().getNodeStore(); - BEAST_EXPECT(db); - - TestData data(seedValue, 4, 2); - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - for (std::uint32_t i = 0; i < 2 * ledgersPerShard; ++i) - BEAST_EXPECT(saveLedger(ndb, *data.ledgers_[i])); - - BEAST_EXPECT(db->getShardInfo()->finalized().empty()); - db->importDatabase(ndb); - for (std::uint32_t i = 1; i <= 2; ++i) - waitShard(*db, i); - - auto const finalShards{db->getShardInfo()->finalized()}; - for (std::uint32_t shardIndex : {1, 2}) - BEAST_EXPECT(boost::icl::contains(finalShards, shardIndex)); - } - { - Env env{*this, testConfig(shardDir.path())}; - DatabaseShard* db = env.app().getShardStore(); - BEAST_EXPECT(db); - - TestData data(seedValue, 4, 2); - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - for (std::uint32_t i = 1; i <= 2; ++i) - waitShard(*db, i); - - auto const finalShards{db->getShardInfo()->finalized()}; - for (std::uint32_t shardIndex : {1, 2}) - BEAST_EXPECT(boost::icl::contains(finalShards, shardIndex)); - - for (std::uint32_t i = 0; i < 2 * ledgersPerShard; ++i) - checkLedger(data, *db, *data.ledgers_[i]); - } - } - - void - testImportWithOnlineDelete(std::uint64_t const seedValue) - { - testcase("Import node store with online delete"); - - using namespace test::jtx; - using test::CaptureLogs; - - beast::temp_dir shardDir; - beast::temp_dir nodeDir; - std::string capturedLogs; - - { - auto c = testConfig(shardDir.path(), nodeDir.path()); - auto& section = c->section(ConfigSection::nodeDatabase()); - section.set("online_delete", "550"); - section.set("advisory_delete", "1"); - - // Adjust the log level to capture relevant output - c->section(SECTION_RPC_STARTUP) - .append( - "{ \"command\": \"log_level\", \"severity\": \"trace\" " - "}"); - - std::unique_ptr logs(new CaptureLogs(&capturedLogs)); - Env env{*this, std::move(c), std::move(logs)}; - - DatabaseShard* db = env.app().getShardStore(); - Database& ndb = env.app().getNodeStore(); - BEAST_EXPECT(db); - - auto& store = env.app().getSHAMapStore(); - - // Allow online delete to delete the startup ledgers - // so that it will take some time for the import to - // catch up to the point of the next rotation - store.setCanDelete(10); - - // Create some ledgers for the shard store to import - auto const shardCount = 5; - TestData data(seedValue, 4, shardCount); - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - store.rendezvous(); - auto const lastRotated = store.getLastRotated(); - BEAST_EXPECT(lastRotated >= 553 && lastRotated < 1103); - - // Start the import - db->importDatabase(ndb); - - while (!db->getDatabaseImportSequence()) - { - // Wait until the import starts - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - - // Enable unimpeded online deletion now that the import has started - store.setCanDelete(std::numeric_limits::max()); - - auto pauseVerifier = std::thread([lastRotated, &store, db, this] { - // The import should still be running when this thread starts - BEAST_EXPECT(db->getDatabaseImportSequence()); - auto rotationProgress = lastRotated; - while (auto const ledgerSeq = db->getDatabaseImportSequence()) - { - // Make sure database rotations dont interfere - // with the import - - auto const last = store.getLastRotated(); - if (last != rotationProgress) - { - // A rotation occurred during shard import. Not - // necessarily an error - - BEAST_EXPECT( - !ledgerSeq || ledgerSeq >= rotationProgress); - rotationProgress = last; - } - } - }); - - auto join = [&pauseVerifier]() { - if (pauseVerifier.joinable()) - pauseVerifier.join(); - }; - - // Create more ledgers to trigger online deletion - data = TestData(seedValue * 2); - if (!BEAST_EXPECT(data.makeLedgers(env, shardCount))) - { - join(); - return; - } - - join(); - BEAST_EXPECT(store.getLastRotated() != lastRotated); - } - - // Database rotation should have been postponed at some - // point during the import - auto const expectedLogMessage = - "rotation would interfere with ShardStore import"; - BEAST_EXPECT( - capturedLogs.find(expectedLogMessage) != std::string::npos); - } - - void - testImportWithHistoricalPaths(std::uint64_t const seedValue) - { - testcase("Import with historical paths"); - - using namespace test::jtx; - - // Test importing with multiple historical paths - { - beast::temp_dir shardDir; - std::array historicalDirs; - std::array historicalPaths; - - std::transform( - historicalDirs.begin(), - historicalDirs.end(), - historicalPaths.begin(), - [](const beast::temp_dir& dir) { return dir.path(); }); - - beast::temp_dir nodeDir; - auto c = testConfig(shardDir.path(), nodeDir.path()); - - auto& historyPaths = c->section(SECTION_HISTORICAL_SHARD_PATHS); - historyPaths.append( - {historicalPaths[0].string(), - historicalPaths[1].string(), - historicalPaths[2].string(), - historicalPaths[3].string()}); - - Env env{*this, std::move(c)}; - DatabaseShard* db = env.app().getShardStore(); - Database& ndb = env.app().getNodeStore(); - BEAST_EXPECT(db); - - auto const shardCount = 4; - - TestData data(seedValue, 4, shardCount); - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - for (std::uint32_t i = 0; i < shardCount * ledgersPerShard; ++i) - BEAST_EXPECT(saveLedger(ndb, *data.ledgers_[i])); - - BEAST_EXPECT(db->getShardInfo()->finalized().empty()); - - db->importDatabase(ndb); - for (std::uint32_t i = 1; i <= shardCount; ++i) - waitShard(*db, i); - - auto const final{db->getShardInfo()->finalized()}; - for (std::uint32_t shardIndex : {1, 2, 3, 4}) - BEAST_EXPECT(boost::icl::contains(final, shardIndex)); - - auto const mainPathCount = std::distance( - boost::filesystem::directory_iterator(shardDir.path()), - boost::filesystem::directory_iterator()); - - // Only the two most recent shards - // should be stored at the main path - BEAST_EXPECT(mainPathCount == 2); - - auto const historicalPathCount = std::accumulate( - historicalPaths.begin(), - historicalPaths.end(), - 0, - [](int const sum, boost::filesystem::path const& path) { - return sum + - std::distance( - boost::filesystem::directory_iterator(path), - boost::filesystem::directory_iterator()); - }); - - // All historical shards should be stored - // at historical paths - BEAST_EXPECT(historicalPathCount == shardCount - 2); - } - - // Test importing with a single historical path - { - beast::temp_dir shardDir; - beast::temp_dir historicalDir; - beast::temp_dir nodeDir; - - auto c = testConfig(shardDir.path(), nodeDir.path()); - - auto& historyPaths = c->section(SECTION_HISTORICAL_SHARD_PATHS); - historyPaths.append({historicalDir.path()}); - - Env env{*this, std::move(c)}; - DatabaseShard* db = env.app().getShardStore(); - Database& ndb = env.app().getNodeStore(); - BEAST_EXPECT(db); - - auto const shardCount = 4; - - TestData data(seedValue * 2, 4, shardCount); - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - for (std::uint32_t i = 0; i < shardCount * ledgersPerShard; ++i) - BEAST_EXPECT(saveLedger(ndb, *data.ledgers_[i])); - - BEAST_EXPECT(db->getShardInfo()->finalized().empty()); - - db->importDatabase(ndb); - for (std::uint32_t i = 1; i <= shardCount; ++i) - waitShard(*db, i); - - auto const finalShards{db->getShardInfo()->finalized()}; - for (std::uint32_t shardIndex : {1, 2, 3, 4}) - BEAST_EXPECT(boost::icl::contains(finalShards, shardIndex)); - - auto const mainPathCount = std::distance( - boost::filesystem::directory_iterator(shardDir.path()), - boost::filesystem::directory_iterator()); - - // Only the two most recent shards - // should be stored at the main path - BEAST_EXPECT(mainPathCount == 2); - - auto const historicalPathCount = std::distance( - boost::filesystem::directory_iterator(historicalDir.path()), - boost::filesystem::directory_iterator()); - - // All historical shards should be stored - // at historical paths - BEAST_EXPECT(historicalPathCount == shardCount - 2); - } - } - - void - testPrepareWithHistoricalPaths(std::uint64_t const seedValue) - { - testcase("Prepare with historical paths"); - - using namespace test::jtx; - - // Create the primary shard directory - beast::temp_dir primaryDir; - auto config{testConfig(primaryDir.path())}; - - // Create four historical directories - std::array historicalDirs; - { - auto& paths{config->section(SECTION_HISTORICAL_SHARD_PATHS)}; - for (auto const& dir : historicalDirs) - paths.append(dir.path()); - } - - Env env{*this, std::move(config)}; - - // Create some shards - std::uint32_t constexpr numShards{4}; - TestData data(seedValue, 4, numShards); - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - auto shardStore{env.app().getShardStore()}; - BEAST_EXPECT(shardStore); - - for (auto i = 0; i < numShards; ++i) - { - auto const shardIndex{createShard(data, *shardStore, numShards)}; - if (!BEAST_EXPECT( - shardIndex && *shardIndex >= 1 && *shardIndex <= numShards)) - { - return; - } - } - - { - // Confirm finalized shards are in the shard store - auto const finalized{shardStore->getShardInfo()->finalized()}; - BEAST_EXPECT(boost::icl::length(finalized) == numShards); - BEAST_EXPECT(boost::icl::first(finalized) == 1); - BEAST_EXPECT(boost::icl::last(finalized) == numShards); - } - - using namespace boost::filesystem; - auto const dirContains = [](beast::temp_dir const& dir, - std::uint32_t shardIndex) { - boost::filesystem::path const path(std::to_string(shardIndex)); - for (auto const& it : directory_iterator(dir.path())) - if (boost::filesystem::path(it).stem() == path) - return true; - return false; - }; - auto const historicalDirsContains = [&](std::uint32_t shardIndex) { - for (auto const& dir : historicalDirs) - if (dirContains(dir, shardIndex)) - return true; - return false; - }; - - // Confirm two most recent shards are in the primary shard directory - for (auto const shardIndex : {numShards - 1, numShards}) - { - BEAST_EXPECT(dirContains(primaryDir, shardIndex)); - BEAST_EXPECT(!historicalDirsContains(shardIndex)); - } - - // Confirm remaining shards are in the historical shard directories - for (auto shardIndex = 1; shardIndex < numShards - 1; ++shardIndex) - { - BEAST_EXPECT(!dirContains(primaryDir, shardIndex)); - BEAST_EXPECT(historicalDirsContains(shardIndex)); - } - - // Create some more shards to exercise recent shard rotation - data = TestData(seedValue * 2, 4, numShards); - if (!BEAST_EXPECT(data.makeLedgers(env, numShards))) - return; - - for (auto i = 0; i < numShards; ++i) - { - auto const shardIndex{ - createShard(data, *shardStore, numShards * 2, numShards)}; - if (!BEAST_EXPECT( - shardIndex && *shardIndex >= numShards + 1 && - *shardIndex <= numShards * 2)) - { - return; - } - } - - { - // Confirm finalized shards are in the shard store - auto const finalized{shardStore->getShardInfo()->finalized()}; - BEAST_EXPECT(boost::icl::length(finalized) == numShards * 2); - BEAST_EXPECT(boost::icl::first(finalized) == 1); - BEAST_EXPECT(boost::icl::last(finalized) == numShards * 2); - } - - // Confirm two most recent shards are in the primary shard directory - for (auto const shardIndex : {numShards * 2 - 1, numShards * 2}) - { - BEAST_EXPECT(dirContains(primaryDir, shardIndex)); - BEAST_EXPECT(!historicalDirsContains(shardIndex)); - } - - // Confirm remaining shards are in the historical shard directories - for (auto shardIndex = 1; shardIndex < numShards * 2 - 1; ++shardIndex) - { - BEAST_EXPECT(!dirContains(primaryDir, shardIndex)); - BEAST_EXPECT(historicalDirsContains(shardIndex)); - } - } - - void - testOpenShardManagement(std::uint64_t const seedValue) - { - testcase("Open shard management"); - - using namespace test::jtx; - - beast::temp_dir shardDir; - Env env{*this, testConfig(shardDir.path())}; - - auto shardStore{env.app().getShardStore()}; - BEAST_EXPECT(shardStore); - - // Create one shard more than the open final limit - auto const openFinalLimit{env.app().config().getValueFor( - SizedItem::openFinalLimit, std::nullopt)}; - auto const numShards{openFinalLimit + 1}; - - TestData data(seedValue, 2, numShards); - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - BEAST_EXPECT(shardStore->getShardInfo()->finalized().empty()); - - int oldestShardIndex{-1}; - for (auto i = 0; i < numShards; ++i) - { - auto shardIndex{createShard(data, *shardStore, numShards)}; - if (!BEAST_EXPECT( - shardIndex && *shardIndex >= 1 && *shardIndex <= numShards)) - { - return; - } - - BEAST_EXPECT(boost::icl::contains( - shardStore->getShardInfo()->finalized(), *shardIndex)); - - if (oldestShardIndex == -1) - oldestShardIndex = *shardIndex; - } - - // The number of open shards exceeds the open limit by one. - // A sweep will close enough shards to be within the limit. - shardStore->sweep(); - - // Read from the closed shard and automatically open it - auto const ledgerSeq{shardStore->lastLedgerSeq(oldestShardIndex)}; - auto const index{ledgerSeq - ledgersPerShard - 1}; - BEAST_EXPECT(shardStore->fetchNodeObject( - data.ledgers_[index]->info().hash, ledgerSeq)); - } - - void - testShardInfo(std::uint64_t const seedValue) - { - testcase("Shard info"); - - using namespace test::jtx; - beast::temp_dir shardDir; - Env env{*this, testConfig(shardDir.path())}; - - auto shardStore{env.app().getShardStore()}; - BEAST_EXPECT(shardStore); - - // Check shard store is empty - { - auto const shardInfo{shardStore->getShardInfo()}; - BEAST_EXPECT( - shardInfo->msgTimestamp().time_since_epoch().count() == 0); - BEAST_EXPECT(shardInfo->finalizedToString().empty()); - BEAST_EXPECT(shardInfo->finalized().empty()); - BEAST_EXPECT(shardInfo->incompleteToString().empty()); - BEAST_EXPECT(shardInfo->incomplete().empty()); - } - - // Create an incomplete shard with index 1 - TestData data(seedValue, dataSizeMax, 2); - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - if (!BEAST_EXPECT(shardStore->prepareLedger(2 * ledgersPerShard))) - return; - - // Check shard is incomplete - { - auto const shardInfo{shardStore->getShardInfo()}; - BEAST_EXPECT(shardInfo->finalizedToString().empty()); - BEAST_EXPECT(shardInfo->finalized().empty()); - BEAST_EXPECT(shardInfo->incompleteToString() == "1:0"); - BEAST_EXPECT( - shardInfo->incomplete().find(1) != - shardInfo->incomplete().end()); - } - - // Finalize the shard - { - auto shardIndex{createShard(data, *shardStore)}; - if (!BEAST_EXPECT(shardIndex && *shardIndex == 1)) - return; - } - - // Check shard is finalized - { - auto const shardInfo{shardStore->getShardInfo()}; - BEAST_EXPECT(shardInfo->finalizedToString() == "1"); - BEAST_EXPECT(boost::icl::contains(shardInfo->finalized(), 1)); - BEAST_EXPECT(shardInfo->incompleteToString().empty()); - BEAST_EXPECT(shardInfo->incomplete().empty()); - BEAST_EXPECT(!shardInfo->update(1, ShardState::finalized, 0)); - BEAST_EXPECT(shardInfo->setFinalizedFromString("2")); - BEAST_EXPECT(shardInfo->finalizedToString() == "2"); - BEAST_EXPECT(boost::icl::contains(shardInfo->finalized(), 2)); - } - - // Create an incomplete shard with index 2 - if (!BEAST_EXPECT(shardStore->prepareLedger(3 * ledgersPerShard))) - return; - - // Store 10 percent of the ledgers - for (std::uint32_t i = 0; i < (ledgersPerShard / 10); ++i) - { - auto const ledgerSeq{ - shardStore->prepareLedger(3 * ledgersPerShard)}; - if (!BEAST_EXPECT(ledgerSeq != std::nullopt)) - return; - - auto const arrInd{*ledgerSeq - ledgersPerShard - 1}; - if (!BEAST_EXPECT(saveLedger(*shardStore, *data.ledgers_[arrInd]))) - return; - - shardStore->setStored(data.ledgers_[arrInd]); - } - - auto const shardInfo{shardStore->getShardInfo()}; - BEAST_EXPECT(shardInfo->incompleteToString() == "2:10"); - BEAST_EXPECT( - shardInfo->incomplete().find(2) != shardInfo->incomplete().end()); - - auto const timeStamp{env.app().timeKeeper().now()}; - shardInfo->setMsgTimestamp(timeStamp); - BEAST_EXPECT(timeStamp == shardInfo->msgTimestamp()); - - // Check message - auto const msg{shardInfo->makeMessage(env.app())}; - Serializer s; - s.add32(HashPrefix::shardInfo); - - BEAST_EXPECT(msg.timestamp() != 0); - s.add32(msg.timestamp()); - - // Verify incomplete shard - { - BEAST_EXPECT(msg.incomplete_size() == 1); - - auto const& incomplete{msg.incomplete(0)}; - BEAST_EXPECT(incomplete.shardindex() == 2); - s.add32(incomplete.shardindex()); - - BEAST_EXPECT( - static_cast(incomplete.state()) == - ShardState::acquire); - s.add32(incomplete.state()); - - BEAST_EXPECT(incomplete.has_progress()); - BEAST_EXPECT(incomplete.progress() == 10); - s.add32(incomplete.progress()); - } - - // Verify finalized shard - BEAST_EXPECT(msg.has_finalized()); - BEAST_EXPECT(msg.finalized() == "1"); - s.addRaw(msg.finalized().data(), msg.finalized().size()); - - // Verify public key - auto slice{makeSlice(msg.publickey())}; - BEAST_EXPECT(publicKeyType(slice)); - - // Verify signature - BEAST_EXPECT(verify( - PublicKey(slice), s.slice(), makeSlice(msg.signature()), false)); - - BEAST_EXPECT(msg.peerchain_size() == 0); - } - - void - testSQLiteDatabase(std::uint64_t const seedValue) - { - testcase("SQLite Database"); - - using namespace test::jtx; - - beast::temp_dir shardDir; - Env env{*this, testConfig(shardDir.path())}; - - auto shardStore{env.app().getShardStore()}; - BEAST_EXPECT(shardStore); - - auto const shardCount = 3; - TestData data(seedValue, 3, shardCount); - if (!BEAST_EXPECT(data.makeLedgers(env))) - return; - - BEAST_EXPECT(shardStore->getShardInfo()->finalized().empty()); - BEAST_EXPECT(shardStore->getShardInfo()->incompleteToString().empty()); - - auto rdb = - dynamic_cast(&env.app().getRelationalDatabase()); - - BEAST_EXPECT(rdb); - - for (std::uint32_t i = 0; i < shardCount; ++i) - { - // Populate the shard store - - auto n = createShard(data, *shardStore, shardCount); - if (!BEAST_EXPECT(n && *n >= 1 && *n <= shardCount)) - return; - } - - // Close these databases to force the SQLiteDatabase - // to use the shard databases and lookup tables. - rdb->closeLedgerDB(); - rdb->closeTransactionDB(); - - // Lambda for comparing Ledger objects - auto infoCmp = [](auto const& a, auto const& b) { - return a.hash == b.hash && a.txHash == b.txHash && - a.accountHash == b.accountHash && - a.parentHash == b.parentHash && a.drops == b.drops && - a.accepted == b.accepted && a.closeFlags == b.closeFlags && - a.closeTimeResolution == b.closeTimeResolution && - a.closeTime == b.closeTime; - }; - - for (auto const& ledger : data.ledgers_) - { - // Compare each test ledger to the data retrieved - // from the SQLiteDatabase class - - if (shardStore->seqToShardIndex(ledger->seq()) < - shardStore->earliestShardIndex() || - ledger->info().seq < shardStore->earliestLedgerSeq()) - continue; - - auto info = rdb->getLedgerInfoByHash(ledger->info().hash); - - BEAST_EXPECT(info); - BEAST_EXPECT(infoCmp(*info, ledger->info())); - - for (auto const& transaction : ledger->txs) - { - // Compare each test transaction to the data - // retrieved from the SQLiteDatabase class - - error_code_i error{rpcSUCCESS}; - - auto reference = rdb->getTransaction( - transaction.first->getTransactionID(), {}, error); - - BEAST_EXPECT(error == rpcSUCCESS); - if (!BEAST_EXPECT(reference.index() == 0)) - continue; - - auto txn = std::get<0>(reference).first->getSTransaction(); - - BEAST_EXPECT( - transaction.first->getFullText() == txn->getFullText()); - } - } - - // Create additional ledgers to test a pathway in - // 'ripple::saveLedgerMeta' wherein fetching the - // accepted ledger fails - data = TestData(seedValue * 2, 4, 1); - if (!BEAST_EXPECT(data.makeLedgers(env, shardCount))) - return; - } - -public: - DatabaseShard_test() : journal_("DatabaseShard_test", *this) - { - } - - void - run() override - { - auto seedValue = [] { - static std::uint64_t seedValue = 41; - seedValue += 10; - return seedValue; - }; - - testStandalone(); - testCreateShard(seedValue()); - testReopenDatabase(seedValue()); - testGetFinalShards(seedValue()); - testPrepareShards(seedValue()); - testImportShard(seedValue()); - testCorruptedDatabase(seedValue()); - testIllegalFinalKey(seedValue()); - testDeterministicShard(seedValue()); - testImportNodeStore(seedValue()); - testImportWithOnlineDelete(seedValue()); - testImportWithHistoricalPaths(seedValue()); - testPrepareWithHistoricalPaths(seedValue()); - testOpenShardManagement(seedValue()); - testShardInfo(seedValue()); - testSQLiteDatabase(seedValue()); - } -}; - -BEAST_DEFINE_TESTSUITE_MANUAL(DatabaseShard, NodeStore, ripple); - -} // namespace NodeStore -} // namespace ripple diff --git a/src/test/nodestore/Database_test.cpp b/src/test/nodestore/Database_test.cpp index 6774857dfc6..d866247da89 100644 --- a/src/test/nodestore/Database_test.cpp +++ b/src/test/nodestore/Database_test.cpp @@ -616,37 +616,6 @@ class Database_test : public TestBase std::strcmp(e.what(), "earliest_seq set more than once") == 0); } - - // Verify default ledgers per shard - { - std::unique_ptr db = - Manager::instance().make_Database( - megabytes(4), scheduler, 2, nodeParams, journal_); - BEAST_EXPECT( - db->ledgersPerShard() == DEFAULT_LEDGERS_PER_SHARD); - } - - // Set an invalid ledgers per shard - try - { - nodeParams.set("ledgers_per_shard", "100"); - std::unique_ptr db = - Manager::instance().make_Database( - megabytes(4), scheduler, 2, nodeParams, journal_); - } - catch (std::runtime_error const& e) - { - BEAST_EXPECT( - std::strcmp(e.what(), "Invalid ledgers_per_shard") == 0); - } - - // Set a valid ledgers per shard - nodeParams.set("ledgers_per_shard", "256"); - std::unique_ptr db = Manager::instance().make_Database( - megabytes(4), scheduler, 2, nodeParams, journal_); - - // Verify database uses the ledgers per shard - BEAST_EXPECT(db->ledgersPerShard() == 256); } } diff --git a/src/test/rpc/NodeToShardRPC_test.cpp b/src/test/rpc/NodeToShardRPC_test.cpp deleted file mode 100644 index ec1ff367c1e..00000000000 --- a/src/test/rpc/NodeToShardRPC_test.cpp +++ /dev/null @@ -1,414 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 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 -#include -#include -#include -#include -#include -#include - -namespace ripple { -namespace test { - -class NodeToShardRPC_test : public beast::unit_test::suite -{ - bool - importCompleted( - NodeStore::DatabaseShard* shardStore, - std::uint8_t const numberOfShards, - Json::Value const& result) - { - auto const info = shardStore->getShardInfo(); - - // Assume completed if the import isn't running - auto const completed = - result[jss::error_message] == "Database import not running"; - - if (completed) - { - BEAST_EXPECT( - info->incomplete().size() + info->finalized().size() == - numberOfShards); - } - - return completed; - } - -public: - void - testDisabled() - { - testcase("Disabled"); - - beast::temp_dir tempDir; - - jtx::Env env = [&] { - auto c = jtx::envconfig(); - auto& sectionNode = c->section(ConfigSection::nodeDatabase()); - sectionNode.set("earliest_seq", "257"); - sectionNode.set("ledgers_per_shard", "256"); - c->setupControl(true, true, true); - - return jtx::Env(*this, std::move(c)); - }(); - - std::uint8_t const numberOfShards = 10; - - // Create some ledgers so that we can initiate a - // shard store database import. - for (int i = 0; i < 256 * (numberOfShards + 1); ++i) - { - env.close(); - } - - { - auto shardStore = env.app().getShardStore(); - if (!BEAST_EXPECT(!shardStore)) - return; - } - - { - // Try the node_to_shard status RPC command. Should fail. - - Json::Value jvParams; - jvParams[jss::action] = "status"; - - auto const result = env.rpc( - "json", "node_to_shard", to_string(jvParams))[jss::result]; - - BEAST_EXPECT(result[jss::error_code] == rpcNOT_ENABLED); - } - - { - // Try to start a shard store import via the RPC - // interface. Should fail. - - Json::Value jvParams; - jvParams[jss::action] = "start"; - - auto const result = env.rpc( - "json", "node_to_shard", to_string(jvParams))[jss::result]; - - BEAST_EXPECT(result[jss::error_code] == rpcNOT_ENABLED); - } - - { - // Try the node_to_shard status RPC command. Should fail. - - Json::Value jvParams; - jvParams[jss::action] = "status"; - - auto const result = env.rpc( - "json", "node_to_shard", to_string(jvParams))[jss::result]; - - BEAST_EXPECT(result[jss::error_code] == rpcNOT_ENABLED); - } - } - - void - testStart() - { - testcase("Start"); - - beast::temp_dir tempDir; - - jtx::Env env = [&] { - auto c = jtx::envconfig(); - auto& section = c->section(ConfigSection::shardDatabase()); - section.set("path", tempDir.path()); - section.set("max_historical_shards", "20"); - section.set("ledgers_per_shard", "256"); - section.set("earliest_seq", "257"); - auto& sectionNode = c->section(ConfigSection::nodeDatabase()); - sectionNode.set("earliest_seq", "257"); - sectionNode.set("ledgers_per_shard", "256"); - c->setupControl(true, true, true); - - return jtx::Env(*this, std::move(c)); - }(); - - std::uint8_t const numberOfShards = 10; - - // Create some ledgers so that we can initiate a - // shard store database import. - for (int i = 0; i < env.app().getShardStore()->ledgersPerShard() * - (numberOfShards + 1); - ++i) - { - env.close(); - } - - auto shardStore = env.app().getShardStore(); - if (!BEAST_EXPECT(shardStore)) - return; - - { - // Initiate a shard store import via the RPC - // interface. - - Json::Value jvParams; - jvParams[jss::action] = "start"; - - auto const result = env.rpc( - "json", "node_to_shard", to_string(jvParams))[jss::result]; - - BEAST_EXPECT( - result[jss::message] == "Database import initiated..."); - } - - while (!shardStore->getDatabaseImportSequence()) - { - // Wait until the import starts - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - - { - // Verify that the import is in progress with - // the node_to_shard status RPC command - - Json::Value jvParams; - jvParams[jss::action] = "status"; - - auto const result = env.rpc( - "json", "node_to_shard", to_string(jvParams))[jss::result]; - - BEAST_EXPECT( - result[jss::status] == "success" || - importCompleted(shardStore, numberOfShards, result)); - - std::chrono::seconds const maxWait{180}; - - { - auto const start = std::chrono::system_clock::now(); - while (true) - { - // Verify that the status object accurately - // reflects import progress. - - auto const completeShards = - shardStore->getShardInfo()->finalized(); - - if (!completeShards.empty()) - { - auto const result = env.rpc( - "json", - "node_to_shard", - to_string(jvParams))[jss::result]; - - if (!importCompleted( - shardStore, numberOfShards, result)) - { - BEAST_EXPECT(result[jss::firstShardIndex] == 1); - BEAST_EXPECT(result[jss::lastShardIndex] == 10); - } - } - - if (boost::icl::contains(completeShards, 1)) - { - auto const result = env.rpc( - "json", - "node_to_shard", - to_string(jvParams))[jss::result]; - - BEAST_EXPECT( - result[jss::currentShardIndex] >= 1 || - importCompleted( - shardStore, numberOfShards, result)); - - break; - } - - if (std::this_thread::sleep_for( - std::chrono::milliseconds{100}); - std::chrono::system_clock::now() - start > maxWait) - { - BEAST_EXPECTS( - false, - "Import timeout: could just be a slow machine."); - break; - } - } - } - - { - // Wait for the import to complete - auto const start = std::chrono::system_clock::now(); - while (!boost::icl::contains( - shardStore->getShardInfo()->finalized(), 10)) - { - if (std::this_thread::sleep_for( - std::chrono::milliseconds{100}); - std::chrono::system_clock::now() - start > maxWait) - { - BEAST_EXPECT(importCompleted( - shardStore, numberOfShards, result)); - break; - } - } - } - } - } - - void - testStop() - { - testcase("Stop"); - - beast::temp_dir tempDir; - - jtx::Env env = [&] { - auto c = jtx::envconfig(); - auto& section = c->section(ConfigSection::shardDatabase()); - section.set("path", tempDir.path()); - section.set("max_historical_shards", "20"); - section.set("ledgers_per_shard", "256"); - section.set("earliest_seq", "257"); - auto& sectionNode = c->section(ConfigSection::nodeDatabase()); - sectionNode.set("earliest_seq", "257"); - sectionNode.set("ledgers_per_shard", "256"); - c->setupControl(true, true, true); - - return jtx::Env( - *this, std::move(c), nullptr, beast::severities::kDisabled); - }(); - - std::uint8_t const numberOfShards = 10; - - // Create some ledgers so that we can initiate a - // shard store database import. - for (int i = 0; i < env.app().getShardStore()->ledgersPerShard() * - (numberOfShards + 1); - ++i) - { - env.close(); - } - - auto shardStore = env.app().getShardStore(); - if (!BEAST_EXPECT(shardStore)) - return; - - { - // Initiate a shard store import via the RPC - // interface. - - Json::Value jvParams; - jvParams[jss::action] = "start"; - - auto const result = env.rpc( - "json", "node_to_shard", to_string(jvParams))[jss::result]; - - BEAST_EXPECT( - result[jss::message] == "Database import initiated..."); - } - - { - // Verify that the import is in progress with - // the node_to_shard status RPC command - - Json::Value jvParams; - jvParams[jss::action] = "status"; - - auto const result = env.rpc( - "json", "node_to_shard", to_string(jvParams))[jss::result]; - - BEAST_EXPECT( - result[jss::status] == "success" || - importCompleted(shardStore, numberOfShards, result)); - - std::chrono::seconds const maxWait{30}; - auto const start = std::chrono::system_clock::now(); - - while (shardStore->getShardInfo()->finalized().empty()) - { - // Wait for at least one shard to complete - - if (std::this_thread::sleep_for(std::chrono::milliseconds{100}); - std::chrono::system_clock::now() - start > maxWait) - { - BEAST_EXPECTS( - false, "Import timeout: could just be a slow machine."); - break; - } - } - } - - { - Json::Value jvParams; - jvParams[jss::action] = "stop"; - - auto const result = env.rpc( - "json", "node_to_shard", to_string(jvParams))[jss::result]; - - BEAST_EXPECT( - result[jss::message] == "Database import halt initiated..." || - importCompleted(shardStore, numberOfShards, result)); - } - - std::chrono::seconds const maxWait{30}; - auto const start = std::chrono::system_clock::now(); - - while (true) - { - // Wait until we can verify that the import has - // stopped - - Json::Value jvParams; - jvParams[jss::action] = "status"; - - auto const result = env.rpc( - "json", "node_to_shard", to_string(jvParams))[jss::result]; - - // When the import has stopped, polling the - // status returns an error - if (result.isMember(jss::error)) - { - if (BEAST_EXPECT(result.isMember(jss::error_message))) - { - BEAST_EXPECT( - result[jss::error_message] == - "Database import not running"); - } - - break; - } - - if (std::this_thread::sleep_for(std::chrono::milliseconds{100}); - std::chrono::system_clock::now() - start > maxWait) - { - BEAST_EXPECTS( - false, "Import timeout: could just be a slow machine."); - break; - } - } - } - - void - run() override - { - testDisabled(); - testStart(); - testStop(); - } -}; - -BEAST_DEFINE_TESTSUITE_MANUAL(NodeToShardRPC, rpc, ripple); -} // namespace test -} // namespace ripple diff --git a/src/test/rpc/RPCCall_test.cpp b/src/test/rpc/RPCCall_test.cpp index f3aaf468a9e..5f13c9799a1 100644 --- a/src/test/rpc/RPCCall_test.cpp +++ b/src/test/rpc/RPCCall_test.cpp @@ -2545,231 +2545,6 @@ static RPCCallTestData const rpcCallTestArray[] = { ] })"}, - // download_shard - // -------------------------------------------------------------- - {"download_shard: minimal.", - __LINE__, - { - "download_shard", - "20", - "url_NotValidated", - }, - RPCCallTestData::no_exception, - R"({ - "method" : "download_shard", - "params" : [ - { - "api_version" : %API_VER%, - "shards" : [ - { - "index" : 20, - "url" : "url_NotValidated" - } - ] - } - ] - })"}, - {"download_shard:", - __LINE__, - { - "download_shard", - "20", - "url_NotValidated", - }, - RPCCallTestData::no_exception, - R"({ - "method" : "download_shard", - "params" : [ - { - "api_version" : %API_VER%, - "shards" : [ - { - "index" : 20, - "url" : "url_NotValidated" - } - ] - } - ] - })"}, - {"download_shard: many shards.", - __LINE__, - { - "download_shard", - "200000000", - "url_NotValidated0", - "199999999", - "url_NotValidated1", - "199999998", - "url_NotValidated2", - "199999997", - "url_NotValidated3", - }, - RPCCallTestData::no_exception, - R"({ - "method" : "download_shard", - "params" : [ - { - "api_version" : %API_VER%, - "shards" : [ - { - "index" : 200000000, - "url" : "url_NotValidated0" - }, - { - "index" : 199999999, - "url" : "url_NotValidated1" - }, - { - "index" : 199999998, - "url" : "url_NotValidated2" - }, - { - "index" : 199999997, - "url" : "url_NotValidated3" - } - ] - } - ] - })"}, - {"download_shard: many shards.", - __LINE__, - { - "download_shard", - "2000000", - "url_NotValidated0", - "2000001", - "url_NotValidated1", - "2000002", - "url_NotValidated2", - "2000003", - "url_NotValidated3", - "2000004", - "url_NotValidated4", - }, - RPCCallTestData::no_exception, - R"({ - "method" : "download_shard", - "params" : [ - { - "api_version" : %API_VER%, - "shards" : [ - { - "index" : 2000000, - "url" : "url_NotValidated0" - }, - { - "index" : 2000001, - "url" : "url_NotValidated1" - }, - { - "index" : 2000002, - "url" : "url_NotValidated2" - }, - { - "index" : 2000003, - "url" : "url_NotValidated3" - }, - { - "index" : 2000004, - "url" : "url_NotValidated4" - } - ] - } - ] - })"}, - {"download_shard: too few arguments.", - __LINE__, - {"download_shard", "20"}, - RPCCallTestData::no_exception, - R"({ - "method" : "download_shard", - "params" : [ - { - "error" : "badSyntax", - "error_code" : 1, - "error_message" : "Syntax error." - } - ] - })"}, - {// Note: this should return an error but not throw. - "download_shard: novalidate too few arguments.", - __LINE__, - {"download_shard", "novalidate", "20"}, - RPCCallTestData::bad_cast, - R"()"}, - {"download_shard: novalidate at end.", - __LINE__, - { - "download_shard", - "20", - "url_NotValidated", - "novalidate", - }, - RPCCallTestData::no_exception, - R"({ - "method" : "download_shard", - "params" : [ - { - "api_version" : %API_VER%, - "shards" : [ - { - "index" : 20, - "url" : "url_NotValidated" - } - ] - } - ] - })"}, - {"download_shard: novalidate in middle.", - __LINE__, - { - "download_shard", - "20", - "url_NotValidated20", - "novalidate", - "200", - "url_NotValidated200", - }, - RPCCallTestData::no_exception, - R"({ - "method" : "download_shard", - "params" : [ - { - "error" : "invalidParams", - "error_code" : 31, - "error_message" : "Invalid parameters." - } - ] - })"}, - {// Note: this should return an error but not throw. - "download_shard: arguments swapped.", - __LINE__, - { - "download_shard", - "url_NotValidated", - "20", - }, - RPCCallTestData::bad_cast, - R"()"}, - {"download_shard: index too small.", - __LINE__, - { - "download_shard", - "-1", - "url_NotValidated", - }, - RPCCallTestData::bad_cast, - R"()"}, - {"download_shard: index too big.", - __LINE__, - { - "download_shard", - "4294967296", - "url_NotValidated", - }, - RPCCallTestData::bad_cast, - R"()"}, - // feature // --------------------------------------------------------------------- {"feature: minimal.", @@ -4232,75 +4007,6 @@ static RPCCallTestData const rpcCallTestArray[] = { ] })"}, - // node_to_shard - // ------------------------------------------------------------------- - {"node_to_shard: status.", - __LINE__, - {"node_to_shard", "status"}, - RPCCallTestData::no_exception, - R"({ - "method" : "node_to_shard", - "params" : [ - { - "api_version" : %API_VER%, - "action" : "status" - } - ] - })"}, - {"node_to_shard: start.", - __LINE__, - {"node_to_shard", "start"}, - RPCCallTestData::no_exception, - R"({ - "method" : "node_to_shard", - "params" : [ - { - "api_version" : %API_VER%, - "action" : "start" - } - ] - })"}, - {"node_to_shard: stop.", - __LINE__, - {"node_to_shard", "stop"}, - RPCCallTestData::no_exception, - R"({ - "method" : "node_to_shard", - "params" : [ - { - "api_version" : %API_VER%, - "action" : "stop" - } - ] - })"}, - {"node_to_shard: too many arguments.", - __LINE__, - {"node_to_shard", "start", "stop"}, - RPCCallTestData::no_exception, - R"({ - "method" : "node_to_shard", - "params" : [ - { - "error" : "badSyntax", - "error_code" : 1, - "error_message" : "Syntax error." - } - ] - })"}, - {"node_to_shard: invalid argument.", - __LINE__, - {"node_to_shard", "invalid"}, - RPCCallTestData::no_exception, - R"({ - "method" : "node_to_shard", - "params" : [ - { - "api_version" : %API_VER%, - "action" : "invalid" - } - ] - })"}, - // owner_info // ------------------------------------------------------------------ {"owner_info: minimal.", diff --git a/src/test/rpc/ShardArchiveHandler_test.cpp b/src/test/rpc/ShardArchiveHandler_test.cpp deleted file mode 100644 index 82f12fe49a9..00000000000 --- a/src/test/rpc/ShardArchiveHandler_test.cpp +++ /dev/null @@ -1,705 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { -namespace test { - -class ShardArchiveHandler_test : public beast::unit_test::suite -{ - using Downloads = std::vector>; - - std::shared_ptr - createServer(jtx::Env& env, bool ssl = true) - { - std::vector list; - list.push_back(TrustedPublisherServer::randomValidator()); - return make_TrustedPublisherServer( - env.app().getIOService(), - list, - env.timeKeeper().now() + std::chrono::seconds{3600}, - // No future VLs - {}, - ssl); - } - -public: - // Test the shard downloading module by queueing - // a download and verifying the contents of the - // state database. - void - testSingleDownloadAndStateDB() - { - testcase("testSingleDownloadAndStateDB"); - - beast::temp_dir tempDir; - - auto c = jtx::envconfig(); - auto& section = c->section(ConfigSection::shardDatabase()); - section.set("path", tempDir.path()); - section.set("max_historical_shards", "20"); - c->setupControl(true, true, true); - - jtx::Env env(*this, std::move(c)); - auto handler = env.app().getShardArchiveHandler(); - BEAST_EXPECT(handler); - BEAST_EXPECT(dynamic_cast(handler) == nullptr); - - std::string const rawUrl = "https://foo:443/1.tar.lz4"; - parsedURL url; - - parseUrl(url, rawUrl); - handler->add(1, {url, rawUrl}); - - { - std::lock_guard lock(handler->m_); - std::uint64_t rowCount = 0; - - readArchiveDB( - *handler->sqlDB_, [&](std::string const& url, int state) { - BEAST_EXPECT(state == 1); - BEAST_EXPECT(url == rawUrl); - ++rowCount; - }); - - BEAST_EXPECT(rowCount == 1); - } - - handler->release(); - } - - // Test the shard downloading module by queueing - // three downloads and verifying the contents of - // the state database. - void - testDownloadsAndStateDB() - { - testcase("testDownloadsAndStateDB"); - - beast::temp_dir tempDir; - - auto c = jtx::envconfig(); - auto& section = c->section(ConfigSection::shardDatabase()); - section.set("path", tempDir.path()); - section.set("max_historical_shards", "20"); - c->setupControl(true, true, true); - - jtx::Env env(*this, std::move(c)); - auto handler = env.app().getShardArchiveHandler(); - BEAST_EXPECT(handler); - BEAST_EXPECT(dynamic_cast(handler) == nullptr); - - Downloads const dl = { - {1, "https://foo:443/1.tar.lz4"}, - {2, "https://foo:443/2.tar.lz4"}, - {3, "https://foo:443/3.tar.lz4"}}; - - for (auto const& entry : dl) - { - parsedURL url; - parseUrl(url, entry.second); - handler->add(entry.first, {url, entry.second}); - } - - { - std::lock_guard lock(handler->m_); - std::uint64_t pos = 0; - - readArchiveDB( - *handler->sqlDB_, [&](std::string const& url, int state) { - BEAST_EXPECT(state == dl[pos].first); - BEAST_EXPECT(url == dl[pos].second); - ++pos; - }); - - BEAST_EXPECT(pos == dl.size()); - } - - handler->release(); - } - - // Test the shard downloading module by initiating - // and completing ten downloads and verifying the - // contents of the filesystem and the handler's - // archives. - void - testDownloadsAndFileSystem() - { - testcase("testDownloadsAndFileSystem"); - - beast::temp_dir tempDir; - - auto c = jtx::envconfig(); - { - auto& section{c->section(ConfigSection::shardDatabase())}; - section.set("path", tempDir.path()); - section.set("max_historical_shards", "20"); - section.set("ledgers_per_shard", "256"); - section.set("earliest_seq", "257"); - } - { - auto& section{c->section(ConfigSection::nodeDatabase())}; - section.set("ledgers_per_shard", "256"); - section.set("earliest_seq", "257"); - } - c->setupControl(true, true, true); - - jtx::Env env( - *this, std::move(c), nullptr, beast::severities::kDisabled); - - std::uint8_t const numberOfDownloads = 10; - - // Create some ledgers so that the ShardArchiveHandler - // can verify the last ledger hash for the shard - // downloads. - for (int i = 0; i < env.app().getShardStore()->ledgersPerShard() * - (numberOfDownloads + 1); - ++i) - { - env.close(); - } - - auto handler = env.app().getShardArchiveHandler(); - BEAST_EXPECT(handler); - BEAST_EXPECT(dynamic_cast(handler) == nullptr); - - auto server = createServer(env); - auto host = server->local_endpoint().address().to_string(); - auto port = std::to_string(server->local_endpoint().port()); - server->stop(); - - Downloads const dl = [count = numberOfDownloads, &host, &port] { - Downloads ret; - - for (int i = 1; i <= count; ++i) - { - ret.push_back( - {i, - (boost::format("https://%s:%d/%d.tar.lz4") % host % port % - i) - .str()}); - } - - return ret; - }(); - - for (auto const& entry : dl) - { - parsedURL url; - parseUrl(url, entry.second); - handler->add(entry.first, {url, entry.second}); - } - - BEAST_EXPECT(handler->start()); - - auto stateDir = - RPC::ShardArchiveHandler::getDownloadDirectory(env.app().config()); - - std::unique_lock lock(handler->m_); - - BEAST_EXPECT( - boost::filesystem::exists(stateDir) || handler->archives_.empty()); - - using namespace std::chrono_literals; - auto waitMax = 60s; - - while (!handler->archives_.empty()) - { - lock.unlock(); - std::this_thread::sleep_for(1s); - - if (waitMax -= 1s; waitMax <= 0s) - { - BEAST_EXPECT(false); - break; - } - - lock.lock(); - } - - BEAST_EXPECT(!boost::filesystem::exists(stateDir)); - } - - // Test the shard downloading module by initiating - // and completing ten downloads and verifying the - // contents of the filesystem and the handler's - // archives. Then restart the application and ensure - // that the handler is created and started automatically. - void - testDownloadsAndRestart() - { - testcase("testDownloadsAndRestart"); - - beast::temp_dir tempDir; - - { - auto c = jtx::envconfig(); - { - auto& section{c->section(ConfigSection::shardDatabase())}; - section.set("path", tempDir.path()); - section.set("max_historical_shards", "20"); - section.set("ledgers_per_shard", "256"); - section.set("earliest_seq", "257"); - } - { - auto& section{c->section(ConfigSection::nodeDatabase())}; - section.set("ledgers_per_shard", "256"); - section.set("earliest_seq", "257"); - } - c->setupControl(true, true, true); - - jtx::Env env( - *this, std::move(c), nullptr, beast::severities::kDisabled); - - std::uint8_t const numberOfDownloads = 10; - - // Create some ledgers so that the ShardArchiveHandler - // can verify the last ledger hash for the shard - // downloads. - for (int i = 0; i < env.app().getShardStore()->ledgersPerShard() * - (numberOfDownloads + 1); - ++i) - { - env.close(); - } - - auto handler = env.app().getShardArchiveHandler(); - BEAST_EXPECT(handler); - BEAST_EXPECT( - dynamic_cast(handler) == nullptr); - - auto server = createServer(env); - auto host = server->local_endpoint().address().to_string(); - auto port = std::to_string(server->local_endpoint().port()); - server->stop(); - - Downloads const dl = [count = numberOfDownloads, &host, &port] { - Downloads ret; - - for (int i = 1; i <= count; ++i) - { - ret.push_back( - {i, - (boost::format("https://%s:%d/%d.tar.lz4") % host % - port % i) - .str()}); - } - - return ret; - }(); - - for (auto const& entry : dl) - { - parsedURL url; - parseUrl(url, entry.second); - handler->add(entry.first, {url, entry.second}); - } - - auto stateDir = RPC::ShardArchiveHandler::getDownloadDirectory( - env.app().config()); - - boost::filesystem::copy_file( - stateDir / stateDBName, - boost::filesystem::path(tempDir.path()) / stateDBName); - - BEAST_EXPECT(handler->start()); - - std::unique_lock lock(handler->m_); - - BEAST_EXPECT( - boost::filesystem::exists(stateDir) || - handler->archives_.empty()); - - using namespace std::chrono_literals; - auto waitMax = 60s; - - while (!handler->archives_.empty()) - { - lock.unlock(); - std::this_thread::sleep_for(1s); - - if (waitMax -= 1s; waitMax <= 0s) - { - BEAST_EXPECT(false); - break; - } - - lock.lock(); - } - - BEAST_EXPECT(!boost::filesystem::exists(stateDir)); - - boost::filesystem::create_directory(stateDir); - - boost::filesystem::copy_file( - boost::filesystem::path(tempDir.path()) / stateDBName, - stateDir / stateDBName); - } - - auto c = jtx::envconfig(); - { - auto& section{c->section(ConfigSection::shardDatabase())}; - section.set("path", tempDir.path()); - section.set("max_historical_shards", "20"); - section.set("shard_verification_retry_interval", "1"); - section.set("shard_verification_max_attempts", "10000"); - section.set("ledgers_per_shard", "256"); - section.set("earliest_seq", "257"); - } - { - auto& section{c->section(ConfigSection::nodeDatabase())}; - section.set("ledgers_per_shard", "256"); - section.set("earliest_seq", "257"); - } - c->setupControl(true, true, true); - - jtx::Env env( - *this, std::move(c), nullptr, beast::severities::kDisabled); - std::uint8_t const numberOfDownloads = 10; - - // Create some ledgers so that the ShardArchiveHandler - // can verify the last ledger hash for the shard - // downloads. - for (int i = 0; i < env.app().getShardStore()->ledgersPerShard() * - (numberOfDownloads + 1); - ++i) - { - env.close(); - } - - auto handler = env.app().getShardArchiveHandler(); - BEAST_EXPECT(dynamic_cast(handler) != nullptr); - - auto stateDir = - RPC::ShardArchiveHandler::getDownloadDirectory(env.app().config()); - - std::unique_lock lock(handler->m_); - - BEAST_EXPECT( - boost::filesystem::exists(stateDir) || handler->archives_.empty()); - - using namespace std::chrono_literals; - auto waitMax = 60s; - - while (!handler->archives_.empty()) - { - lock.unlock(); - std::this_thread::sleep_for(1s); - - if (waitMax -= 1s; waitMax <= 0s) - { - BEAST_EXPECT(false); - break; - } - - lock.lock(); - } - - BEAST_EXPECT(!boost::filesystem::exists(stateDir)); - } - - // Ensure that downloads fail when the shard - // database cannot store any more shards - void - testShardCountFailure() - { - testcase("testShardCountFailure"); - std::string capturedLogs; - - { - beast::temp_dir tempDir; - - auto c = jtx::envconfig(); - { - auto& section{c->section(ConfigSection::shardDatabase())}; - section.set("path", tempDir.path()); - section.set("max_historical_shards", "1"); - section.set("ledgers_per_shard", "256"); - section.set("earliest_seq", "257"); - } - { - auto& section{c->section(ConfigSection::nodeDatabase())}; - section.set("ledgers_per_shard", "256"); - section.set("earliest_seq", "257"); - } - c->setupControl(true, true, true); - - std::unique_ptr logs(new CaptureLogs(&capturedLogs)); - jtx::Env env(*this, std::move(c), std::move(logs)); - - std::uint8_t const numberOfDownloads = 10; - - // Create some ledgers so that the ShardArchiveHandler - // can verify the last ledger hash for the shard - // downloads. - for (int i = 0; i < env.app().getShardStore()->ledgersPerShard() * - (numberOfDownloads + 1); - ++i) - { - env.close(); - } - - auto handler = env.app().getShardArchiveHandler(); - BEAST_EXPECT(handler); - BEAST_EXPECT( - dynamic_cast(handler) == nullptr); - - auto server = createServer(env); - auto host = server->local_endpoint().address().to_string(); - auto port = std::to_string(server->local_endpoint().port()); - server->stop(); - - Downloads const dl = [count = numberOfDownloads, &host, &port] { - Downloads ret; - - for (int i = 1; i <= count; ++i) - { - ret.push_back( - {i, - (boost::format("https://%s:%d/%d.tar.lz4") % host % - port % i) - .str()}); - } - - return ret; - }(); - - for (auto const& entry : dl) - { - parsedURL url; - parseUrl(url, entry.second); - handler->add(entry.first, {url, entry.second}); - } - - BEAST_EXPECT(!handler->start()); - auto stateDir = RPC::ShardArchiveHandler::getDownloadDirectory( - env.app().config()); - - handler->release(); - BEAST_EXPECT(!boost::filesystem::exists(stateDir)); - } - - auto const expectedErrorMessage = - "shards 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 maximum number of historical " - "shards reached"; - BEAST_EXPECT( - capturedLogs.find(expectedErrorMessage) != std::string::npos); - - { - beast::temp_dir tempDir; - - auto c = jtx::envconfig(); - { - auto& section{c->section(ConfigSection::shardDatabase())}; - section.set("path", tempDir.path()); - section.set("max_historical_shards", "0"); - section.set("ledgers_per_shard", "256"); - section.set("earliest_seq", "257"); - } - { - auto& section{c->section(ConfigSection::nodeDatabase())}; - section.set("ledgers_per_shard", "256"); - section.set("earliest_seq", "257"); - } - c->setupControl(true, true, true); - - std::unique_ptr logs(new CaptureLogs(&capturedLogs)); - jtx::Env env(*this, std::move(c), std::move(logs)); - - std::uint8_t const numberOfDownloads = 1; - - // Create some ledgers so that the ShardArchiveHandler - // can verify the last ledger hash for the shard - // downloads. - for (int i = 0; i < env.app().getShardStore()->ledgersPerShard() * - ((numberOfDownloads * 3) + 1); - ++i) - { - env.close(); - } - - auto handler = env.app().getShardArchiveHandler(); - BEAST_EXPECT(handler); - BEAST_EXPECT( - dynamic_cast(handler) == nullptr); - - auto server = createServer(env); - auto host = server->local_endpoint().address().to_string(); - auto port = std::to_string(server->local_endpoint().port()); - server->stop(); - - Downloads const dl = [count = numberOfDownloads, &host, &port] { - Downloads ret; - - for (int i = 1; i <= count; ++i) - { - ret.push_back( - {i, - (boost::format("https://%s:%d/%d.tar.lz4") % host % - port % i) - .str()}); - } - - return ret; - }(); - - for (auto const& entry : dl) - { - parsedURL url; - parseUrl(url, entry.second); - handler->add(entry.first, {url, entry.second}); - } - - BEAST_EXPECT(!handler->start()); - auto stateDir = RPC::ShardArchiveHandler::getDownloadDirectory( - env.app().config()); - - handler->release(); - BEAST_EXPECT(!boost::filesystem::exists(stateDir)); - } - - auto const expectedErrorMessage2 = - "shard 1 maximum number of historical shards reached"; - BEAST_EXPECT( - capturedLogs.find(expectedErrorMessage2) != std::string::npos); - } - - // Ensure that downloads fail when the shard - // database has already stored one of the - // queued shards - void - testRedundantShardFailure() - { - testcase("testRedundantShardFailure"); - std::string capturedLogs; - - { - beast::temp_dir tempDir; - - auto c = jtx::envconfig(); - { - auto& section{c->section(ConfigSection::shardDatabase())}; - section.set("path", tempDir.path()); - section.set("max_historical_shards", "1"); - section.set("ledgers_per_shard", "256"); - section.set("earliest_seq", "257"); - } - { - auto& section{c->section(ConfigSection::nodeDatabase())}; - section.set("ledgers_per_shard", "256"); - section.set("earliest_seq", "257"); - } - c->setupControl(true, true, true); - - std::unique_ptr logs(new CaptureLogs(&capturedLogs)); - jtx::Env env( - *this, - std::move(c), - std::move(logs), - beast::severities::kDebug); - - std::uint8_t const numberOfDownloads = 10; - - // Create some ledgers so that the ShardArchiveHandler - // can verify the last ledger hash for the shard - // downloads. - for (int i = 0; i < env.app().getShardStore()->ledgersPerShard() * - (numberOfDownloads + 1); - ++i) - { - env.close(); - } - - BEAST_EXPECT(env.app().getShardStore()->prepareShards({1})); - - auto handler = env.app().getShardArchiveHandler(); - BEAST_EXPECT(handler); - BEAST_EXPECT( - dynamic_cast(handler) == nullptr); - - auto server = createServer(env); - auto host = server->local_endpoint().address().to_string(); - auto port = std::to_string(server->local_endpoint().port()); - server->stop(); - - Downloads const dl = [count = numberOfDownloads, &host, &port] { - Downloads ret; - - for (int i = 1; i <= count; ++i) - { - ret.push_back( - {i, - (boost::format("https://%s:%d/%d.tar.lz4") % host % - port % i) - .str()}); - } - - return ret; - }(); - - for (auto const& entry : dl) - { - parsedURL url; - parseUrl(url, entry.second); - handler->add(entry.first, {url, entry.second}); - } - - BEAST_EXPECT(!handler->start()); - auto stateDir = RPC::ShardArchiveHandler::getDownloadDirectory( - env.app().config()); - - handler->release(); - BEAST_EXPECT(!boost::filesystem::exists(stateDir)); - } - - auto const expectedErrorMessage = - "shard 1 is already queued for import"; - BEAST_EXPECT( - capturedLogs.find(expectedErrorMessage) != std::string::npos); - } - - void - run() override - { - testSingleDownloadAndStateDB(); - testDownloadsAndStateDB(); - testDownloadsAndFileSystem(); - testDownloadsAndRestart(); - testShardCountFailure(); - testRedundantShardFailure(); - } -}; - -BEAST_DEFINE_TESTSUITE_PRIO(ShardArchiveHandler, app, ripple, 3); - -} // namespace test -} // namespace ripple diff --git a/src/test/shamap/common.h b/src/test/shamap/common.h index 2280c77d4a1..db5a2c40acf 100644 --- a/src/test/shamap/common.h +++ b/src/test/shamap/common.h @@ -20,7 +20,6 @@ #ifndef RIPPLE_SHAMAP_TESTS_COMMON_H_INCLUDED #define RIPPLE_SHAMAP_TESTS_COMMON_H_INCLUDED -#include #include #include #include @@ -81,12 +80,14 @@ class TestNodeFamily : public Family return j_; } - std::shared_ptr getFullBelowCache(std::uint32_t) override + std::shared_ptr + getFullBelowCache() override { return fbCache_; } - std::shared_ptr getTreeNodeCache(std::uint32_t) override + std::shared_ptr + getTreeNodeCache() override { return tnCache_; } @@ -98,12 +99,6 @@ class TestNodeFamily : public Family tnCache_->sweep(); } - bool - isShardBacked() const override - { - return true; - } - void missingNodeAcquireBySeq(std::uint32_t refNum, uint256 const& nodeHash) override diff --git a/src/xrpld/app/consensus/RCLConsensus.cpp b/src/xrpld/app/consensus/RCLConsensus.cpp index 7b061e10b31..69fb371578a 100644 --- a/src/xrpld/app/consensus/RCLConsensus.cpp +++ b/src/xrpld/app/consensus/RCLConsensus.cpp @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include diff --git a/src/xrpld/app/ledger/InboundLedger.h b/src/xrpld/app/ledger/InboundLedger.h index 62b6925d59c..13f603e79d0 100644 --- a/src/xrpld/app/ledger/InboundLedger.h +++ b/src/xrpld/app/ledger/InboundLedger.h @@ -42,7 +42,6 @@ class InboundLedger final : public TimeoutCounter, // These are the reasons we might acquire a ledger enum class Reason { HISTORY, // Acquiring past ledger - SHARD, // Acquiring for shard GENERIC, // Generic other reasons CONSENSUS // We believe the consensus round requires this ledger }; diff --git a/src/xrpld/app/ledger/LedgerMaster.h b/src/xrpld/app/ledger/LedgerMaster.h index 7921773e3f0..5149424e285 100644 --- a/src/xrpld/app/ledger/LedgerMaster.h +++ b/src/xrpld/app/ledger/LedgerMaster.h @@ -357,9 +357,6 @@ class LedgerMaster : public AbstractFetchPackContainer // The last ledger we handled fetching history std::shared_ptr mHistLedger; - // The last ledger we handled fetching for a shard - std::shared_ptr mShardLedger; - // Fully validated ledger, whether or not we have the ledger resident. std::pair mLastValidLedger{uint256(), 0}; diff --git a/src/xrpld/app/ledger/detail/InboundLedger.cpp b/src/xrpld/app/ledger/detail/InboundLedger.cpp index b98f24aed43..5b0c3469111 100644 --- a/src/xrpld/app/ledger/detail/InboundLedger.cpp +++ b/src/xrpld/app/ledger/detail/InboundLedger.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -112,40 +111,6 @@ InboundLedger::init(ScopedLockType& collectionLock) if (failed_) return; - if (!complete_) - { - auto shardStore = app_.getShardStore(); - if (mReason == Reason::SHARD) - { - if (!shardStore) - { - JLOG(journal_.error()) - << "Acquiring shard with no shard store available"; - failed_ = true; - return; - } - - mHaveHeader = false; - mHaveTransactions = false; - mHaveState = false; - mLedger.reset(); - - tryDB(app_.getShardFamily()->db()); - if (failed_) - return; - } - else if (shardStore && mSeq >= shardStore->earliestLedgerSeq()) - { - if (auto l = shardStore->fetchLedger(hash_, mSeq)) - { - mHaveHeader = true; - mHaveTransactions = true; - mHaveState = true; - complete_ = true; - mLedger = std::move(l); - } - } - } if (!complete_) { addPeers(); @@ -160,7 +125,7 @@ InboundLedger::init(ScopedLockType& collectionLock) mLedger->read(keylet::fees())); mLedger->setImmutable(); - if (mReason == Reason::HISTORY || mReason == Reason::SHARD) + if (mReason == Reason::HISTORY) return; app_.getLedgerMaster().storeLedger(mLedger); @@ -200,8 +165,6 @@ InboundLedger::checkLocal() { if (mLedger) tryDB(mLedger->stateMap().family().db()); - else if (mReason == Reason::SHARD) - tryDB(app_.getShardFamily()->db()); else tryDB(app_.getNodeFamily().db()); if (failed_ || complete_) @@ -283,8 +246,7 @@ InboundLedger::tryDB(NodeStore::Database& srcDB) mLedger = std::make_shared( deserializePrefixedHeader(makeSlice(data)), app_.config(), - mReason == Reason::SHARD ? *app_.getShardFamily() - : app_.getNodeFamily()); + app_.getNodeFamily()); if (mLedger->info().hash != hash_ || (mSeq != 0 && mSeq != mLedger->info().seq)) { @@ -495,9 +457,6 @@ InboundLedger::done() mLedger->setImmutable(); switch (mReason) { - case Reason::SHARD: - app_.getShardStore()->setStored(mLedger); - [[fallthrough]]; case Reason::HISTORY: app_.getInboundLedgers().onLedgerFetched(); break; @@ -551,9 +510,7 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) if (!mHaveHeader) { - tryDB( - mReason == Reason::SHARD ? app_.getShardFamily()->db() - : app_.getNodeFamily().db()); + tryDB(app_.getNodeFamily().db()); if (failed_) { JLOG(journal_.warn()) << " failed local for " << hash_; @@ -854,8 +811,7 @@ InboundLedger::takeHeader(std::string const& data) if (complete_ || failed_ || mHaveHeader) return true; - auto* f = mReason == Reason::SHARD ? app_.getShardFamily() - : &app_.getNodeFamily(); + auto* f = &app_.getNodeFamily(); mLedger = std::make_shared( deserializeHeader(makeSlice(data)), app_.config(), *f); if (mLedger->info().hash != hash_ || diff --git a/src/xrpld/app/ledger/detail/InboundLedgers.cpp b/src/xrpld/app/ledger/detail/InboundLedgers.cpp index 04964d2a921..2b4d2161b63 100644 --- a/src/xrpld/app/ledger/detail/InboundLedgers.cpp +++ b/src/xrpld/app/ledger/detail/InboundLedgers.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -70,9 +69,6 @@ class InboundLedgersImp : public InboundLedgers InboundLedger::Reason reason) override { assert(hash.isNonZero()); - assert( - reason != InboundLedger::Reason::SHARD || - (seq != 0 && app_.getShardStore())); // probably not the right rule if (app_.getOPs().isNeedNetworkLedger() && @@ -119,25 +115,6 @@ class InboundLedgersImp : public InboundLedgers if (!inbound->isComplete()) return {}; - if (reason == InboundLedger::Reason::HISTORY) - { - if (inbound->getLedger()->stateMap().family().isShardBacked()) - app_.getNodeStore().storeLedger(inbound->getLedger()); - } - else if (reason == InboundLedger::Reason::SHARD) - { - auto shardStore = app_.getShardStore(); - if (!shardStore) - { - JLOG(j_.error()) - << "Acquiring shard with no shard store available"; - return {}; - } - if (inbound->getLedger()->stateMap().family().isShardBacked()) - shardStore->setStored(inbound->getLedger()); - else - shardStore->storeLedger(inbound->getLedger()); - } return inbound->getLedger(); } @@ -285,7 +262,7 @@ class InboundLedgersImp : public InboundLedgers } // Should only be called with an inboundledger that has - // a reason of history or shard + // a reason of history void onLedgerFetched() override { diff --git a/src/xrpld/app/ledger/detail/LedgerMaster.cpp b/src/xrpld/app/ledger/detail/LedgerMaster.cpp index f03004fd14c..dab8f838249 100644 --- a/src/xrpld/app/ledger/detail/LedgerMaster.cpp +++ b/src/xrpld/app/ledger/detail/LedgerMaster.cpp @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -830,38 +829,13 @@ LedgerMaster::tryFill(std::shared_ptr ledger) void LedgerMaster::getFetchPack(LedgerIndex missing, InboundLedger::Reason reason) { - LedgerIndex const ledgerIndex([&]() { - if (reason == InboundLedger::Reason::SHARD) - { - // Do not acquire a ledger sequence greater - // than the last ledger in the shard - auto const shardStore{app_.getShardStore()}; - auto const shardIndex{shardStore->seqToShardIndex(missing)}; - return std::min(missing + 1, shardStore->lastLedgerSeq(shardIndex)); - } - return missing + 1; - }()); + LedgerIndex const ledgerIndex = missing + 1; auto const haveHash{getLedgerHashForHistory(ledgerIndex, reason)}; if (!haveHash || haveHash->isZero()) { - if (reason == InboundLedger::Reason::SHARD) - { - auto const shardStore{app_.getShardStore()}; - auto const shardIndex{shardStore->seqToShardIndex(missing)}; - if (missing < shardStore->lastLedgerSeq(shardIndex)) - { - JLOG(m_journal.error()) - << "No hash for fetch pack. " - << "Missing ledger sequence " << missing - << " while acquiring shard " << shardIndex; - } - } - else - { - JLOG(m_journal.error()) - << "No hash for fetch pack. Missing Index " << missing; - } + JLOG(m_journal.error()) + << "No hash for fetch pack. Missing Index " << missing; return; } @@ -1342,8 +1316,7 @@ LedgerMaster::getLedgerHashForHistory( { // Try to get the hash of a ledger we need to fetch for history std::optional ret; - auto const& l{ - reason == InboundLedger::Reason::SHARD ? mShardLedger : mHistLedger}; + auto const& l{mHistLedger}; if (l && l->info().seq >= index) { @@ -2001,54 +1974,35 @@ LedgerMaster::fetchForHistory( auto seq = ledger->info().seq; assert(seq == missing); JLOG(m_journal.trace()) << "fetchForHistory acquired " << seq; - if (reason == InboundLedger::Reason::SHARD) + setFullLedger(ledger, false, false); + int fillInProgress; { - ledger->setFull(); - { - std::lock_guard lock(m_mutex); - mShardLedger = ledger; - } - if (!ledger->stateMap().family().isShardBacked()) - app_.getShardStore()->storeLedger(ledger); + std::lock_guard lock(m_mutex); + mHistLedger = ledger; + fillInProgress = mFillInProgress; } - else + if (fillInProgress == 0 && + app_.getRelationalDatabase().getHashByIndex(seq - 1) == + ledger->info().parentHash) { - setFullLedger(ledger, false, false); - int fillInProgress; { + // Previous ledger is in DB std::lock_guard lock(m_mutex); - mHistLedger = ledger; - fillInProgress = mFillInProgress; - } - if (fillInProgress == 0 && - app_.getRelationalDatabase().getHashByIndex(seq - 1) == - ledger->info().parentHash) - { - { - // Previous ledger is in DB - std::lock_guard lock(m_mutex); - mFillInProgress = seq; - } - app_.getJobQueue().addJob( - jtADVANCE, "tryFill", [this, ledger]() { - tryFill(ledger); - }); + mFillInProgress = seq; } + app_.getJobQueue().addJob( + jtADVANCE, "tryFill", [this, ledger]() { + tryFill(ledger); + }); } progress = true; } else { std::uint32_t fetchSz; - if (reason == InboundLedger::Reason::SHARD) - // Do not fetch ledger sequences lower - // than the shard's first ledger sequence - fetchSz = app_.getShardStore()->firstLedgerSeq( - app_.getShardStore()->seqToShardIndex(missing)); - else - // Do not fetch ledger sequences lower - // than the earliest ledger sequence - fetchSz = app_.getNodeStore().earliestLedgerSeq(); + // Do not fetch ledger sequences lower + // than the earliest ledger sequence + fetchSz = app_.getNodeStore().earliestLedgerSeq(); fetchSz = missing >= fetchSz ? std::min(ledger_fetch_size_, (missing - fetchSz) + 1) : 0; @@ -2081,7 +2035,8 @@ LedgerMaster::fetchForHistory( << "Ledgers: " << app_.getLedgerMaster().getCompleteLedgers(); JLOG(m_journal.fatal()) << "Acquire reason: " - << (reason == InboundLedger::Reason::HISTORY ? "HISTORY" : "SHARD"); + << (reason == InboundLedger::Reason::HISTORY ? "HISTORY" + : "NOT HISTORY"); clearLedger(missing + 1); progress = true; } @@ -2133,15 +2088,6 @@ LedgerMaster::doAdvance(std::unique_lock& sl) else missing = std::nullopt; } - if (!missing && mFillInProgress == 0) - { - if (auto shardStore = app_.getShardStore()) - { - missing = shardStore->prepareLedger(mValidLedgerSeq); - if (missing) - reason = InboundLedger::Reason::SHARD; - } - } if (missing) { fetchForHistory(*missing, progress, reason, sl); @@ -2156,7 +2102,6 @@ LedgerMaster::doAdvance(std::unique_lock& sl) else { mHistLedger.reset(); - mShardLedger.reset(); JLOG(m_journal.trace()) << "tryAdvance not fetching history"; } } diff --git a/src/xrpld/app/main/Application.cpp b/src/xrpld/app/main/Application.cpp index ff6cc0584ca..f3308a091dc 100644 --- a/src/xrpld/app/main/Application.cpp +++ b/src/xrpld/app/main/Application.cpp @@ -50,17 +50,14 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include #include -#include #include #include #include @@ -192,9 +189,6 @@ class ApplicationImp : public Application, public BasicApp std::unique_ptr m_nodeStore; NodeFamily nodeFamily_; - std::unique_ptr shardStore_; - std::unique_ptr shardFamily_; - std::unique_ptr shardArchiveHandler_; // VFALCO TODO Make OrderBookDB abstract OrderBookDB m_orderBookDB; std::unique_ptr m_pathRequests; @@ -361,13 +355,6 @@ class ApplicationImp : public Application, public BasicApp , nodeFamily_(*this, *m_collectorManager) - // The shard store is optional and make_ShardStore can return null. - , shardStore_(make_ShardStore( - *this, - m_nodeStoreScheduler, - 4, - logs_->journal("ShardStore"))) - , m_orderBookDB(*this) , m_pathRequests(std::make_unique( @@ -565,14 +552,6 @@ class ApplicationImp : public Application, public BasicApp return nodeFamily_; } - // The shard store is an optional feature. If the sever is configured for - // shards, this function will return a valid pointer, otherwise a nullptr. - Family* - getShardFamily() override - { - return shardFamily_.get(); - } - TimeKeeper& timeKeeper() override { @@ -696,72 +675,6 @@ class ApplicationImp : public Application, public BasicApp return *m_nodeStore; } - // The shard store is an optional feature. If the sever is configured for - // shards, this function will return a valid pointer, otherwise a nullptr. - NodeStore::DatabaseShard* - getShardStore() override - { - return shardStore_.get(); - } - - RPC::ShardArchiveHandler* - getShardArchiveHandler(bool tryRecovery) override - { - static std::mutex handlerMutex; - std::lock_guard lock(handlerMutex); - - // After constructing the handler, try to - // initialize it. Log on error; set the - // member variable on success. - auto initAndSet = - [this](std::unique_ptr&& handler) { - if (!handler) - return false; - - if (!handler->init()) - { - JLOG(m_journal.error()) - << "Failed to initialize ShardArchiveHandler."; - - return false; - } - - shardArchiveHandler_ = std::move(handler); - return true; - }; - - // Need to resume based on state from a previous - // run. - if (tryRecovery) - { - if (shardArchiveHandler_ != nullptr) - { - JLOG(m_journal.error()) - << "ShardArchiveHandler already created at startup."; - - return nullptr; - } - - auto handler = - RPC::ShardArchiveHandler::tryMakeRecoveryHandler(*this); - - if (!initAndSet(std::move(handler))) - return nullptr; - } - - // Construct the ShardArchiveHandler - if (shardArchiveHandler_ == nullptr) - { - auto handler = - RPC::ShardArchiveHandler::makeShardArchiveHandler(*this); - - if (!initAndSet(std::move(handler))) - return nullptr; - } - - return shardArchiveHandler_.get(); - } - Application::MutexType& getMasterMutex() override { @@ -1075,10 +988,10 @@ class ApplicationImp : public Application, public BasicApp { std::shared_ptr const fullBelowCache = - nodeFamily_.getFullBelowCache(0); + nodeFamily_.getFullBelowCache(); std::shared_ptr const treeNodeCache = - nodeFamily_.getTreeNodeCache(0); + nodeFamily_.getTreeNodeCache(); std::size_t const oldFullBelowSize = fullBelowCache->size(); std::size_t const oldTreeNodeSize = treeNodeCache->size(); @@ -1094,25 +1007,6 @@ class ApplicationImp : public Application, public BasicApp << "NodeFamily::TreeNodeCache sweep. Size before: " << oldTreeNodeSize << "; size after: " << treeNodeCache->size(); } - if (shardFamily_) - { - std::size_t const oldFullBelowSize = - shardFamily_->getFullBelowCacheSize(); - std::size_t const oldTreeNodeSize = - shardFamily_->getTreeNodeCacheSize().second; - - shardFamily_->sweep(); - - JLOG(m_journal.debug()) - << "ShardFamily::FullBelowCache sweep. Size before: " - << oldFullBelowSize - << "; size after: " << shardFamily_->getFullBelowCacheSize(); - - JLOG(m_journal.debug()) - << "ShardFamily::TreeNodeCache sweep. Size before: " - << oldTreeNodeSize << "; size after: " - << shardFamily_->getTreeNodeCacheSize().second; - } { TaggedCache const& masterTxCache = getMasterTransaction().getCache(); @@ -1129,11 +1023,6 @@ class ApplicationImp : public Application, public BasicApp // Does not appear to have an associated cache. getNodeStore().sweep(); } - if (shardStore_) - { - // Does not appear to have an associated cache. - shardStore_->sweep(); - } { std::size_t const oldLedgerMasterCacheSize = getLedgerMaster().getFetchPackCacheSize(); @@ -1266,9 +1155,6 @@ class ApplicationImp : public Application, public BasicApp // and new validations must be greater than this. std::atomic maxDisallowedLedger_{0}; - bool - nodeToShards(); - void startGenesisLedger(); @@ -1348,15 +1234,6 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) if (!initRelationalDatabase() || !initNodeStore()) return false; - if (shardStore_) - { - shardFamily_ = - std::make_unique(*this, *m_collectorManager); - - if (!shardStore_->init()) - return false; - } - if (!peerReservations_->load(getWalletDB())) { JLOG(m_journal.fatal()) << "Cannot find peer reservations!"; @@ -1543,13 +1420,6 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) add(*overlay_); // add to PropertyStream } - if (!config_->standalone()) - { - // NodeStore import into the ShardStore requires the SQLite database - if (config_->nodeToShard && !nodeToShards()) - return false; - } - // start first consensus round if (!config_->reporting() && !m_networkOPs->beginConsensus( @@ -1664,38 +1534,6 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) } } - RPC::ShardArchiveHandler* shardArchiveHandler = nullptr; - if (shardStore_) - { - try - { - // Create a ShardArchiveHandler if recovery - // is needed (there's a state database left - // over from a previous run). - auto handler = getShardArchiveHandler(true); - - // Recovery is needed. - if (handler) - shardArchiveHandler = handler; - } - catch (std::exception const& e) - { - JLOG(m_journal.fatal()) - << "Exception when starting ShardArchiveHandler from " - "state database: " - << e.what(); - - return false; - } - } - - if (shardArchiveHandler && !shardArchiveHandler->start()) - { - JLOG(m_journal.fatal()) << "Failed to start ShardArchiveHandler."; - - return false; - } - validatorSites_->start(); if (reportingETL_) @@ -1807,12 +1645,8 @@ ApplicationImp::run() m_loadManager->stop(); m_shaMapStore->stop(); m_jobQueue->stop(); - if (shardArchiveHandler_) - shardArchiveHandler_->stop(); if (overlay_) overlay_->stop(); - if (shardStore_) - shardStore_->stop(); grpcServer_->stop(); m_networkOPs->stop(); serverHandler_->stop(); @@ -1876,9 +1710,6 @@ ApplicationImp::fdRequired() const // doubled if online delete is enabled). needed += std::max(5, m_shaMapStore->fdRequired()); - if (shardStore_) - needed += shardStore_->fdRequired(); - // One fd per incoming connection a port can accept, or // if no limit is set, assume it'll handle 256 clients. for (auto const& p : serverHandler_->setup().ports) @@ -2345,27 +2176,6 @@ ApplicationImp::journal(std::string const& name) return logs_->journal(name); } -bool -ApplicationImp::nodeToShards() -{ - assert(overlay_); - assert(!config_->standalone()); - - if (config_->section(ConfigSection::shardDatabase()).empty()) - { - JLOG(m_journal.fatal()) - << "The [shard_db] configuration setting must be set"; - return false; - } - if (!shardStore_) - { - JLOG(m_journal.fatal()) << "Invalid [shard_db] configuration"; - return false; - } - shardStore_->importDatabase(getNodeStore()); - return true; -} - void ApplicationImp::setMaxDisallowedLedger() { diff --git a/src/xrpld/app/main/Application.h b/src/xrpld/app/main/Application.h index 57e6f1730e5..d4871317e73 100644 --- a/src/xrpld/app/main/Application.h +++ b/src/xrpld/app/main/Application.h @@ -42,14 +42,10 @@ class Manager; } namespace NodeStore { class Database; -class DatabaseShard; } // namespace NodeStore namespace perf { class PerfLog; } -namespace RPC { -class ShardArchiveHandler; -} // VFALCO TODO Fix forward declares required for header dependency loops class AmendmentTable; @@ -172,8 +168,6 @@ class Application : public beast::PropertyStream::Source getCollectorManager() = 0; virtual Family& getNodeFamily() = 0; - virtual Family* - getShardFamily() = 0; virtual TimeKeeper& timeKeeper() = 0; virtual JobQueue& @@ -210,10 +204,6 @@ class Application : public beast::PropertyStream::Source getValidations() = 0; virtual NodeStore::Database& getNodeStore() = 0; - virtual NodeStore::DatabaseShard* - getShardStore() = 0; - virtual RPC::ShardArchiveHandler* - getShardArchiveHandler(bool tryRecovery = false) = 0; virtual InboundLedgers& getInboundLedgers() = 0; virtual InboundTransactions& diff --git a/src/xrpld/app/main/DBInit.h b/src/xrpld/app/main/DBInit.h index 3d2f42717b2..528f2e8105e 100644 --- a/src/xrpld/app/main/DBInit.h +++ b/src/xrpld/app/main/DBInit.h @@ -124,96 +124,6 @@ inline constexpr std::array TxDBInit{ //////////////////////////////////////////////////////////////////////////////// -// The Ledger Meta database maps ledger hashes to shard indexes -inline constexpr auto LgrMetaDBName{"ledger_meta.db"}; - -// In C++17 omitting the explicit template parameters caused -// a crash -inline constexpr std::array LgrMetaDBPragma -{ - "PRAGMA page_size=4096;", "PRAGMA journal_size_limit=1582080;", - "PRAGMA max_page_count=2147483646;", - -#if (ULONG_MAX > UINT_MAX) && !defined(NO_SQLITE_MMAP) - "PRAGMA mmap_size=17179869184;" -#else - - // Provide an explicit `no-op` SQL statement - // in order to keep the size of the array - // constant regardless of the preprocessor - // condition evaluation - "PRAGMA sqlite_noop_statement;" -#endif -}; - -inline constexpr std::array LgrMetaDBInit{ - {"BEGIN TRANSACTION;", - - "CREATE TABLE IF NOT EXISTS LedgerMeta ( \ - LedgerHash CHARACTER(64) PRIMARY KEY, \ - ShardIndex INTEGER \ - );", - - "END TRANSACTION;"}}; - -//////////////////////////////////////////////////////////////////////////////// - -// Transaction Meta database maps transaction IDs to shard indexes -inline constexpr auto TxMetaDBName{"transaction_meta.db"}; - -// In C++17 omitting the explicit template parameters caused -// a crash -inline constexpr std::array TxMetaDBPragma -{ - "PRAGMA page_size=4096;", "PRAGMA journal_size_limit=1582080;", - "PRAGMA max_page_count=2147483646;", - -#if (ULONG_MAX > UINT_MAX) && !defined(NO_SQLITE_MMAP) - "PRAGMA mmap_size=17179869184;" -#else - - // Provide an explicit `no-op` SQL statement - // in order to keep the size of the array - // constant regardless of the preprocessor - // condition evaluation - "PRAGMA sqlite_noop_statement;" -#endif -}; - -inline constexpr std::array TxMetaDBInit{ - {"BEGIN TRANSACTION;", - - "CREATE TABLE IF NOT EXISTS TransactionMeta ( \ - TransID CHARACTER(64) PRIMARY KEY, \ - ShardIndex INTEGER \ - );", - - "END TRANSACTION;"}}; - -//////////////////////////////////////////////////////////////////////////////// - -// Temporary database used with an incomplete shard that is being acquired -inline constexpr auto AcquireShardDBName{"acquire.db"}; - -inline constexpr std::array AcquireShardDBPragma{ - {"PRAGMA journal_size_limit=1582080;"}}; - -inline constexpr std::array AcquireShardDBInit{ - {"CREATE TABLE IF NOT EXISTS Shard ( \ - ShardIndex INTEGER PRIMARY KEY, \ - LastLedgerHash CHARACTER(64), \ - StoredLedgerSeqs BLOB \ - );"}}; - -//////////////////////////////////////////////////////////////////////////////// - -// Pragma for Ledger and Transaction databases with final shards -// These override the CommonDBPragma values defined above. -inline constexpr std::array FinalShardDBPragma{ - {"PRAGMA synchronous=OFF;", "PRAGMA journal_mode=OFF;"}}; - -//////////////////////////////////////////////////////////////////////////////// - inline constexpr auto WalletDBName{"wallet.db"}; inline constexpr std::array WalletDBInit{ @@ -247,36 +157,6 @@ inline constexpr std::array WalletDBInit{ "END TRANSACTION;"}}; -//////////////////////////////////////////////////////////////////////////////// - -static constexpr auto stateDBName{"state.db"}; - -// These override the CommonDBPragma values defined above. -static constexpr std::array DownloaderDBPragma{ - {"PRAGMA synchronous=FULL;", "PRAGMA journal_mode=DELETE;"}}; - -static constexpr std::array ShardArchiveHandlerDBInit{ - {"BEGIN TRANSACTION;", - - "CREATE TABLE IF NOT EXISTS State ( \ - ShardIndex INTEGER PRIMARY KEY, \ - URL TEXT \ - );", - - "END TRANSACTION;"}}; - -static constexpr std::array DatabaseBodyDBInit{ - {"BEGIN TRANSACTION;", - - "CREATE TABLE IF NOT EXISTS download ( \ - Path TEXT, \ - Data BLOB, \ - Size BIGINT UNSIGNED, \ - Part BIGINT UNSIGNED PRIMARY KEY \ - );", - - "END TRANSACTION;"}}; - } // namespace ripple #endif diff --git a/src/xrpld/app/main/Main.cpp b/src/xrpld/app/main/Main.cpp index 059d9758d39..799911f63dd 100644 --- a/src/xrpld/app/main/Main.cpp +++ b/src/xrpld/app/main/Main.cpp @@ -144,7 +144,6 @@ printHelp(const po::options_description& desc) " consensus_info\n" " deposit_authorized " "[]\n" - " download_shard [[ ]]\n" " feature [ [accept|reject]]\n" " fetch_info [clear]\n" " gateway_balances [] [ [ " @@ -160,7 +159,6 @@ printHelp(const po::options_description& desc) " log_level [[] ]\n" " logrotate\n" " manifest \n" - " node_to_shard [status|start|stop]\n" " peers\n" " ping\n" " random\n" @@ -398,7 +396,6 @@ run(int argc, char** argv) "Load the specified ledger file.")( "load", "Load the current ledger from the local DB.")( "net", "Get the initial ledger from the network.")( - "nodetoshard", "Import node store into shards")( "replay", "Replay a ledger close.")( "trap_tx_hash", po::value(), @@ -676,9 +673,6 @@ run(int argc, char** argv) if (vm.count("import")) config->doImport = true; - if (vm.count("nodetoshard")) - config->nodeToShard = true; - if (vm.count("ledger")) { config->START_LEDGER = vm["ledger"].as(); diff --git a/src/xrpld/app/misc/NetworkOPs.cpp b/src/xrpld/app/misc/NetworkOPs.cpp index 9cf5d097099..a7ee935f102 100644 --- a/src/xrpld/app/misc/NetworkOPs.cpp +++ b/src/xrpld/app/misc/NetworkOPs.cpp @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include @@ -2472,10 +2471,7 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) info[jss::counters] = app_.getPerfLog().countersJson(); Json::Value nodestore(Json::objectValue); - if (app_.getShardStore()) - app_.getShardStore()->getCountsJson(nodestore); - else - app_.getNodeStore().getCountsJson(nodestore); + app_.getNodeStore().getCountsJson(nodestore); info[jss::counters][jss::nodestore] = nodestore; info[jss::current_activities] = app_.getPerfLog().currentJson(); } diff --git a/src/xrpld/app/misc/SHAMapStoreImp.cpp b/src/xrpld/app/misc/SHAMapStoreImp.cpp index d32556a4b29..9344463295b 100644 --- a/src/xrpld/app/misc/SHAMapStoreImp.cpp +++ b/src/xrpld/app/misc/SHAMapStoreImp.cpp @@ -290,8 +290,8 @@ SHAMapStoreImp::run() LedgerIndex lastRotated = state_db_.getState().lastRotated; netOPs_ = &app_.getOPs(); ledgerMaster_ = &app_.getLedgerMaster(); - fullBelowCache_ = &(*app_.getNodeFamily().getFullBelowCache(0)); - treeNodeCache_ = &(*app_.getNodeFamily().getTreeNodeCache(0)); + fullBelowCache_ = &(*app_.getNodeFamily().getFullBelowCache()); + treeNodeCache_ = &(*app_.getNodeFamily().getTreeNodeCache()); if (advisoryDelete_) canDelete_ = state_db_.getCanDelete(); @@ -329,27 +329,8 @@ SHAMapStoreImp::run() validatedSeq >= lastRotated + deleteInterval_ && canDelete_ >= lastRotated - 1 && healthWait() == keepGoing; - // Make sure we don't delete ledgers currently being - // imported into the ShardStore - bool const waitForImport = readyToRotate && [this, lastRotated] { - if (auto shardStore = app_.getShardStore()) - { - if (auto sequence = shardStore->getDatabaseImportSequence()) - return sequence <= lastRotated - 1; - } - - return false; - }(); - - if (waitForImport) - { - JLOG(journal_.info()) - << "NOT rotating validatedSeq " << validatedSeq - << " as rotation would interfere with ShardStore import"; - } - // will delete up to (not including) lastRotated - if (readyToRotate && !waitForImport) + if (readyToRotate) { JLOG(journal_.warn()) << "rotating validatedSeq " << validatedSeq << " lastRotated " diff --git a/src/xrpld/app/rdb/Download.h b/src/xrpld/app/rdb/Download.h deleted file mode 100644 index 6ee02d4c100..00000000000 --- a/src/xrpld/app/rdb/Download.h +++ /dev/null @@ -1,79 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 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_APP_RDB_DOWNLOAD_H_INCLUDED -#define RIPPLE_APP_RDB_DOWNLOAD_H_INCLUDED - -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { - -/** - * @brief openDatabaseBodyDb Opens a database that will store the contents of a - * file being downloaded, returns its descriptor, and starts a new - * download process or continues an existing one. - * @param setup Path to the database and other opening parameters. - * @param path Path of the new file to download. - * @return Pair containing a unique pointer to the database and the amount of - * bytes already downloaded if a download is being continued. - */ -std::pair, std::optional> -openDatabaseBodyDb( - DatabaseCon::Setup const& setup, - boost::filesystem::path const& path); - -/** - * @brief databaseBodyDoPut Saves a new fragment of a downloaded file. - * @param session Session with the database. - * @param data Downloaded fragment of file data to save. - * @param path Path to the file currently being downloaded. - * @param fileSize Size of the portion of the file already downloaded. - * @param part The index of the most recently updated database row. - * @param maxRowSizePad A constant padding value that accounts for other data - * stored in each row of the database. - * @return Index of the most recently updated database row. - */ -std::uint64_t -databaseBodyDoPut( - soci::session& session, - std::string const& data, - std::string const& path, - std::uint64_t fileSize, - std::uint64_t part, - std::uint16_t maxRowSizePad); - -/** - * @brief databaseBodyFinish Finishes the download process and writes the file - * to disk. - * @param session Session with the database. - * @param fout Opened file into which the downloaded data from the database will - * be written. - */ -void -databaseBodyFinish(soci::session& session, std::ofstream& fout); - -} // namespace ripple - -#endif diff --git a/src/xrpld/app/rdb/README.md b/src/xrpld/app/rdb/README.md index 1a68a1ae5e3..f4cb5f203a4 100644 --- a/src/xrpld/app/rdb/README.md +++ b/src/xrpld/app/rdb/README.md @@ -2,9 +2,8 @@ The guiding principles of the Relational Database Interface are summarized below: -* All hard-coded SQL statements should be stored in the [files](#source-files) under the `ripple/app/rdb` directory. With the exception of test modules, no hard-coded SQL should be added to any other file in rippled. +* All hard-coded SQL statements should be stored in the [files](#source-files) under the `xrpld/app/rdb` directory. With the exception of test modules, no hard-coded SQL should be added to any other file in rippled. * The base class `RelationalDatabase` is inherited by derived classes that each provide an interface for operating on distinct relational database systems. -* For future use, the shard store will be used if the node store is absent. ## Overview @@ -12,7 +11,7 @@ Firstly, the interface `RelationalDatabase` is inherited by the classes `SQLiteD ## Configuration -The config section `[relational_db]` has a property named `backend` whose value designates which database implementation will be used for node or shard databases. Presently the only valid value for this property is `sqlite`: +The config section `[relational_db]` has a property named `backend` whose value designates which database implementation will be used for node databases. Presently the only valid value for this property is `sqlite`: ``` [relational_db] @@ -24,35 +23,25 @@ backend=sqlite The Relational Database Interface consists of the following directory structure (as of November 2021): ``` -src/ripple/app/rdb/ +src/xrpld/app/rdb/ ├── backend │   ├── detail -│   │   ├── impl -│   │   │   ├── Node.cpp -│   │   │   └── Shard.cpp +│   │   ├── Node.cpp │   │   ├── Node.h -│   │   └── Shard.h -│   ├── impl │   │   ├── PostgresDatabase.cpp │   │   └── SQLiteDatabase.cpp │   ├── PostgresDatabase.h │   └── SQLiteDatabase.h -├── impl -│   ├── Download.cpp +├── detail │   ├── PeerFinder.cpp │   ├── RelationalDatabase.cpp -│   ├── ShardArchive.cpp │   ├── State.cpp -│   ├── UnitaryShard.cpp │   ├── Vacuum.cpp │   └── Wallet.cpp -├── Download.h ├── PeerFinder.h ├── RelationalDatabase.h ├── README.md -├── ShardArchive.h ├── State.h -├── UnitaryShard.h ├── Vacuum.h └── Wallet.h ``` @@ -61,16 +50,12 @@ src/ripple/app/rdb/ | File | Contents | | ----------- | ----------- | | `Node.[h\|cpp]` | Defines/Implements methods used by `SQLiteDatabase` for interacting with SQLite node databases| -| `Shard.[h\|cpp]` | Defines/Implements methods used by `SQLiteDatabase` for interacting with SQLite shard databases | | `PostgresDatabase.[h\|cpp]` | Defines/Implements the class `PostgresDatabase`/`PostgresDatabaseImp` which inherits from `RelationalDatabase` and is used to operate on the main stores | |`SQLiteDatabase.[h\|cpp]`| Defines/Implements the class `SQLiteDatabase`/`SQLiteDatabaseImp` which inherits from `RelationalDatabase` and is used to operate on the main stores | -| `Download.[h\|cpp]` | Defines/Implements methods for persisting file downloads to a SQLite database | | `PeerFinder.[h\|cpp]` | Defines/Implements methods for interacting with the PeerFinder SQLite database | |`RelationalDatabase.cpp`| Implements the static method `RelationalDatabase::init` which is used to initialize an instance of `RelationalDatabase` | | `RelationalDatabase.h` | Defines the abstract class `RelationalDatabase`, the primary class of the Relational Database Interface | -| `ShardArchive.[h\|cpp]` | Defines/Implements methods used by `ShardArchiveHandler` for interacting with SQLite databases containing metadata regarding shard downloads | | `State.[h\|cpp]` | Defines/Implements methods for interacting with the State SQLite database which concerns ledger deletion and database rotation | -| `UnitaryShard.[h\|cpp]` | Defines/Implements methods used by a unitary instance of `Shard` for interacting with the various SQLite databases thereof. These files are distinct from `Shard.[h\|cpp]` which contain methods used by `SQLiteDatabaseImp` | | `Vacuum.[h\|cpp]` | Defines/Implements a method for performing the `VACUUM` operation on SQLite databases | | `Wallet.[h\|cpp]` | Defines/Implements methods for interacting with Wallet SQLite databases | @@ -84,19 +69,15 @@ The Relational Database Interface provides three categories of methods for inter * Free functions for interacting with SQLite databases used by various components of the software. These methods feature a `soci::session` parameter which facilitates connecting to SQLite databases, and are defined and implemented in the following files: - * `Download.[h\|cpp]` * `PeerFinder.[h\|cpp]` - * `ShardArchive.[h\|cpp]` * `State.[h\|cpp]` - * `UnitaryShard.[h\|cpp]` * `Vacuum.[h\|cpp]` * `Wallet.[h\|cpp]` -* Free functions used exclusively by `SQLiteDatabaseImp` for interacting with SQLite databases owned by the node store or shard store. Unlike the free functions in the files listed above, these are not intended to be invoked directly by clients. Rather, these methods are invoked by derived instances of `RelationalDatabase`. These methods are defined in the following files: +* Free functions used exclusively by `SQLiteDatabaseImp` for interacting with SQLite databases owned by the node store. Unlike the free functions in the files listed above, these are not intended to be invoked directly by clients. Rather, these methods are invoked by derived instances of `RelationalDatabase`. These methods are defined in the following files: * `Node.[h|cpp]` - * `Shard.[h|cpp]` -* Member functions of `RelationalDatabase`, `SQLiteDatabase`, and `PostgresDatabase` which are used to access the main stores (node store, shard store). The `SQLiteDatabase` class will access the node store by default, but will use shard databases if the node store is not present and the shard store is available. The class `PostgresDatabase` uses only the node store. +* Member functions of `RelationalDatabase`, `SQLiteDatabase`, and `PostgresDatabase` which are used to access the node store. diff --git a/src/xrpld/app/rdb/ShardArchive.h b/src/xrpld/app/rdb/ShardArchive.h deleted file mode 100644 index 44f990ab5f5..00000000000 --- a/src/xrpld/app/rdb/ShardArchive.h +++ /dev/null @@ -1,78 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 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_APP_RDB_SHARDARCHIVE_H_INCLUDED -#define RIPPLE_APP_RDB_SHARDARCHIVE_H_INCLUDED - -#include -#include - -namespace ripple { - -/** - * @brief makeArchiveDB Opens the shard archive database and returns its - * descriptor. - * @param dir Path to the database to open. - * @param dbName Name of the database. - * @return Unique pointer to the opened database. - */ -std::unique_ptr -makeArchiveDB(boost::filesystem::path const& dir, std::string const& dbName); - -/** - * @brief readArchiveDB Reads entries from the shard archive database and - * invokes the given callback for each entry. - * @param db Session with the database. - * @param func Callback to invoke for each entry. - */ -void -readArchiveDB( - DatabaseCon& db, - std::function const& func); - -/** - * @brief insertArchiveDB Adds an entry to the shard archive database. - * @param db Session with the database. - * @param shardIndex Shard index to add. - * @param url Shard download url to add. - */ -void -insertArchiveDB( - DatabaseCon& db, - std::uint32_t shardIndex, - std::string const& url); - -/** - * @brief deleteFromArchiveDB Deletes an entry from the shard archive database. - * @param db Session with the database. - * @param shardIndex Shard index to remove from the database. - */ -void -deleteFromArchiveDB(DatabaseCon& db, std::uint32_t shardIndex); - -/** - * @brief dropArchiveDB Removes a table in the shard archive database. - * @param db Session with the database. - */ -void -dropArchiveDB(DatabaseCon& db); - -} // namespace ripple - -#endif diff --git a/src/xrpld/app/rdb/State.h b/src/xrpld/app/rdb/State.h index b245270cda2..e65e9d4d57a 100644 --- a/src/xrpld/app/rdb/State.h +++ b/src/xrpld/app/rdb/State.h @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/src/xrpld/app/rdb/UnitaryShard.h b/src/xrpld/app/rdb/UnitaryShard.h deleted file mode 100644 index e848000221d..00000000000 --- a/src/xrpld/app/rdb/UnitaryShard.h +++ /dev/null @@ -1,155 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 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_APP_RDB_UNITARYSHARD_H_INCLUDED -#define RIPPLE_APP_RDB_UNITARYSHARD_H_INCLUDED - -#include -#include -#include -#include -#include - -namespace ripple { - -struct DatabasePair -{ - std::unique_ptr ledgerDb; - std::unique_ptr transactionDb; -}; - -/** - * @brief makeShardCompleteLedgerDBs Opens shard databases for verified shards - * and returns their descriptors. - * @param config Config object. - * @param setup Path to the databases and other opening parameters. - * @return Pair of unique pointers to the opened ledger and transaction - * databases. - */ -DatabasePair -makeShardCompleteLedgerDBs( - Config const& config, - DatabaseCon::Setup const& setup); - -/** - * @brief makeShardIncompleteLedgerDBs Opens shard databases for partially - * downloaded or unverified shards and returns their descriptors. - * @param config Config object. - * @param setup Path to the databases and other opening parameters. - * @param checkpointerSetup Checkpointer parameters. - * @return Pair of unique pointers to the opened ledger and transaction - * databases. - */ -DatabasePair -makeShardIncompleteLedgerDBs( - Config const& config, - DatabaseCon::Setup const& setup, - DatabaseCon::CheckpointerSetup const& checkpointerSetup); - -/** - * @brief updateLedgerDBs Saves the given ledger to shard databases. - * @param txdb Session with the transaction databases. - * @param lgrdb Session with the ledger databases. - * @param ledger Ledger to save. - * @param index Index of the shard that owns the ledger. - * @param stop Reference to an atomic flag that can stop the process if raised. - * @param j Journal - * @return True if the ledger was successfully saved. - */ -bool -updateLedgerDBs( - soci::session& txdb, - soci::session& lgrdb, - std::shared_ptr const& ledger, - std::uint32_t index, - std::atomic& stop, - beast::Journal j); - -/** - * @brief makeAcquireDB Opens the shard acquire database and returns its - * descriptor. - * @param setup Path to the database and other opening parameters. - * @param checkpointerSetup Checkpointer parameters. - * @return Unique pointer to the opened database. - */ -std::unique_ptr -makeAcquireDB( - DatabaseCon::Setup const& setup, - DatabaseCon::CheckpointerSetup const& checkpointerSetup); - -/** - * @brief insertAcquireDBIndex Adds a new shard index to the shard acquire - * database. - * @param session Session with the database. - * @param index Index to add. - */ -void -insertAcquireDBIndex(soci::session& session, std::uint32_t index); - -/** - * @brief selectAcquireDBLedgerSeqs Returns the set of acquired ledgers for - * the given shard. - * @param session Session with the database. - * @param index Shard index. - * @return Pair which contains true if such an index was found in the database, - * and a string which contains the set of ledger sequences. - * If no sequences were saved then the optional will have no value. - */ -std::pair> -selectAcquireDBLedgerSeqs(soci::session& session, std::uint32_t index); - -struct AcquireShardSeqsHash -{ - std::optional sequences; - std::optional hash; -}; - -/** - * @brief selectAcquireDBLedgerSeqsHash Returns the set of acquired ledger - * sequences and the last ledger hash for the shard with the provided - * index. - * @param session Session with the database. - * @param index Shard index. - * @return Pair which contains true if such an index was found in the database - * and the AcquireShardSeqsHash structure which contains a string with - * the ledger sequences and a string with last ledger hash. If the set - * of sequences or hash were not saved then no value is returned. - */ -std::pair -selectAcquireDBLedgerSeqsHash(soci::session& session, std::uint32_t index); - -/** - * @brief updateAcquireDB Updates information in the acquire DB. - * @param session Session with the database. - * @param ledger Ledger to save into the database. - * @param index Shard index. - * @param lastSeq Last acquired ledger sequence. - * @param seqs Current set of acquired ledger sequences if it's not empty. - */ -void -updateAcquireDB( - soci::session& session, - std::shared_ptr const& ledger, - std::uint32_t index, - std::uint32_t lastSeq, - std::optional const& seqs); - -} // namespace ripple - -#endif diff --git a/src/xrpld/app/rdb/backend/detail/detail/Node.cpp b/src/xrpld/app/rdb/backend/detail/Node.cpp similarity index 93% rename from src/xrpld/app/rdb/backend/detail/detail/Node.cpp rename to src/xrpld/app/rdb/backend/detail/Node.cpp index 67a80b43cf3..70e42b0ae85 100644 --- a/src/xrpld/app/rdb/backend/detail/detail/Node.cpp +++ b/src/xrpld/app/rdb/backend/detail/Node.cpp @@ -622,8 +622,7 @@ getTxHistory( soci::session& session, Application& app, LedgerIndex startIndex, - int quantity, - bool count) + int quantity) { std::string sql = boost::str( boost::format( @@ -663,13 +662,6 @@ getTxHistory( txs.push_back(trans); } } - - if (!total && count) - { - session << "SELECT COUNT(*) FROM Transactions;", soci::into(total); - - total = -total; - } } return {txs, total}; @@ -685,9 +677,6 @@ getTxHistory( * the account, the ledger search range, the offset of the first entry to * return, the number of transactions to return, and a flag if this * number is unlimited. - * @param limit_used Number of transactions already returned in calls - * to other shard databases, if shard databases are used. - * No value if the node database is used. * @param descending True for descending order, false for ascending. * @param binary True for binary form, false for decoded. * @param count True for counting the number of transactions, false for @@ -700,7 +689,6 @@ transactionsSQL( Application& app, std::string selection, RelationalDatabase::AccountTxOptions const& options, - std::optional const& limit_used, bool descending, bool binary, bool count, @@ -729,14 +717,6 @@ transactionsSQL( numberOfResults = options.limit; } - if (limit_used) - { - if (numberOfResults <= *limit_used) - return ""; - else - numberOfResults -= *limit_used; - } - std::string maxClause = ""; std::string minClause = ""; @@ -790,9 +770,6 @@ transactionsSQL( * the account, the ledger search range, the offset of the first entry to * return, the number of transactions to return, and a flag if this * number is unlimited. - * @param limit_used Number of transactions already returned in calls - * to other shard databases, if shard databases are used. - * No value if the node database is used. * @param descending True for descending order, false for ascending. * @param j Journal. * @return Vector of pairs of found transactions and their metadata sorted by @@ -809,7 +786,6 @@ getAccountTxs( Application& app, LedgerMaster& ledgerMaster, RelationalDatabase::AccountTxOptions const& options, - std::optional const& limit_used, bool descending, beast::Journal j) { @@ -819,7 +795,6 @@ getAccountTxs( app, "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta", options, - limit_used, descending, false, false, @@ -880,18 +855,6 @@ getAccountTxs( total++; } } - - if (!total && limit_used) - { - RelationalDatabase::AccountTxOptions opt = options; - opt.offset = 0; - std::string sql1 = transactionsSQL( - app, "COUNT(*)", opt, limit_used, descending, false, false, j); - - session << sql1, soci::into(total); - - total = -total; - } } return {ret, total}; @@ -903,11 +866,9 @@ getOldestAccountTxs( Application& app, LedgerMaster& ledgerMaster, RelationalDatabase::AccountTxOptions const& options, - std::optional const& limit_used, beast::Journal j) { - return getAccountTxs( - session, app, ledgerMaster, options, limit_used, false, j); + return getAccountTxs(session, app, ledgerMaster, options, false, j); } std::pair @@ -916,11 +877,9 @@ getNewestAccountTxs( Application& app, LedgerMaster& ledgerMaster, RelationalDatabase::AccountTxOptions const& options, - std::optional const& limit_used, beast::Journal j) { - return getAccountTxs( - session, app, ledgerMaster, options, limit_used, true, j); + return getAccountTxs(session, app, ledgerMaster, options, true, j); } /** @@ -933,9 +892,6 @@ getNewestAccountTxs( * the account, the ledger search range, the offset of the first entry to * return, the number of transactions to return, and a flag if this * number is unlimited. - * @param limit_used Number of transactions already returned in calls to other - * shard databases, if shard databases are used. No value if the node - * database is used. * @param descending True for descending order, false for ascending. * @param j Journal. * @return Vector of tuples each containing (the found transactions, their @@ -951,7 +907,6 @@ getAccountTxsB( soci::session& session, Application& app, RelationalDatabase::AccountTxOptions const& options, - std::optional const& limit_used, bool descending, beast::Journal j) { @@ -961,7 +916,6 @@ getAccountTxsB( app, "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta", options, - limit_used, descending, true /*binary*/, false, @@ -1001,18 +955,6 @@ getAccountTxsB( ret.emplace_back(std::move(rawTxn), std::move(txnMeta), seq); total++; } - - if (!total && limit_used) - { - RelationalDatabase::AccountTxOptions opt = options; - opt.offset = 0; - std::string sql1 = transactionsSQL( - app, "COUNT(*)", opt, limit_used, descending, true, false, j); - - session << sql1, soci::into(total); - - total = -total; - } } return {ret, total}; @@ -1023,10 +965,9 @@ getOldestAccountTxsB( soci::session& session, Application& app, RelationalDatabase::AccountTxOptions const& options, - std::optional const& limit_used, beast::Journal j) { - return getAccountTxsB(session, app, options, limit_used, false, j); + return getAccountTxsB(session, app, options, false, j); } std::pair, int> @@ -1034,10 +975,9 @@ getNewestAccountTxsB( soci::session& session, Application& app, RelationalDatabase::AccountTxOptions const& options, - std::optional const& limit_used, beast::Journal j) { - return getAccountTxsB(session, app, options, limit_used, true, j); + return getAccountTxsB(session, app, options, true, j); } /** @@ -1052,8 +992,6 @@ getNewestAccountTxsB( * match: the account, the ledger search range, the marker of the first * returned entry, the number of transactions to return, and a flag if * this number unlimited. - * @param limit_used Number of transactions already returned in calls - * to other shard databases. * @param page_length Total number of transactions to return. * @param forward True for ascending order, false for descending. * @return Vector of tuples of found transactions, their metadata and account @@ -1069,7 +1007,6 @@ accountTxPage( void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const& onTransaction, RelationalDatabase::AccountTxPageOptions const& options, - int limit_used, std::uint32_t page_length, bool forward) { @@ -1085,10 +1022,6 @@ accountTxPage( else numberOfResults = options.limit; - if (numberOfResults < limit_used) - return {options.marker, -1}; - numberOfResults -= limit_used; - // As an account can have many thousands of transactions, there is a limit // placed on the amount of transactions returned. If the limit is reached // before the result set has been exhausted (we always query for one more @@ -1104,8 +1037,6 @@ accountTxPage( } std::optional newmarker; - if (limit_used > 0) - newmarker = options.marker; static std::string const prefix( R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq, @@ -1251,17 +1182,10 @@ oldestAccountTxPage( void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const& onTransaction, RelationalDatabase::AccountTxPageOptions const& options, - int limit_used, std::uint32_t page_length) { return accountTxPage( - session, - onUnsavedLedger, - onTransaction, - options, - limit_used, - page_length, - true); + session, onUnsavedLedger, onTransaction, options, page_length, true); } std::pair, int> @@ -1272,17 +1196,10 @@ newestAccountTxPage( void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const& onTransaction, RelationalDatabase::AccountTxPageOptions const& options, - int limit_used, std::uint32_t page_length) { return accountTxPage( - session, - onUnsavedLedger, - onTransaction, - options, - limit_used, - page_length, - false); + session, onUnsavedLedger, onTransaction, options, page_length, false); } std::variant diff --git a/src/xrpld/app/rdb/backend/detail/Node.h b/src/xrpld/app/rdb/backend/detail/Node.h index d7c170663a5..5564adf8954 100644 --- a/src/xrpld/app/rdb/backend/detail/Node.h +++ b/src/xrpld/app/rdb/backend/detail/Node.h @@ -249,7 +249,6 @@ getHashesByIndex( * @param app Application object. * @param startIndex Offset of first returned entry. * @param quantity Number of returned entries. - * @param count True if counting of all transaction in that shard required. * @return Vector of shared pointers to transactions sorted in * descending order by ledger sequence. Also number of transactions * if count == true. @@ -259,8 +258,7 @@ getTxHistory( soci::session& session, Application& app, LedgerIndex startIndex, - int quantity, - bool count); + int quantity); /** * @brief getOldestAccountTxs Returns oldest transactions for given @@ -272,9 +270,6 @@ getTxHistory( * the account, minimum and maximum ledger numbers to search, * offset of first entry to return, number of transactions to return, * flag if this number unlimited. - * @param limit_used Number or transactions already returned in calls - * to another shard databases, if shard databases are used. - * None if node database is used. * @param j Journal. * @return Vector of pairs of found transactions and their metadata * sorted in ascending order by account sequence. @@ -290,7 +285,6 @@ getOldestAccountTxs( Application& app, LedgerMaster& ledgerMaster, RelationalDatabase::AccountTxOptions const& options, - std::optional const& limit_used, beast::Journal j); /** @@ -303,9 +297,6 @@ getOldestAccountTxs( * the account, minimum and maximum ledger numbers to search, * offset of first entry to return, number of transactions to return, * flag if this number unlimited. - * @param limit_used Number or transactions already returned in calls - * to another shard databases, if shard databases are used. - * None if node database is used. * @param j Journal. * @return Vector of pairs of found transactions and their metadata * sorted in descending order by account sequence. @@ -321,7 +312,6 @@ getNewestAccountTxs( Application& app, LedgerMaster& ledgerMaster, RelationalDatabase::AccountTxOptions const& options, - std::optional const& limit_used, beast::Journal j); /** @@ -334,9 +324,6 @@ getNewestAccountTxs( * the account, minimum and maximum ledger numbers to search, * offset of first entry to return, number of transactions to return, * flag if this number unlimited. - * @param limit_used Number or transactions already returned in calls - * to another shard databases, if shard databases are used. - * None if node database is used. * @param j Journal. * @return Vector of tuples of found transactions, their metadata and * account sequences sorted in ascending order by account @@ -351,7 +338,6 @@ getOldestAccountTxsB( soci::session& session, Application& app, RelationalDatabase::AccountTxOptions const& options, - std::optional const& limit_used, beast::Journal j); /** @@ -364,9 +350,6 @@ getOldestAccountTxsB( * the account, minimum and maximum ledger numbers to search, * offset of first entry to return, number of transactions to return, * flag if this number unlimited. - * @param limit_used Number or transactions already returned in calls - * to another shard databases, if shard databases are used. - * None if node database is used. * @param j Journal. * @return Vector of tuples of found transactions, their metadata and * account sequences sorted in descending order by account @@ -381,7 +364,6 @@ getNewestAccountTxsB( soci::session& session, Application& app, RelationalDatabase::AccountTxOptions const& options, - std::optional const& limit_used, beast::Journal j); /** @@ -396,8 +378,6 @@ getNewestAccountTxsB( * match: the account, minimum and maximum ledger numbers to search, * marker of first returned entry, number of transactions to return, * flag if this number unlimited. - * @param limit_used Number or transactions already returned in calls - * to another shard databases. * @param page_length Total number of transactions to return. * @return Vector of tuples of found transactions, their metadata and * account sequences sorted in ascending order by account @@ -412,7 +392,6 @@ oldestAccountTxPage( void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const& onTransaction, RelationalDatabase::AccountTxPageOptions const& options, - int limit_used, std::uint32_t page_length); /** @@ -427,8 +406,6 @@ oldestAccountTxPage( * match: the account, minimum and maximum ledger numbers to search, * marker of first returned entry, number of transactions to return, * flag if this number unlimited. - * @param limit_used Number or transactions already returned in calls - * to another shard databases. * @param page_length Total number of transactions to return. * @return Vector of tuples of found transactions, their metadata and * account sequences sorted in descending order by account @@ -443,7 +420,6 @@ newestAccountTxPage( void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const& onTransaction, RelationalDatabase::AccountTxPageOptions const& options, - int limit_used, std::uint32_t page_length); /** diff --git a/src/xrpld/app/rdb/backend/detail/PostgresDatabase.cpp b/src/xrpld/app/rdb/backend/detail/PostgresDatabase.cpp index ac998991a6d..ac1a9813c2b 100644 --- a/src/xrpld/app/rdb/backend/detail/PostgresDatabase.cpp +++ b/src/xrpld/app/rdb/backend/detail/PostgresDatabase.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include diff --git a/src/xrpld/app/rdb/backend/detail/SQLiteDatabase.cpp b/src/xrpld/app/rdb/backend/detail/SQLiteDatabase.cpp index 3edc5d163d8..bc5992d03d0 100644 --- a/src/xrpld/app/rdb/backend/detail/SQLiteDatabase.cpp +++ b/src/xrpld/app/rdb/backend/detail/SQLiteDatabase.cpp @@ -25,10 +25,8 @@ #include #include #include -#include #include #include -#include #include #include #include @@ -59,19 +57,6 @@ class SQLiteDatabaseImp final : public SQLiteDatabase JLOG(j_.fatal()) << error; Throw(error.data()); } - - if (app.getShardStore() && - !makeMetaDBs( - config, - setup, - DatabaseCon::CheckpointerSetup{&jobQueue, &app_.logs()})) - { - std::string_view constexpr error = - "Failed to create metadata databases"; - - JLOG(j_.fatal()) << error; - Throw(error.data()); - } } std::optional @@ -195,7 +180,6 @@ class SQLiteDatabaseImp final : public SQLiteDatabase bool const useTxTables_; beast::Journal j_; std::unique_ptr lgrdb_, txdb_; - std::unique_ptr lgrMetaDB_, txMetaDB_; /** * @brief makeLedgerDBs Opens ledger and transaction databases for the node @@ -211,56 +195,6 @@ class SQLiteDatabaseImp final : public SQLiteDatabase DatabaseCon::Setup const& setup, DatabaseCon::CheckpointerSetup const& checkpointerSetup); - /** - * @brief makeMetaDBs Opens shard index lookup databases, and stores - * their descriptors in private member variables. - * @param config Config object. - * @param setup Path to the databases and other opening parameters. - * @param checkpointerSetup Checkpointer parameters. - * @return True if node databases opened successfully. - */ - bool - makeMetaDBs( - Config const& config, - DatabaseCon::Setup const& setup, - DatabaseCon::CheckpointerSetup const& checkpointerSetup); - - /** - * @brief seqToShardIndex Provides the index of the shard that stores the - * ledger with the given sequence. - * @param ledgerSeq Ledger sequence. - * @return Shard index. - */ - std::uint32_t - seqToShardIndex(LedgerIndex ledgerSeq) - { - return app_.getShardStore()->seqToShardIndex(ledgerSeq); - } - - /** - * @brief firstLedgerSeq Returns the sequence of the first ledger stored in - * the shard specified by the shard index parameter. - * @param shardIndex Shard Index. - * @return First ledger sequence. - */ - LedgerIndex - firstLedgerSeq(std::uint32_t shardIndex) - { - return app_.getShardStore()->firstLedgerSeq(shardIndex); - } - - /** - * @brief lastLedgerSeq Returns the sequence of the last ledger stored in - * the shard specified by the shard index parameter. - * @param shardIndex Shard Index. - * @return Last ledger sequence. - */ - LedgerIndex - lastLedgerSeq(std::uint32_t shardIndex) - { - return app_.getShardStore()->lastLedgerSeq(shardIndex); - } - /** * @brief existsLedger Checks if the node store ledger database exists. * @return True if the node store ledger database exists. @@ -282,16 +216,6 @@ class SQLiteDatabaseImp final : public SQLiteDatabase return static_cast(txdb_); } - /** - * shardStoreExists Checks whether the shard store exists - * @return True if the shard store exists - */ - bool - shardStoreExists() - { - return app_.getShardStore() != nullptr; - } - /** * @brief checkoutTransaction Checks out and returns node store ledger * database. @@ -313,131 +237,6 @@ class SQLiteDatabaseImp final : public SQLiteDatabase { return txdb_->checkoutDb(); } - - /** - * @brief doLedger Checks out the ledger database owned by the shard - * containing the given ledger, and invokes the provided callback - * with a session to that database. - * @param ledgerSeq Ledger sequence. - * @param callback Callback function to call. - * @return Value returned by callback function. - */ - bool - doLedger( - LedgerIndex ledgerSeq, - std::function const& callback) - { - return app_.getShardStore()->callForLedgerSQLByLedgerSeq( - ledgerSeq, callback); - } - - /** - * @brief doTransaction Checks out the transaction database owned by the - * shard containing the given ledger, and invokes the provided - * callback with a session to that database. - * @param ledgerSeq Ledger sequence. - * @param callback Callback function to call. - * @return Value returned by callback function. - */ - bool - doTransaction( - LedgerIndex ledgerSeq, - std::function const& callback) - { - return app_.getShardStore()->callForTransactionSQLByLedgerSeq( - ledgerSeq, callback); - } - - /** - * @brief iterateLedgerForward Checks out ledger databases for all shards in - * ascending order starting from the given shard index, until all - * shards in range have been visited or the callback returns false. - * For each visited shard, we invoke the provided callback with a - * session to the database and the current shard index. - * @param firstIndex First shard index to visit or no value if all shards - * should be visited. - * @param callback Callback function to call. - * @return True if each callback function returned true, false otherwise. - */ - bool - iterateLedgerForward( - std::optional firstIndex, - std::function< - bool(soci::session& session, std::uint32_t shardIndex)> const& - callback) - { - return app_.getShardStore()->iterateLedgerSQLsForward( - firstIndex, callback); - } - - /** - * @brief iterateTransactionForward Checks out transaction databases for all - * shards in ascending order starting from the given shard index, - * until all shards in range have been visited or the callback - * returns false. For each visited shard, we invoke the provided - * callback with a session to the database and the current shard - * index. - * @param firstIndex First shard index to visit or no value if all shards - * should be visited. - * @param callback Callback function to call. - * @return True if each callback function returned true, false otherwise. - */ - bool - iterateTransactionForward( - std::optional firstIndex, - std::function< - bool(soci::session& session, std::uint32_t shardIndex)> const& - callback) - { - return app_.getShardStore()->iterateLedgerSQLsForward( - firstIndex, callback); - } - - /** - * @brief iterateLedgerBack Checks out ledger databases for all - * shards in descending order starting from the given shard index, - * until all shards in range have been visited or the callback - * returns false. For each visited shard, we invoke the provided - * callback with a session to the database and the current shard - * index. - * @param firstIndex First shard index to visit or no value if all shards - * should be visited. - * @param callback Callback function to call. - * @return True if each callback function returned true, false otherwise. - */ - bool - iterateLedgerBack( - std::optional firstIndex, - std::function< - bool(soci::session& session, std::uint32_t shardIndex)> const& - callback) - { - return app_.getShardStore()->iterateLedgerSQLsBack( - firstIndex, callback); - } - - /** - * @brief iterateTransactionBack Checks out transaction databases for all - * shards in descending order starting from the given shard index, - * until all shards in range have been visited or the callback - * returns false. For each visited shard, we invoke the provided - * callback with a session to the database and the current shard - * index. - * @param firstIndex First shard index to visit or no value if all shards - * should be visited. - * @param callback Callback function to call. - * @return True if each callback function returned true, false otherwise. - */ - bool - iterateTransactionBack( - std::optional firstIndex, - std::function< - bool(soci::session& session, std::uint32_t shardIndex)> const& - callback) - { - return app_.getShardStore()->iterateLedgerSQLsBack( - firstIndex, callback); - } }; bool @@ -453,21 +252,6 @@ SQLiteDatabaseImp::makeLedgerDBs( return res; } -bool -SQLiteDatabaseImp::makeMetaDBs( - Config const& config, - DatabaseCon::Setup const& setup, - DatabaseCon::CheckpointerSetup const& checkpointerSetup) -{ - auto [lgrMetaDB, txMetaDB] = - detail::makeMetaDBs(config, setup, checkpointerSetup); - - txMetaDB_ = std::move(txMetaDB); - lgrMetaDB_ = std::move(lgrMetaDB); - - return true; -} - std::optional SQLiteDatabaseImp::getMinLedgerSeq() { @@ -478,19 +262,6 @@ SQLiteDatabaseImp::getMinLedgerSeq() return detail::getMinLedgerSeq(*db, detail::TableType::Ledgers); } - /* else use shard databases, if available */ - if (shardStoreExists()) - { - std::optional res; - iterateLedgerForward( - {}, [&](soci::session& session, std::uint32_t shardIndex) { - res = detail::getMinLedgerSeq( - session, detail::TableType::Ledgers); - return !res; - }); - return res; - } - /* else return empty value */ return {}; } @@ -507,18 +278,6 @@ SQLiteDatabaseImp::getTransactionsMinLedgerSeq() return detail::getMinLedgerSeq(*db, detail::TableType::Transactions); } - if (shardStoreExists()) - { - std::optional res; - iterateTransactionForward( - {}, [&](soci::session& session, std::uint32_t shardIndex) { - res = detail::getMinLedgerSeq( - session, detail::TableType::Transactions); - return !res; - }); - return res; - } - return {}; } @@ -535,18 +294,6 @@ SQLiteDatabaseImp::getAccountTransactionsMinLedgerSeq() *db, detail::TableType::AccountTransactions); } - if (shardStoreExists()) - { - std::optional res; - iterateTransactionForward( - {}, [&](soci::session& session, std::uint32_t shardIndex) { - res = detail::getMinLedgerSeq( - session, detail::TableType::AccountTransactions); - return !res; - }); - return res; - } - return {}; } @@ -559,18 +306,6 @@ SQLiteDatabaseImp::getMaxLedgerSeq() return detail::getMaxLedgerSeq(*db, detail::TableType::Ledgers); } - if (shardStoreExists()) - { - std::optional res; - iterateLedgerBack( - {}, [&](soci::session& session, std::uint32_t shardIndex) { - res = detail::getMaxLedgerSeq( - session, detail::TableType::Ledgers); - return !res; - }); - return res; - } - return {}; } @@ -587,15 +322,6 @@ SQLiteDatabaseImp::deleteTransactionByLedgerSeq(LedgerIndex ledgerSeq) *db, detail::TableType::Transactions, ledgerSeq); return; } - - if (shardStoreExists()) - { - doTransaction(ledgerSeq, [&](soci::session& session) { - detail::deleteByLedgerSeq( - session, detail::TableType::Transactions, ledgerSeq); - return true; - }); - } } void @@ -608,17 +334,6 @@ SQLiteDatabaseImp::deleteBeforeLedgerSeq(LedgerIndex ledgerSeq) *db, detail::TableType::Ledgers, ledgerSeq); return; } - - if (shardStoreExists()) - { - iterateLedgerBack( - seqToShardIndex(ledgerSeq), - [&](soci::session& session, std::uint32_t shardIndex) { - detail::deleteBeforeLedgerSeq( - session, detail::TableType::Ledgers, ledgerSeq); - return true; - }); - } } void @@ -634,17 +349,6 @@ SQLiteDatabaseImp::deleteTransactionsBeforeLedgerSeq(LedgerIndex ledgerSeq) *db, detail::TableType::Transactions, ledgerSeq); return; } - - if (shardStoreExists()) - { - iterateTransactionBack( - seqToShardIndex(ledgerSeq), - [&](soci::session& session, std::uint32_t shardIndex) { - detail::deleteBeforeLedgerSeq( - session, detail::TableType::Transactions, ledgerSeq); - return true; - }); - } } void @@ -661,17 +365,6 @@ SQLiteDatabaseImp::deleteAccountTransactionsBeforeLedgerSeq( *db, detail::TableType::AccountTransactions, ledgerSeq); return; } - - if (shardStoreExists()) - { - iterateTransactionBack( - seqToShardIndex(ledgerSeq), - [&](soci::session& session, std::uint32_t shardIndex) { - detail::deleteBeforeLedgerSeq( - session, detail::TableType::AccountTransactions, ledgerSeq); - return true; - }); - } } std::size_t @@ -686,18 +379,6 @@ SQLiteDatabaseImp::getTransactionCount() return detail::getRows(*db, detail::TableType::Transactions); } - if (shardStoreExists()) - { - std::size_t rows = 0; - iterateTransactionForward( - {}, [&](soci::session& session, std::uint32_t shardIndex) { - rows += - detail::getRows(session, detail::TableType::Transactions); - return true; - }); - return rows; - } - return 0; } @@ -713,18 +394,6 @@ SQLiteDatabaseImp::getAccountTransactionCount() return detail::getRows(*db, detail::TableType::AccountTransactions); } - if (shardStoreExists()) - { - std::size_t rows = 0; - iterateTransactionForward( - {}, [&](soci::session& session, std::uint32_t shardIndex) { - rows += detail::getRows( - session, detail::TableType::AccountTransactions); - return true; - }); - return rows; - } - return 0; } @@ -737,25 +406,6 @@ SQLiteDatabaseImp::getLedgerCountMinMax() return detail::getRowsMinMax(*db, detail::TableType::Ledgers); } - if (shardStoreExists()) - { - CountMinMax res{0, 0, 0}; - iterateLedgerForward( - {}, [&](soci::session& session, std::uint32_t shardIndex) { - auto r = - detail::getRowsMinMax(session, detail::TableType::Ledgers); - if (r.numberOfRows) - { - res.numberOfRows += r.numberOfRows; - if (res.minLedgerSequence == 0) - res.minLedgerSequence = r.minLedgerSequence; - res.maxLedgerSequence = r.maxLedgerSequence; - } - return true; - }); - return res; - } - return {0, 0, 0}; } @@ -771,27 +421,6 @@ SQLiteDatabaseImp::saveValidatedLedger( return false; } - if (auto shardStore = app_.getShardStore(); shardStore) - { - if (ledger->info().seq < shardStore->earliestLedgerSeq()) - // For the moment return false only when the ShardStore - // should accept the ledger, but fails when attempting - // to do so, i.e. when saveLedgerMeta fails. Later when - // the ShardStore supercedes the NodeStore, change this - // line to return false if the ledger is too early. - return true; - - auto lgrMetaSession = lgrMetaDB_->checkoutDb(); - auto txMetaSession = txMetaDB_->checkoutDb(); - - return detail::saveLedgerMeta( - ledger, - app_, - *lgrMetaSession, - *txMetaSession, - shardStore->seqToShardIndex(ledger->info().seq)); - } - return true; } @@ -807,16 +436,6 @@ SQLiteDatabaseImp::getLedgerInfoByIndex(LedgerIndex ledgerSeq) return res; } - if (shardStoreExists()) - { - std::optional res; - doLedger(ledgerSeq, [&](soci::session& session) { - res = detail::getLedgerInfoByIndex(session, ledgerSeq, j_); - return true; - }); - return res; - } - return {}; } @@ -832,22 +451,6 @@ SQLiteDatabaseImp::getNewestLedgerInfo() return res; } - if (shardStoreExists()) - { - std::optional res; - iterateLedgerBack( - {}, [&](soci::session& session, std::uint32_t shardIndex) { - if (auto info = detail::getNewestLedgerInfo(session, j_)) - { - res = info; - return false; - } - return true; - }); - - return res; - } - return {}; } @@ -864,24 +467,6 @@ SQLiteDatabaseImp::getLimitedOldestLedgerInfo(LedgerIndex ledgerFirstIndex) return res; } - if (shardStoreExists()) - { - std::optional res; - iterateLedgerForward( - seqToShardIndex(ledgerFirstIndex), - [&](soci::session& session, std::uint32_t shardIndex) { - if (auto info = detail::getLimitedOldestLedgerInfo( - session, ledgerFirstIndex, j_)) - { - res = info; - return false; - } - return true; - }); - - return res; - } - return {}; } @@ -898,23 +483,6 @@ SQLiteDatabaseImp::getLimitedNewestLedgerInfo(LedgerIndex ledgerFirstIndex) return res; } - if (shardStoreExists()) - { - std::optional res; - iterateLedgerBack( - {}, [&](soci::session& session, std::uint32_t shardIndex) { - if (auto info = detail::getLimitedNewestLedgerInfo( - session, ledgerFirstIndex, j_)) - { - res = info; - return false; - } - return shardIndex >= seqToShardIndex(ledgerFirstIndex); - }); - - return res; - } - return {}; } @@ -930,24 +498,6 @@ SQLiteDatabaseImp::getLedgerInfoByHash(uint256 const& ledgerHash) return res; } - if (auto shardStore = app_.getShardStore()) - { - std::optional res; - auto lgrMetaSession = lgrMetaDB_->checkoutDb(); - - if (auto const shardIndex = - detail::getShardIndexforLedger(*lgrMetaSession, ledgerHash)) - { - shardStore->callForLedgerSQLByShardIndex( - *shardIndex, [&](soci::session& session) { - res = detail::getLedgerInfoByHash(session, ledgerHash, j_); - return false; // unused - }); - } - - return res; - } - return {}; } @@ -963,16 +513,6 @@ SQLiteDatabaseImp::getHashByIndex(LedgerIndex ledgerIndex) return res; } - if (shardStoreExists()) - { - uint256 hash; - doLedger(ledgerIndex, [&](soci::session& session) { - hash = detail::getHashByIndex(session, ledgerIndex); - return true; - }); - return hash; - } - return uint256(); } @@ -988,16 +528,6 @@ SQLiteDatabaseImp::getHashesByIndex(LedgerIndex ledgerIndex) return res; } - if (shardStoreExists()) - { - std::optional res; - doLedger(ledgerIndex, [&](soci::session& session) { - res = detail::getHashesByIndex(session, ledgerIndex, j_); - return true; - }); - return res; - } - return {}; } @@ -1013,26 +543,6 @@ SQLiteDatabaseImp::getHashesByIndex(LedgerIndex minSeq, LedgerIndex maxSeq) return res; } - if (shardStoreExists()) - { - std::map res; - while (minSeq <= maxSeq) - { - LedgerIndex shardMaxSeq = lastLedgerSeq(seqToShardIndex(minSeq)); - if (shardMaxSeq > maxSeq) - shardMaxSeq = maxSeq; - doLedger(minSeq, [&](soci::session& session) { - auto r = - detail::getHashesByIndex(session, minSeq, shardMaxSeq, j_); - res.insert(r.begin(), r.end()); - return true; - }); - minSeq = shardMaxSeq + 1; - } - - return res; - } - return {}; } @@ -1045,39 +555,12 @@ SQLiteDatabaseImp::getTxHistory(LedgerIndex startIndex) if (existsTransaction()) { auto db = checkoutTransaction(); - auto const res = - detail::getTxHistory(*db, app_, startIndex, 20, false).first; + auto const res = detail::getTxHistory(*db, app_, startIndex, 20).first; if (!res.empty()) return res; } - if (shardStoreExists()) - { - std::vector> txs; - int quantity = 20; - iterateTransactionBack( - {}, [&](soci::session& session, std::uint32_t shardIndex) { - auto [tx, total] = detail::getTxHistory( - session, app_, startIndex, quantity, true); - txs.insert(txs.end(), tx.begin(), tx.end()); - if (total > 0) - { - quantity -= total; - if (quantity <= 0) - return false; - startIndex = 0; - } - else - { - startIndex += total; - } - return true; - }); - - return txs; - } - return {}; } @@ -1092,52 +575,10 @@ SQLiteDatabaseImp::getOldestAccountTxs(AccountTxOptions const& options) if (existsTransaction()) { auto db = checkoutTransaction(); - return detail::getOldestAccountTxs( - *db, app_, ledgerMaster, options, {}, j_) + return detail::getOldestAccountTxs(*db, app_, ledgerMaster, options, j_) .first; } - if (shardStoreExists()) - { - AccountTxs ret; - AccountTxOptions opt = options; - int limit_used = 0; - iterateTransactionForward( - opt.minLedger ? seqToShardIndex(opt.minLedger) - : std::optional(), - [&](soci::session& session, std::uint32_t shardIndex) { - if (opt.maxLedger && - shardIndex > seqToShardIndex(opt.maxLedger)) - return false; - auto [r, total] = detail::getOldestAccountTxs( - session, app_, ledgerMaster, opt, limit_used, j_); - ret.insert(ret.end(), r.begin(), r.end()); - if (!total) - return false; - if (total > 0) - { - limit_used += total; - opt.offset = 0; - } - else - { - /* - * If total < 0, then -total means number of transactions - * skipped, see definition of return value of function - * ripple::getOldestAccountTxs(). - */ - total = -total; - if (opt.offset <= total) - opt.offset = 0; - else - opt.offset -= total; - } - return true; - }); - - return ret; - } - return {}; } @@ -1152,52 +593,10 @@ SQLiteDatabaseImp::getNewestAccountTxs(AccountTxOptions const& options) if (existsTransaction()) { auto db = checkoutTransaction(); - return detail::getNewestAccountTxs( - *db, app_, ledgerMaster, options, {}, j_) + return detail::getNewestAccountTxs(*db, app_, ledgerMaster, options, j_) .first; } - if (shardStoreExists()) - { - AccountTxs ret; - AccountTxOptions opt = options; - int limit_used = 0; - iterateTransactionBack( - opt.maxLedger ? seqToShardIndex(opt.maxLedger) - : std::optional(), - [&](soci::session& session, std::uint32_t shardIndex) { - if (opt.minLedger && - shardIndex < seqToShardIndex(opt.minLedger)) - return false; - auto [r, total] = detail::getNewestAccountTxs( - session, app_, ledgerMaster, opt, limit_used, j_); - ret.insert(ret.end(), r.begin(), r.end()); - if (!total) - return false; - if (total > 0) - { - limit_used += total; - opt.offset = 0; - } - else - { - /* - * If total < 0, then -total means number of transactions - * skipped, see definition of return value of function - * ripple::getNewestAccountTxs(). - */ - total = -total; - if (opt.offset <= total) - opt.offset = 0; - else - opt.offset -= total; - } - return true; - }); - - return ret; - } - return {}; } @@ -1210,48 +609,7 @@ SQLiteDatabaseImp::getOldestAccountTxsB(AccountTxOptions const& options) if (existsTransaction()) { auto db = checkoutTransaction(); - return detail::getOldestAccountTxsB(*db, app_, options, {}, j_).first; - } - - if (shardStoreExists()) - { - MetaTxsList ret; - AccountTxOptions opt = options; - int limit_used = 0; - iterateTransactionForward( - opt.minLedger ? seqToShardIndex(opt.minLedger) - : std::optional(), - [&](soci::session& session, std::uint32_t shardIndex) { - if (opt.maxLedger && - shardIndex > seqToShardIndex(opt.maxLedger)) - return false; - auto [r, total] = detail::getOldestAccountTxsB( - session, app_, opt, limit_used, j_); - ret.insert(ret.end(), r.begin(), r.end()); - if (!total) - return false; - if (total > 0) - { - limit_used += total; - opt.offset = 0; - } - else - { - /* - * If total < 0, then -total means number of transactions - * skipped, see definition of return value of function - * ripple::getOldestAccountTxsB(). - */ - total = -total; - if (opt.offset <= total) - opt.offset = 0; - else - opt.offset -= total; - } - return true; - }); - - return ret; + return detail::getOldestAccountTxsB(*db, app_, options, j_).first; } return {}; @@ -1266,48 +624,7 @@ SQLiteDatabaseImp::getNewestAccountTxsB(AccountTxOptions const& options) if (existsTransaction()) { auto db = checkoutTransaction(); - return detail::getNewestAccountTxsB(*db, app_, options, {}, j_).first; - } - - if (shardStoreExists()) - { - MetaTxsList ret; - AccountTxOptions opt = options; - int limit_used = 0; - iterateTransactionBack( - opt.maxLedger ? seqToShardIndex(opt.maxLedger) - : std::optional(), - [&](soci::session& session, std::uint32_t shardIndex) { - if (opt.minLedger && - shardIndex < seqToShardIndex(opt.minLedger)) - return false; - auto [r, total] = detail::getNewestAccountTxsB( - session, app_, opt, limit_used, j_); - ret.insert(ret.end(), r.begin(), r.end()); - if (!total) - return false; - if (total > 0) - { - limit_used += total; - opt.offset = 0; - } - else - { - /* - * If total < 0, then -total means number of transactions - * skipped, see definition of return value of function - * ripple::getNewestAccountTxsB(). - */ - total = -total; - if (opt.offset <= total) - opt.offset = 0; - else - opt.offset -= total; - } - return true; - }); - - return ret; + return detail::getNewestAccountTxsB(*db, app_, options, j_).first; } return {}; @@ -1339,39 +656,11 @@ SQLiteDatabaseImp::oldestAccountTxPage(AccountTxPageOptions const& options) auto db = checkoutTransaction(); auto newmarker = detail::oldestAccountTxPage( - *db, onUnsavedLedger, onTransaction, options, 0, page_length) + *db, onUnsavedLedger, onTransaction, options, page_length) .first; return {ret, newmarker}; } - if (shardStoreExists()) - { - AccountTxPageOptions opt = options; - int limit_used = 0; - iterateTransactionForward( - opt.minLedger ? seqToShardIndex(opt.minLedger) - : std::optional(), - [&](soci::session& session, std::uint32_t shardIndex) { - if (opt.maxLedger != UINT32_MAX && - shardIndex > seqToShardIndex(opt.minLedger)) - return false; - auto [marker, total] = detail::oldestAccountTxPage( - session, - onUnsavedLedger, - onTransaction, - opt, - limit_used, - page_length); - opt.marker = marker; - if (total < 0) - return false; - limit_used += total; - return true; - }); - - return {ret, opt.marker}; - } - return {}; } @@ -1401,39 +690,11 @@ SQLiteDatabaseImp::newestAccountTxPage(AccountTxPageOptions const& options) auto db = checkoutTransaction(); auto newmarker = detail::newestAccountTxPage( - *db, onUnsavedLedger, onTransaction, options, 0, page_length) + *db, onUnsavedLedger, onTransaction, options, page_length) .first; return {ret, newmarker}; } - if (shardStoreExists()) - { - AccountTxPageOptions opt = options; - int limit_used = 0; - iterateTransactionBack( - opt.maxLedger != UINT32_MAX ? seqToShardIndex(opt.maxLedger) - : std::optional(), - [&](soci::session& session, std::uint32_t shardIndex) { - if (opt.minLedger && - shardIndex < seqToShardIndex(opt.minLedger)) - return false; - auto [marker, total] = detail::newestAccountTxPage( - session, - onUnsavedLedger, - onTransaction, - opt, - limit_used, - page_length); - opt.marker = marker; - if (total < 0) - return false; - limit_used += total; - return true; - }); - - return {ret, opt.marker}; - } - return {}; } @@ -1462,39 +723,11 @@ SQLiteDatabaseImp::oldestAccountTxPageB(AccountTxPageOptions const& options) auto db = checkoutTransaction(); auto newmarker = detail::oldestAccountTxPage( - *db, onUnsavedLedger, onTransaction, options, 0, page_length) + *db, onUnsavedLedger, onTransaction, options, page_length) .first; return {ret, newmarker}; } - if (shardStoreExists()) - { - AccountTxPageOptions opt = options; - int limit_used = 0; - iterateTransactionForward( - opt.minLedger ? seqToShardIndex(opt.minLedger) - : std::optional(), - [&](soci::session& session, std::uint32_t shardIndex) { - if (opt.maxLedger != UINT32_MAX && - shardIndex > seqToShardIndex(opt.minLedger)) - return false; - auto [marker, total] = detail::oldestAccountTxPage( - session, - onUnsavedLedger, - onTransaction, - opt, - limit_used, - page_length); - opt.marker = marker; - if (total < 0) - return false; - limit_used += total; - return true; - }); - - return {ret, opt.marker}; - } - return {}; } @@ -1523,39 +756,11 @@ SQLiteDatabaseImp::newestAccountTxPageB(AccountTxPageOptions const& options) auto db = checkoutTransaction(); auto newmarker = detail::newestAccountTxPage( - *db, onUnsavedLedger, onTransaction, options, 0, page_length) + *db, onUnsavedLedger, onTransaction, options, page_length) .first; return {ret, newmarker}; } - if (shardStoreExists()) - { - AccountTxPageOptions opt = options; - int limit_used = 0; - iterateTransactionBack( - opt.maxLedger != UINT32_MAX ? seqToShardIndex(opt.maxLedger) - : std::optional(), - [&](soci::session& session, std::uint32_t shardIndex) { - if (opt.minLedger && - shardIndex < seqToShardIndex(opt.minLedger)) - return false; - auto [marker, total] = detail::newestAccountTxPage( - session, - onUnsavedLedger, - onTransaction, - opt, - limit_used, - page_length); - opt.marker = marker; - if (total < 0) - return false; - limit_used += total; - return true; - }); - - return {ret, opt.marker}; - } - return {}; } @@ -1574,37 +779,6 @@ SQLiteDatabaseImp::getTransaction( return detail::getTransaction(*db, app_, id, range, ec); } - if (auto shardStore = app_.getShardStore(); shardStore) - { - std::variant res(TxSearched::unknown); - auto txMetaSession = txMetaDB_->checkoutDb(); - - if (auto const shardIndex = - detail::getShardIndexforTransaction(*txMetaSession, id)) - { - shardStore->callForTransactionSQLByShardIndex( - *shardIndex, [&](soci::session& session) { - std::optional> range1; - if (range) - { - std::uint32_t const low = std::max( - range->lower(), firstLedgerSeq(*shardIndex)); - std::uint32_t const high = std::min( - range->upper(), lastLedgerSeq(*shardIndex)); - if (low <= high) - range1 = ClosedInterval(low, high); - } - res = detail::getTransaction(session, app_, id, range1, ec); - - return res.index() == 1 && - std::get(res) != - TxSearched::unknown; // unused - }); - } - - return res; - } - return TxSearched::unknown; } @@ -1617,14 +791,6 @@ SQLiteDatabaseImp::ledgerDbHasSpace(Config const& config) return detail::dbHasSpace(*db, config, j_); } - if (shardStoreExists()) - { - return iterateLedgerBack( - {}, [&](soci::session& session, std::uint32_t shardIndex) { - return detail::dbHasSpace(session, config, j_); - }); - } - return true; } @@ -1640,14 +806,6 @@ SQLiteDatabaseImp::transactionDbHasSpace(Config const& config) return detail::dbHasSpace(*db, config, j_); } - if (shardStoreExists()) - { - return iterateTransactionBack( - {}, [&](soci::session& session, std::uint32_t shardIndex) { - return detail::dbHasSpace(session, config, j_); - }); - } - return true; } @@ -1659,17 +817,6 @@ SQLiteDatabaseImp::getKBUsedAll() return ripple::getKBUsedAll(lgrdb_->getSession()); } - if (shardStoreExists()) - { - std::uint32_t sum = 0; - iterateLedgerBack( - {}, [&](soci::session& session, std::uint32_t shardIndex) { - sum += ripple::getKBUsedAll(session); - return true; - }); - return sum; - } - return 0; } @@ -1681,17 +828,6 @@ SQLiteDatabaseImp::getKBUsedLedger() return ripple::getKBUsedDB(lgrdb_->getSession()); } - if (shardStoreExists()) - { - std::uint32_t sum = 0; - iterateLedgerBack( - {}, [&](soci::session& session, std::uint32_t shardIndex) { - sum += ripple::getKBUsedDB(session); - return true; - }); - return sum; - } - return 0; } @@ -1706,17 +842,6 @@ SQLiteDatabaseImp::getKBUsedTransaction() return ripple::getKBUsedDB(txdb_->getSession()); } - if (shardStoreExists()) - { - std::uint32_t sum = 0; - iterateTransactionBack( - {}, [&](soci::session& session, std::uint32_t shardIndex) { - sum += ripple::getKBUsedDB(session); - return true; - }); - return sum; - } - return 0; } diff --git a/src/xrpld/app/rdb/backend/detail/Shard.h b/src/xrpld/app/rdb/backend/detail/Shard.h deleted file mode 100644 index 870b6b82fe4..00000000000 --- a/src/xrpld/app/rdb/backend/detail/Shard.h +++ /dev/null @@ -1,90 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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_APP_RDB_BACKEND_DETAIL_SHARD_H_INCLUDED -#define RIPPLE_APP_RDB_BACKEND_DETAIL_SHARD_H_INCLUDED - -#include -#include -#include -#include -#include -#include - -namespace ripple { -namespace detail { - -/** - * @brief makeMetaDBs Opens ledger and transaction 'meta' databases which - * map ledger hashes and transaction IDs to the index of the shard - * that holds the ledger or transaction. - * @param config Config object. - * @param setup Path to database and opening parameters. - * @param checkpointerSetup Database checkpointer setup. - * @return Struct DatabasePair which contains unique pointers to the ledger - * and transaction databases. - */ -DatabasePair -makeMetaDBs( - Config const& config, - DatabaseCon::Setup const& setup, - DatabaseCon::CheckpointerSetup const& checkpointerSetup); - -/** - * @brief saveLedgerMeta Stores (transaction ID -> shard index) and - * (ledger hash -> shard index) mappings in the meta databases. - * @param ledger The ledger. - * @param app Application object. - * @param lgrMetaSession Session to ledger meta database. - * @param txnMetaSession Session to transaction meta database. - * @param shardIndex The index of the shard that contains this ledger. - * @return True on success. - */ -bool -saveLedgerMeta( - std::shared_ptr const& ledger, - Application& app, - soci::session& lgrMetaSession, - soci::session& txnMetaSession, - std::uint32_t shardIndex); - -/** - * @brief getShardIndexforLedger Queries the ledger meta database to - * retrieve the index of the shard that contains this ledger. - * @param session Session to the database. - * @param hash Hash of the ledger. - * @return The index of the shard on success, otherwise an unseated value. - */ -std::optional -getShardIndexforLedger(soci::session& session, LedgerHash const& hash); - -/** - * @brief getShardIndexforTransaction Queries the transaction meta database to - * retrieve the index of the shard that contains this transaction. - * @param session Session to the database. - * @param id ID of the transaction. - * @return The index of the shard on success, otherwise an unseated value. - */ -std::optional -getShardIndexforTransaction(soci::session& session, TxID const& id); - -} // namespace detail -} // namespace ripple - -#endif diff --git a/src/xrpld/app/rdb/backend/detail/detail/Shard.cpp b/src/xrpld/app/rdb/backend/detail/detail/Shard.cpp deleted file mode 100644 index 6db64b1249b..00000000000 --- a/src/xrpld/app/rdb/backend/detail/detail/Shard.cpp +++ /dev/null @@ -1,147 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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 -#include -#include -#include -#include -#include -#include - -namespace ripple { -namespace detail { - -DatabasePair -makeMetaDBs( - Config const& config, - DatabaseCon::Setup const& setup, - DatabaseCon::CheckpointerSetup const& checkpointerSetup) -{ - // ledger meta database - auto lgrMetaDB{std::make_unique( - setup, - LgrMetaDBName, - LgrMetaDBPragma, - LgrMetaDBInit, - checkpointerSetup)}; - - if (!config.useTxTables()) - return {std::move(lgrMetaDB), nullptr}; - - // transaction meta database - auto txMetaDB{std::make_unique( - setup, TxMetaDBName, TxMetaDBPragma, TxMetaDBInit, checkpointerSetup)}; - - return {std::move(lgrMetaDB), std::move(txMetaDB)}; -} - -bool -saveLedgerMeta( - std::shared_ptr const& ledger, - Application& app, - soci::session& lgrMetaSession, - soci::session& txnMetaSession, - std::uint32_t const shardIndex) -{ - std::string_view constexpr lgrSQL = - R"sql(INSERT OR REPLACE INTO LedgerMeta VALUES - (:ledgerHash,:shardIndex);)sql"; - - auto const hash = to_string(ledger->info().hash); - lgrMetaSession << lgrSQL, soci::use(hash), soci::use(shardIndex); - - if (!app.config().useTxTables()) - return true; - - auto const aLedger = [&app, ledger]() -> std::shared_ptr { - try - { - auto aLedger = - app.getAcceptedLedgerCache().fetch(ledger->info().hash); - if (!aLedger) - { - aLedger = std::make_shared(ledger, app); - app.getAcceptedLedgerCache().canonicalize_replace_client( - ledger->info().hash, aLedger); - } - - return aLedger; - } - catch (std::exception const&) - { - JLOG(app.journal("Ledger").warn()) - << "An accepted ledger was missing nodes"; - } - - return {}; - }(); - - if (!aLedger) - return false; - - soci::transaction tr(txnMetaSession); - - for (auto const& acceptedLedgerTx : *aLedger) - { - std::string_view constexpr txnSQL = - R"sql(INSERT OR REPLACE INTO TransactionMeta VALUES - (:transactionID,:shardIndex);)sql"; - - auto const transactionID = - to_string(acceptedLedgerTx->getTransactionID()); - - txnMetaSession << txnSQL, soci::use(transactionID), - soci::use(shardIndex); - } - - tr.commit(); - return true; -} - -std::optional -getShardIndexforLedger(soci::session& session, LedgerHash const& hash) -{ - std::uint32_t shardIndex; - session << "SELECT ShardIndex FROM LedgerMeta WHERE LedgerHash = '" << hash - << "';", - soci::into(shardIndex); - - if (!session.got_data()) - return std::nullopt; - - return shardIndex; -} - -std::optional -getShardIndexforTransaction(soci::session& session, TxID const& id) -{ - std::uint32_t shardIndex; - session << "SELECT ShardIndex FROM TransactionMeta WHERE TransID = '" << id - << "';", - soci::into(shardIndex); - - if (!session.got_data()) - return std::nullopt; - - return shardIndex; -} - -} // namespace detail -} // namespace ripple diff --git a/src/xrpld/app/rdb/detail/Download.cpp b/src/xrpld/app/rdb/detail/Download.cpp deleted file mode 100644 index 012d60b3734..00000000000 --- a/src/xrpld/app/rdb/detail/Download.cpp +++ /dev/null @@ -1,152 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 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 -#include - -namespace ripple { - -std::pair, std::optional> -openDatabaseBodyDb( - DatabaseCon::Setup const& setup, - boost::filesystem::path const& path) -{ - // SOCI requires boost::optional (not std::optional) as the parameter. - boost::optional pathFromDb; - boost::optional size; - - auto conn = std::make_unique( - setup, "Download", DownloaderDBPragma, DatabaseBodyDBInit); - - auto& session = *conn->checkoutDb(); - - session << "SELECT Path FROM Download WHERE Part=0;", - soci::into(pathFromDb); - - // Try to reuse preexisting - // database. - if (pathFromDb) - { - // Can't resuse - database was - // from a different file download. - if (pathFromDb != path.string()) - { - session << "DROP TABLE Download;"; - } - - // Continuing a file download. - else - { - session << "SELECT SUM(LENGTH(Data)) FROM Download;", - soci::into(size); - } - } - - return {std::move(conn), (size ? *size : std::optional())}; -} - -std::uint64_t -databaseBodyDoPut( - soci::session& session, - std::string const& data, - std::string const& path, - std::uint64_t fileSize, - std::uint64_t part, - std::uint16_t maxRowSizePad) -{ - std::uint64_t rowSize = 0; - soci::indicator rti; - - std::uint64_t remainingInRow = 0; - - auto be = - dynamic_cast(session.get_backend()); - BOOST_ASSERT(be); - - // This limits how large we can make the blob - // in each row. Also subtract a pad value to - // account for the other values in the row. - auto const blobMaxSize = - sqlite_api::sqlite3_limit(be->conn_, SQLITE_LIMIT_LENGTH, -1) - - maxRowSizePad; - - std::string newpath; - - auto rowInit = [&] { - session << "INSERT INTO Download VALUES (:path, zeroblob(0), 0, :part)", - soci::use(newpath), soci::use(part); - - remainingInRow = blobMaxSize; - rowSize = 0; - }; - - session << "SELECT Path,Size,Part FROM Download ORDER BY Part DESC " - "LIMIT 1", - soci::into(newpath), soci::into(rowSize), soci::into(part, rti); - - if (!session.got_data()) - { - newpath = path; - rowInit(); - } - else - remainingInRow = blobMaxSize - rowSize; - - auto insert = [&session, &rowSize, &part, &fs = fileSize]( - auto const& data) { - std::uint64_t updatedSize = rowSize + data.size(); - - session << "UPDATE Download SET Data = CAST(Data || :data AS blob), " - "Size = :size WHERE Part = :part;", - soci::use(data), soci::use(updatedSize), soci::use(part); - - fs += data.size(); - }; - - size_t currentBase = 0; - - while (currentBase + remainingInRow < data.size()) - { - if (remainingInRow) - { - insert(data.substr(currentBase, remainingInRow)); - currentBase += remainingInRow; - } - - ++part; - rowInit(); - } - - insert(data.substr(currentBase)); - - return part; -} - -void -databaseBodyFinish(soci::session& session, std::ofstream& fout) -{ - soci::rowset rs = - (session.prepare << "SELECT Data FROM Download ORDER BY PART ASC;"); - - // iteration through the resultset: - for (auto it = rs.begin(); it != rs.end(); ++it) - fout.write(it->data(), it->size()); -} - -} // namespace ripple diff --git a/src/xrpld/app/rdb/detail/RelationalDatabase.cpp b/src/xrpld/app/rdb/detail/RelationalDatabase.cpp index 874550abd97..07dc27fd1d3 100644 --- a/src/xrpld/app/rdb/detail/RelationalDatabase.cpp +++ b/src/xrpld/app/rdb/detail/RelationalDatabase.cpp @@ -20,7 +20,6 @@ #include #include #include -#include namespace ripple { diff --git a/src/xrpld/app/rdb/detail/ShardArchive.cpp b/src/xrpld/app/rdb/detail/ShardArchive.cpp deleted file mode 100644 index 81b99348cb4..00000000000 --- a/src/xrpld/app/rdb/detail/ShardArchive.cpp +++ /dev/null @@ -1,68 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 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 - -namespace ripple { - -std::unique_ptr -makeArchiveDB(boost::filesystem::path const& dir, std::string const& dbName) -{ - return std::make_unique( - dir, dbName, DownloaderDBPragma, ShardArchiveHandlerDBInit); -} - -void -readArchiveDB( - DatabaseCon& db, - std::function const& func) -{ - soci::rowset rs = - (db.getSession().prepare << "SELECT * FROM State;"); - - for (auto it = rs.begin(); it != rs.end(); ++it) - { - func(it->get(1), it->get(0)); - } -} - -void -insertArchiveDB( - DatabaseCon& db, - std::uint32_t shardIndex, - std::string const& url) -{ - db.getSession() << "INSERT INTO State VALUES (:index, :url);", - soci::use(shardIndex), soci::use(url); -} - -void -deleteFromArchiveDB(DatabaseCon& db, std::uint32_t shardIndex) -{ - db.getSession() << "DELETE FROM State WHERE ShardIndex = :index;", - soci::use(shardIndex); -} - -void -dropArchiveDB(DatabaseCon& db) -{ - db.getSession() << "DROP TABLE State;"; -} - -} // namespace ripple diff --git a/src/xrpld/app/rdb/detail/UnitaryShard.cpp b/src/xrpld/app/rdb/detail/UnitaryShard.cpp deleted file mode 100644 index dd64759f4a8..00000000000 --- a/src/xrpld/app/rdb/detail/UnitaryShard.cpp +++ /dev/null @@ -1,320 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 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 -#include -#include -#include - -namespace ripple { - -DatabasePair -makeShardCompleteLedgerDBs( - Config const& config, - DatabaseCon::Setup const& setup) -{ - auto tx{std::make_unique( - setup, TxDBName, FinalShardDBPragma, TxDBInit)}; - tx->getSession() << boost::str( - boost::format("PRAGMA cache_size=-%d;") % - kilobytes(config.getValueFor(SizedItem::txnDBCache, std::nullopt))); - - auto lgr{std::make_unique( - setup, LgrDBName, FinalShardDBPragma, LgrDBInit)}; - lgr->getSession() << boost::str( - boost::format("PRAGMA cache_size=-%d;") % - kilobytes(config.getValueFor(SizedItem::lgrDBCache, std::nullopt))); - - return {std::move(lgr), std::move(tx)}; -} - -DatabasePair -makeShardIncompleteLedgerDBs( - Config const& config, - DatabaseCon::Setup const& setup, - DatabaseCon::CheckpointerSetup const& checkpointerSetup) -{ - // transaction database - auto tx{std::make_unique( - setup, TxDBName, TxDBPragma, TxDBInit, checkpointerSetup)}; - tx->getSession() << boost::str( - boost::format("PRAGMA cache_size=-%d;") % - kilobytes(config.getValueFor(SizedItem::txnDBCache))); - - // ledger database - auto lgr{std::make_unique( - setup, LgrDBName, LgrDBPragma, LgrDBInit, checkpointerSetup)}; - lgr->getSession() << boost::str( - boost::format("PRAGMA cache_size=-%d;") % - kilobytes(config.getValueFor(SizedItem::lgrDBCache))); - - return {std::move(lgr), std::move(tx)}; -} - -bool -updateLedgerDBs( - soci::session& txsession, - soci::session& lgrsession, - std::shared_ptr const& ledger, - std::uint32_t index, - std::atomic& stop, - beast::Journal j) -{ - auto const ledgerSeq{ledger->info().seq}; - - // Update the transactions database - { - auto& session{txsession}; - soci::transaction tr(session); - - session << "DELETE FROM Transactions " - "WHERE LedgerSeq = :seq;", - soci::use(ledgerSeq); - session << "DELETE FROM AccountTransactions " - "WHERE LedgerSeq = :seq;", - soci::use(ledgerSeq); - - if (ledger->info().txHash.isNonZero()) - { - auto const sSeq{std::to_string(ledgerSeq)}; - if (!ledger->txMap().isValid()) - { - JLOG(j.error()) - << "shard " << index << " has an invalid transaction map" - << " on sequence " << sSeq; - return false; - } - - for (auto const& item : ledger->txs) - { - if (stop.load(std::memory_order_relaxed)) - return false; - - TxMeta const txMeta{ - item.first->getTransactionID(), - ledger->seq(), - *item.second}; - - auto const sTxID = to_string(txMeta.getTxID()); - - session << "DELETE FROM AccountTransactions " - "WHERE TransID = :txID;", - soci::use(sTxID); - - auto const& accounts = txMeta.getAffectedAccounts(); - if (!accounts.empty()) - { - auto const sTxnSeq{std::to_string(txMeta.getIndex())}; - auto const s{boost::str( - boost::format("('%s','%s',%s,%s)") % sTxID % "%s" % - sSeq % sTxnSeq)}; - std::string sql; - sql.reserve((accounts.size() + 1) * 128); - sql = - "INSERT INTO AccountTransactions " - "(TransID, Account, LedgerSeq, TxnSeq) VALUES "; - sql += boost::algorithm::join( - accounts | - boost::adaptors::transformed( - [&](AccountID const& accountID) { - return boost::str( - boost::format(s) % - ripple::toBase58(accountID)); - }), - ","); - sql += ';'; - session << sql; - - JLOG(j.trace()) - << "shard " << index << " account transaction: " << sql; - } - else if (!isPseudoTx(*item.first)) - { - // It's okay for pseudo transactions to not affect any - // accounts. But otherwise... - JLOG(j.warn()) - << "shard " << index << " transaction in ledger " - << sSeq << " affects no accounts"; - } - - Serializer s; - item.second->add(s); - session - << (STTx::getMetaSQLInsertReplaceHeader() + - item.first->getMetaSQL( - ledgerSeq, sqlBlobLiteral(s.modData())) + - ';'); - } - } - - tr.commit(); - } - - auto const sHash{to_string(ledger->info().hash)}; - - // Update the ledger database - { - auto& session{lgrsession}; - soci::transaction tr(session); - - auto const sParentHash{to_string(ledger->info().parentHash)}; - auto const sDrops{to_string(ledger->info().drops)}; - auto const closingTime{ - ledger->info().closeTime.time_since_epoch().count()}; - auto const prevClosingTime{ - ledger->info().parentCloseTime.time_since_epoch().count()}; - auto const closeTimeRes{ledger->info().closeTimeResolution.count()}; - auto const sAccountHash{to_string(ledger->info().accountHash)}; - auto const sTxHash{to_string(ledger->info().txHash)}; - - session << "DELETE FROM Ledgers " - "WHERE LedgerSeq = :seq;", - soci::use(ledgerSeq); - session << "INSERT OR REPLACE INTO Ledgers (" - "LedgerHash, LedgerSeq, PrevHash, TotalCoins, ClosingTime," - "PrevClosingTime, CloseTimeRes, CloseFlags, AccountSetHash," - "TransSetHash)" - "VALUES (" - ":ledgerHash, :ledgerSeq, :prevHash, :totalCoins," - ":closingTime, :prevClosingTime, :closeTimeRes," - ":closeFlags, :accountSetHash, :transSetHash);", - soci::use(sHash), soci::use(ledgerSeq), soci::use(sParentHash), - soci::use(sDrops), soci::use(closingTime), - soci::use(prevClosingTime), soci::use(closeTimeRes), - soci::use(ledger->info().closeFlags), soci::use(sAccountHash), - soci::use(sTxHash); - - tr.commit(); - } - - return true; -} - -std::unique_ptr -makeAcquireDB( - DatabaseCon::Setup const& setup, - DatabaseCon::CheckpointerSetup const& checkpointerSetup) -{ - return std::make_unique( - setup, - AcquireShardDBName, - AcquireShardDBPragma, - AcquireShardDBInit, - checkpointerSetup); -} - -void -insertAcquireDBIndex(soci::session& session, std::uint32_t index) -{ - session << "INSERT INTO Shard (ShardIndex) " - "VALUES (:shardIndex);", - soci::use(index); -} - -std::pair> -selectAcquireDBLedgerSeqs(soci::session& session, std::uint32_t index) -{ - // resIndex and must be boost::optional (not std) because that's - // what SOCI expects in its interface. - boost::optional resIndex; - soci::blob sociBlob(session); - soci::indicator blobPresent; - - session << "SELECT ShardIndex, StoredLedgerSeqs " - "FROM Shard " - "WHERE ShardIndex = :index;", - soci::into(resIndex), soci::into(sociBlob, blobPresent), - soci::use(index); - - if (!resIndex || index != resIndex) - return {false, {}}; - - if (blobPresent != soci::i_ok) - return {true, {}}; - - std::string s; - convert(sociBlob, s); - - return {true, s}; -} - -std::pair -selectAcquireDBLedgerSeqsHash(soci::session& session, std::uint32_t index) -{ - // resIndex and sHash0 must be boost::optional (not std) because that's - // what SOCI expects in its interface. - boost::optional resIndex; - boost::optional sHash0; - soci::blob sociBlob(session); - soci::indicator blobPresent; - - session << "SELECT ShardIndex, LastLedgerHash, StoredLedgerSeqs " - "FROM Shard " - "WHERE ShardIndex = :index;", - soci::into(resIndex), soci::into(sHash0), - soci::into(sociBlob, blobPresent), soci::use(index); - - std::optional sHash = - (sHash0 ? *sHash0 : std::optional()); - - if (!resIndex || index != resIndex) - return {false, {{}, {}}}; - - if (blobPresent != soci::i_ok) - return {true, {{}, sHash}}; - - std::string s; - convert(sociBlob, s); - - return {true, {s, sHash}}; -} - -void -updateAcquireDB( - soci::session& session, - std::shared_ptr const& ledger, - std::uint32_t index, - std::uint32_t lastSeq, - std::optional const& seqs) -{ - soci::blob sociBlob(session); - auto const sHash{to_string(ledger->info().hash)}; - - if (seqs) - convert(*seqs, sociBlob); - - if (ledger->info().seq == lastSeq) - { - // Store shard's last ledger hash - session << "UPDATE Shard " - "SET LastLedgerHash = :lastLedgerHash," - "StoredLedgerSeqs = :storedLedgerSeqs " - "WHERE ShardIndex = :shardIndex;", - soci::use(sHash), soci::use(sociBlob), soci::use(index); - } - else - { - session << "UPDATE Shard " - "SET StoredLedgerSeqs = :storedLedgerSeqs " - "WHERE ShardIndex = :shardIndex;", - soci::use(sociBlob), soci::use(index); - } -} - -} // namespace ripple diff --git a/src/xrpld/core/Config.h b/src/xrpld/core/Config.h index 2872193f0ee..e63e6d2f356 100644 --- a/src/xrpld/core/Config.h +++ b/src/xrpld/core/Config.h @@ -146,7 +146,6 @@ class Config : public BasicConfig public: bool doImport = false; - bool nodeToShard = false; bool ELB_SUPPORT = false; // Entries from [ips] config stanza diff --git a/src/xrpld/core/ConfigSections.h b/src/xrpld/core/ConfigSections.h index b4e460f1cfc..8685d29a4d0 100644 --- a/src/xrpld/core/ConfigSections.h +++ b/src/xrpld/core/ConfigSections.h @@ -35,11 +35,6 @@ struct ConfigSection return "node_db"; } static std::string - shardDatabase() - { - return "shard_db"; - } - static std::string importNodeDatabase() { return "import_db"; @@ -56,7 +51,6 @@ struct ConfigSection #define SECTION_ELB_SUPPORT "elb_support" #define SECTION_FEE_DEFAULT "fee_default" #define SECTION_FETCH_DEPTH "fetch_depth" -#define SECTION_HISTORICAL_SHARD_PATHS "historical_shard_paths" #define SECTION_INSIGHT "insight" #define SECTION_IO_WORKERS "io_workers" #define SECTION_IPS "ips" diff --git a/src/xrpld/core/Job.h b/src/xrpld/core/Job.h index c5926ae2e08..76d26c39e72 100644 --- a/src/xrpld/core/Job.h +++ b/src/xrpld/core/Job.h @@ -47,7 +47,6 @@ enum JobType { jtCLIENT_FEE_CHANGE, // Subscription for fee change by a client jtCLIENT_CONSENSUS, // Subscription for consensus state change by a client jtCLIENT_ACCT_HIST, // Subscription for account history by a client - jtCLIENT_SHARD, // Client request for shard archiving jtCLIENT_RPC, // Client RPC request jtCLIENT_WEBSOCKET, // Client websocket request jtRPC, // A websocket command from the client diff --git a/src/xrpld/core/JobTypes.h b/src/xrpld/core/JobTypes.h index 2dbc45ca1b5..3b41ce7ff47 100644 --- a/src/xrpld/core/JobTypes.h +++ b/src/xrpld/core/JobTypes.h @@ -84,7 +84,6 @@ class JobTypes add(jtCLIENT_FEE_CHANGE, "clientFeeChange", maxLimit, 2000ms, 5000ms); add(jtCLIENT_CONSENSUS, "clientConsensus", maxLimit, 2000ms, 5000ms); add(jtCLIENT_ACCT_HIST, "clientAccountHistory", maxLimit, 2000ms, 5000ms); - add(jtCLIENT_SHARD, "clientShardArchive", maxLimit, 2000ms, 5000ms); add(jtCLIENT_RPC, "clientRPC", maxLimit, 2000ms, 5000ms); add(jtCLIENT_WEBSOCKET, "clientWebsocket", maxLimit, 2000ms, 5000ms); add(jtRPC, "RPC", maxLimit, 0ms, 0ms); diff --git a/src/xrpld/net/DatabaseBody.h b/src/xrpld/net/DatabaseBody.h deleted file mode 100644 index 15780ced313..00000000000 --- a/src/xrpld/net/DatabaseBody.h +++ /dev/null @@ -1,179 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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_NET_DATABASEBODY_H -#define RIPPLE_NET_DATABASEBODY_H - -#include -#include -#include -#include -#include - -namespace ripple { - -// DatabaseBody needs to meet requirements -// from asio which is why some conventions -// used elsewhere in this code base are not -// followed. -struct DatabaseBody -{ - // Algorithm for storing buffers when parsing. - class reader; - - // The type of the @ref message::body member. - class value_type; - - /** Returns the size of the body - - @param body The database body to use - */ - static std::uint64_t - size(value_type const& body); -}; - -class DatabaseBody::value_type -{ - // This body container holds a connection to the - // database, and also caches the size when set. - - friend class reader; - friend struct DatabaseBody; - - // The cached file size - std::uint64_t fileSize_ = 0; - boost::filesystem::path path_; - std::unique_ptr conn_; - std::string batch_; - std::shared_ptr strand_; - std::mutex m_; - std::condition_variable c_; - std::uint64_t handlerCount_ = 0; - std::uint64_t part_ = 0; - bool closing_ = false; - -public: - /// Destructor - ~value_type() = default; - - /// Constructor - value_type() = default; - - /// Returns `true` if the file is open - bool - is_open() const - { - return static_cast(conn_); - } - - /// Returns the size of the file if open - std::uint64_t - size() const - { - return fileSize_; - } - - /// Close the file if open - void - close(); - - /** Open a file at the given path with the specified mode - - @param path The utf-8 encoded path to the file - - @param config The configuration settings - - @param io_service The asio context for running a strand. - - @param ec Set to the error, if any occurred - */ - void - open( - boost::filesystem::path const& path, - Config const& config, - boost::asio::io_service& io_service, - boost::system::error_code& ec); -}; - -/** Algorithm for storing buffers when parsing. - - Objects of this type are created during parsing - to store incoming buffers representing the body. -*/ -class DatabaseBody::reader -{ - value_type& body_; // The body we are writing to - - static constexpr std::uint32_t FLUSH_SIZE = 50000000; - static constexpr std::uint8_t MAX_HANDLERS = 3; - static constexpr std::uint16_t MAX_ROW_SIZE_PAD = 500; - -public: - // Constructor. - // - // This is called after the header is parsed and - // indicates that a non-zero sized body may be present. - // `h` holds the received message headers. - // `b` is an instance of `DatabaseBody`. - // - template - explicit reader( - boost::beast::http::header& h, - value_type& b); - - // Initializer - // - // This is called before the body is parsed and - // gives the reader a chance to do something that might - // need to return an error code. It informs us of - // the payload size (`content_length`) which we can - // optionally use for optimization. - // - // Note: boost::Beast calls init() and requires a - // boost::optional (not a std::optional) as the - // parameter. - void - init(boost::optional const&, boost::system::error_code& ec); - - // This function is called one or more times to store - // buffer sequences corresponding to the incoming body. - // - template - std::size_t - put(ConstBufferSequence const& buffers, boost::system::error_code& ec); - - void - do_put(std::string const& data); - - // This function is called when writing is complete. - // It is an opportunity to perform any final actions - // which might fail, in order to return an error code. - // Operations that might fail should not be attempted in - // destructors, since an exception thrown from there - // would terminate the program. - // - void - finish(boost::system::error_code& ec); -}; - -} // namespace ripple - -#include - -#endif // RIPPLE_NET_DATABASEBODY_H diff --git a/src/xrpld/net/DatabaseDownloader.h b/src/xrpld/net/DatabaseDownloader.h deleted file mode 100644 index 490e7c62e16..00000000000 --- a/src/xrpld/net/DatabaseDownloader.h +++ /dev/null @@ -1,76 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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_NET_DATABASEDOWNLOADER_H -#define RIPPLE_NET_DATABASEDOWNLOADER_H - -#include -#include - -namespace ripple { - -class DatabaseDownloader : public HTTPDownloader -{ -public: - virtual ~DatabaseDownloader() = default; - -private: - DatabaseDownloader( - boost::asio::io_service& io_service, - Config const& config, - beast::Journal j); - - static const std::uint8_t MAX_PATH_LEN = - std::numeric_limits::max(); - - std::shared_ptr - getParser( - boost::filesystem::path dstPath, - std::function complete, - boost::system::error_code& ec) override; - - bool - checkPath(boost::filesystem::path const& dstPath) override; - - void - closeBody(std::shared_ptr p) override; - - std::uint64_t - size(std::shared_ptr p) override; - - Config const& config_; - boost::asio::io_service& io_service_; - - friend std::shared_ptr - make_DatabaseDownloader( - boost::asio::io_service& io_service, - Config const& config, - beast::Journal j); -}; - -// DatabaseDownloader must be a shared_ptr because it uses shared_from_this -std::shared_ptr -make_DatabaseDownloader( - boost::asio::io_service& io_service, - Config const& config, - beast::Journal j); - -} // namespace ripple - -#endif // RIPPLE_NET_DATABASEDOWNLOADER_H diff --git a/src/xrpld/net/HTTPDownloader.h b/src/xrpld/net/HTTPDownloader.h deleted file mode 100644 index f96fb8e572b..00000000000 --- a/src/xrpld/net/HTTPDownloader.h +++ /dev/null @@ -1,130 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2018 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_NET_HTTPDOWNLOADER_H_INCLUDED -#define RIPPLE_NET_HTTPDOWNLOADER_H_INCLUDED - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace ripple { - -/** Provides an asynchronous HTTP[S] file downloader - */ -class HTTPDownloader : public std::enable_shared_from_this -{ -public: - using error_code = boost::system::error_code; - - bool - download( - std::string const& host, - std::string const& port, - std::string const& target, - int version, - boost::filesystem::path const& dstPath, - std::function complete, - bool ssl = true); - - void - stop(); - - virtual ~HTTPDownloader() = default; - - bool - sessionIsActive() const; - - bool - isStopping() const; - -protected: - // must be accessed through a shared_ptr - // use make_XXX functions to create - HTTPDownloader( - boost::asio::io_service& io_service, - Config const& config, - beast::Journal j); - - using parser = boost::beast::http::basic_parser; - - beast::Journal const j_; - - void - fail( - boost::filesystem::path dstPath, - boost::system::error_code const& ec, - std::string const& errMsg, - std::shared_ptr parser); - -private: - Config const& config_; - boost::asio::io_service::strand strand_; - std::unique_ptr stream_; - boost::beast::flat_buffer read_buf_; - std::atomic stop_; - - // Used to protect sessionActive_ - mutable std::mutex m_; - bool sessionActive_; - std::condition_variable c_; - - void - do_session( - std::string host, - std::string port, - std::string target, - int version, - boost::filesystem::path dstPath, - std::function complete, - bool ssl, - boost::asio::yield_context yield); - - virtual std::shared_ptr - getParser( - boost::filesystem::path dstPath, - std::function complete, - boost::system::error_code& ec) = 0; - - virtual bool - checkPath(boost::filesystem::path const& dstPath) = 0; - - virtual void - closeBody(std::shared_ptr p) = 0; - - virtual uint64_t - size(std::shared_ptr p) = 0; -}; - -} // namespace ripple - -#endif diff --git a/src/xrpld/net/HTTPStream.h b/src/xrpld/net/HTTPStream.h deleted file mode 100644 index 275d8ca9544..00000000000 --- a/src/xrpld/net/HTTPStream.h +++ /dev/null @@ -1,165 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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_NET_HTTPSTREAM_H_INCLUDED -#define RIPPLE_NET_HTTPSTREAM_H_INCLUDED - -#include -#include - -#include -#include -#include -#include - -#include - -namespace ripple { - -class HTTPStream -{ -public: - using request = boost::beast::http::request; - using parser = boost::beast::http::basic_parser; - - virtual ~HTTPStream() = default; - - [[nodiscard]] virtual boost::asio::ip::tcp::socket& - getStream() = 0; - - [[nodiscard]] virtual bool - connect( - std::string& errorOut, - std::string const& host, - std::string const& port, - boost::asio::yield_context& yield) = 0; - - virtual void - asyncWrite( - request& req, - boost::asio::yield_context& yield, - boost::system::error_code& ec) = 0; - - virtual void - asyncRead( - boost::beast::flat_buffer& buf, - parser& p, - boost::asio::yield_context& yield, - boost::system::error_code& ec) = 0; - - virtual void - asyncReadSome( - boost::beast::flat_buffer& buf, - parser& p, - boost::asio::yield_context& yield, - boost::system::error_code& ec) = 0; -}; - -class SSLStream : public HTTPStream -{ -public: - SSLStream( - Config const& config, - boost::asio::io_service::strand& strand, - beast::Journal j); - - virtual ~SSLStream() = default; - - boost::asio::ip::tcp::socket& - getStream() override; - - bool - connect( - std::string& errorOut, - std::string const& host, - std::string const& port, - boost::asio::yield_context& yield) override; - - void - asyncWrite( - request& req, - boost::asio::yield_context& yield, - boost::system::error_code& ec) override; - - void - asyncRead( - boost::beast::flat_buffer& buf, - parser& p, - boost::asio::yield_context& yield, - boost::system::error_code& ec) override; - - void - asyncReadSome( - boost::beast::flat_buffer& buf, - parser& p, - boost::asio::yield_context& yield, - boost::system::error_code& ec) override; - -private: - HTTPClientSSLContext ssl_ctx_; - std::optional> - stream_; - boost::asio::io_service::strand& strand_; -}; - -class RawStream : public HTTPStream -{ -public: - RawStream(boost::asio::io_service::strand& strand); - - virtual ~RawStream() = default; - - boost::asio::ip::tcp::socket& - getStream() override; - - bool - connect( - std::string& errorOut, - std::string const& host, - std::string const& port, - boost::asio::yield_context& yield) override; - - void - asyncWrite( - request& req, - boost::asio::yield_context& yield, - boost::system::error_code& ec) override; - - void - asyncRead( - boost::beast::flat_buffer& buf, - parser& p, - boost::asio::yield_context& yield, - boost::system::error_code& ec) override; - - void - asyncReadSome( - boost::beast::flat_buffer& buf, - parser& p, - boost::asio::yield_context& yield, - boost::system::error_code& ec) override; - -private: - std::optional stream_; - boost::asio::io_service::strand& strand_; -}; - -} // namespace ripple - -#endif // RIPPLE_NET_HTTPSTREAM_H diff --git a/src/xrpld/net/ShardDownloader.md b/src/xrpld/net/ShardDownloader.md deleted file mode 100644 index d961df61c65..00000000000 --- a/src/xrpld/net/ShardDownloader.md +++ /dev/null @@ -1,311 +0,0 @@ -# Shard Downloader - -## Overview - -This document describes mechanics of the `HTTPDownloader`, a class that performs -the task of downloading shards from remote web servers via HTTP. The downloader -utilizes a strand (`boost::asio::io_service::strand`) to ensure that downloads -are never executed concurrently. Hence, if a download is in progress when -another download is initiated, the second download will be queued and invoked -only when the first download is completed. - -## Motivation - -In March 2020 the downloader was modified to include some key features: - -- The ability to stop downloads during a graceful shutdown. -- The ability to resume partial downloads after a crash or shutdown. - -This document was created to document the changes introduced by this change. - -## Classes - -Much of the shard downloading process concerns the following classes: - -- `HTTPDownloader` - - This is a generic class designed for serially executing downloads via HTTP. - -- `ShardArchiveHandler` - - This class uses the `HTTPDownloader` to fetch shards from remote web servers. - Additionally, the archive handler performs validity checks on the downloaded - files and imports the validated files into the local shard store. - - The `ShardArchiveHandler` exposes a simple public interface: - - ```C++ - /** Add an archive to be downloaded and imported. - @param shardIndex the index of the shard to be imported. - @param url the location of the archive. - @return `true` if successfully added. - @note Returns false if called while downloading. - */ - bool - add(std::uint32_t shardIndex, std::pair&& url); - - /** Starts downloading and importing archives. */ - bool - start(); - ``` - - When a client submits a `download_shard` command via the RPC interface, each - of the requested files is registered with the handler via the `add` method. - After all the files have been registered, the handler's `start` method is - invoked, which in turn creates an instance of the `HTTPDownloader` and begins - the first download. When the download is completed, the downloader invokes - the handler's `complete` method, which will initiate the download of the next - file, or simply return if there are no more downloads to process. When - `complete` is invoked with no remaining files to be downloaded, the handler - and downloader are not destroyed automatically, but persist for the duration - of the application to assist with graceful shutdowns. - -- `DatabaseBody` - - This class defines a custom message body type, allowing an - `http::response_parser` to write to an SQLite database rather than to a flat - file. This class is discussed in further detail in the Recovery section. - -## Graceful Shutdowns & Recovery - -This section describes in greater detail how the shutdown and recovery features -of the downloader are implemented in C++ using the `boost::asio` framework. - -##### Member Variables: - -The variables shown here are members of the `HTTPDownloader` class and -will be used in the following code examples. - -```c++ -std::unique_ptr stream_; -std::condition_variable c_; -std::atomic stop_; -``` - -### Graceful Shutdowns - -##### Thread 1: - -A graceful shutdown begins when the `stop()` method of the -`ShardArchiveHandler` is invoked: - -```c++ -void -ShardArchiveHandler::stop() -{ - std::lock_guard lock(m_); - - if (downloader_) - { - downloader_->stop(); - downloader_.reset(); - } - - stopped(); -} -``` - -Inside of `HTTPDownloader::stop()`, if a download is currently in progress, -the `stop_` member variable is set and the thread waits for the -download to stop: - -```c++ -void -HTTPDownloader::stop() -{ - std::unique_lock lock(m_); - - stop_ = true; - - if(sessionActive_) - { - // Wait for the handler to exit. - c_.wait(lock, - [this]() - { - return !sessionActive_; - }); - } -} -``` - -##### Thread 2: - -The graceful shutdown is realized when the thread executing the download polls -`stop_` after this variable has been set to `true`. Polling occurs -while the file is being downloaded, in between calls to `async_read_some()`. The -stop takes effect when the socket is closed and the handler function ( -`do_session()` ) is exited. - -```c++ -void HTTPDownloader::do_session() -{ - - // (Connection initialization logic) . . . - - - // (In between calls to async_read_some): - if(stop_.load()) - { - close(p); - return exit(); - } - - // . . . - - break; -} -``` - -### Recovery - -Persisting the current state of both the archive handler and the downloader is -achieved by leveraging an SQLite database rather than flat files, as the -database protects against data corruption that could result from a system crash. - -##### ShardArchiveHandler - -Although `HTTPDownloader` is a generic class that could be used to download a -variety of file types, currently it is used exclusively by the -`ShardArchiveHandler` to download shards. In order to provide resilience, the -`ShardArchiveHandler` will use an SQLite database to preserve its current state -whenever there are active, paused, or queued downloads. The `shard_db` section -in the configuration file allows users to specify the location of the database -to use for this purpose. - -###### SQLite Table Format - -| Index | URL | -|:-----:|:-----------------------------------:| -| 1 | https://example.com/1.tar.lz4 | -| 2 | https://example.com/2.tar.lz4 | -| 5 | https://example.com/5.tar.lz4 | - -##### HTTPDownloader - -While the archive handler maintains a list of all partial and queued downloads, -the `HTTPDownloader` stores the raw bytes of the file currently being -downloaded. The partially downloaded file will be represented as one or more -`BLOB` entries in an SQLite database. As the maximum size of a `BLOB` entry is -currently limited to roughly 2.1 GB, a 5 GB shard file for instance will occupy -three database entries upon completion. - -###### SQLite Table Format - -Since downloads execute serially by design, the entries in this table always -correspond to the contents of a single file. - -| Bytes | size | Part | -|:------:|:----------:|:----:| -| 0x... | 2147483647 | 0 | -| 0x... | 2147483647 | 1 | -| 0x... | 705032706 | 2 | - -##### Config File Entry -The `download_path` field of the `shard_db` entry is used to determine where to -store the recovery database. If this field is omitted, the `path` field will be -used instead. - -```dosini -# This is the persistent datastore for shards. It is important for the health -# of the network that rippled operators shard as much as practical. -# NuDB requires SSD storage. Helpful information can be found on -# https://xrpl.org/history-sharding.html -[shard_db] -type=NuDB -path=/var/lib/rippled/db/shards/nudb -download_path=/var/lib/rippled/db/shards/ -max_historical_shards=50 -``` - -##### Resuming Partial Downloads -When resuming downloads after a shutdown, crash, or other interruption, the -`HTTPDownloader` will utilize the `range` field of the HTTP header to download -only the remainder of the partially downloaded file. - -```C++ -auto downloaded = getPartialFileSize(); -auto total = getTotalFileSize(); - -http::request req {http::verb::head, - target, - version}; - -if (downloaded < total) -{ - // If we already downloaded 1000 bytes to the database, - // the range header will look like: - // Range: "bytes=1000-" - req.set(http::field::range, "bytes=" + to_string(downloaded) + "-"); -} -else if(downloaded == total) -{ - // Download is already complete. (Interruption must - // have occurred after file was downloaded but before - // the state file was updated.) -} -else -{ - // The size of the partially downloaded file exceeds - // the total download size. Error condition. Handle - // appropriately. -} -``` - -##### DatabaseBody - -Previously, the `HTTPDownloader` leveraged an `http::response_parser` -instantiated with an `http::file_body`. The `file_body` class declares a nested -type, `reader`, which does the task of writing HTTP message payloads -(constituting a requested file) to the filesystem. In order for the -`http::response_parser` to interface with the database, we implement a custom -body type that declares a nested `reader` type which has been outfitted to -persist octects received from the remote host to a local SQLite database. The -code snippet below illustrates the customization points available to -user-defined body types: - -```C++ -/// Defines a Body type -struct body -{ - /// This determines the return type of the `message::body` member function - using value_type = ...; - - /// An optional function, returns the body's payload size (which may be - /// zero) - static - std::uint64_t - size(value_type const& v); - - /// The algorithm used for extracting buffers - class reader; - - /// The algorithm used for inserting buffers - class writer; -} - -``` -Note that the `DatabaseBody` class is specifically designed to work with `asio` -and follows `asio` conventions. - -The method invoked to write data to the filesystem (or SQLite database in our -case) has the following signature: - -```C++ -std::size_t -body::reader::put(ConstBufferSequence const& buffers, error_code& ec); -``` - -## Sequence Diagram - -This sequence diagram demonstrates a scenario wherein the `ShardArchiveHandler` -leverages the state persisted in the database to recover from a crash and resume -the requested downloads. - -![alt_text](./images/interrupt_sequence.png "Resuming downloads post abort") - -## State Diagram - -This diagram illustrates the various states of the Shard Downloader module. - -![alt_text](./images/states.png "Shard Downloader states") diff --git a/src/xrpld/net/detail/DatabaseBody.ipp b/src/xrpld/net/detail/DatabaseBody.ipp deleted file mode 100644 index 76223ca6a35..00000000000 --- a/src/xrpld/net/detail/DatabaseBody.ipp +++ /dev/null @@ -1,231 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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 - -namespace ripple { - -inline void -DatabaseBody::value_type::close() -{ - { - std::unique_lock lock(m_); - - // Stop all scheduled and currently - // executing handlers before closing. - if (handlerCount_) - { - closing_ = true; - - auto predicate = [&] { return !handlerCount_; }; - c_.wait(lock, predicate); - } - - conn_.reset(); - } -} - -inline void -DatabaseBody::value_type::open( - boost::filesystem::path const& path, - Config const& config, - boost::asio::io_service& io_service, - boost::system::error_code& ec) -{ - strand_.reset(new boost::asio::io_service::strand(io_service)); - path_ = path; - - auto setup = setup_DatabaseCon(config); - setup.dataDir = path.parent_path(); - setup.useGlobalPragma = false; - - auto [conn, size] = openDatabaseBodyDb(setup, path); - conn_ = std::move(conn); - if (size) - fileSize_ = *size; -} - -// This is called from message::payload_size -inline std::uint64_t -DatabaseBody::size(value_type const& body) -{ - // Forward the call to the body - return body.size(); -} - -// We don't do much in the reader constructor since the -// database is already open. -// -template -DatabaseBody::reader::reader( - boost::beast::http::header&, - value_type& body) - : body_(body) -{ -} - -// We don't do anything with content_length but a sophisticated -// application might check available space on the device -// to see if there is enough room to store the body. -inline void -DatabaseBody::reader::init( - boost::optional const& /*content_length*/, - boost::system::error_code& ec) -{ - // The connection must already be available for writing - assert(body_.conn_); - - // The error_code specification requires that we - // either set the error to some value, or set it - // to indicate no error. - // - // We don't do anything fancy so set "no error" - ec = {}; -} - -// This will get called one or more times with body buffers -// -template -std::size_t -DatabaseBody::reader::put( - ConstBufferSequence const& buffers, - boost::system::error_code& ec) -{ - // This function must return the total number of - // bytes transferred from the input buffers. - std::size_t nwritten = 0; - - // Loop over all the buffers in the sequence, - // and write each one to the database. - for (auto it = buffer_sequence_begin(buffers); - it != buffer_sequence_end(buffers); - ++it) - { - boost::asio::const_buffer buffer = *it; - - body_.batch_.append( - static_cast(buffer.data()), buffer.size()); - - // Write this buffer to the database - if (body_.batch_.size() > FLUSH_SIZE) - { - bool post = true; - - { - std::lock_guard lock(body_.m_); - - if (body_.handlerCount_ >= MAX_HANDLERS) - post = false; - else - ++body_.handlerCount_; - } - - if (post) - { - body_.strand_->post( - [data = body_.batch_, this] { this->do_put(data); }); - - body_.batch_.clear(); - } - } - - nwritten += it->size(); - } - - // Indicate success - // This is required by the error_code specification - ec = {}; - - return nwritten; -} - -inline void -DatabaseBody::reader::do_put(std::string const& data) -{ - using namespace boost::asio; - - { - std::unique_lock lock(body_.m_); - - // The download is being halted. - if (body_.closing_) - { - if (--body_.handlerCount_ == 0) - { - lock.unlock(); - body_.c_.notify_one(); - } - - return; - } - } - - auto path = body_.path_.string(); - - { - auto db = body_.conn_->checkoutDb(); - body_.part_ = databaseBodyDoPut( - *db, data, path, body_.fileSize_, body_.part_, MAX_ROW_SIZE_PAD); - } - - bool const notify = [this] { - std::lock_guard lock(body_.m_); - return --body_.handlerCount_ == 0; - }(); - - if (notify) - body_.c_.notify_one(); -} - -// Called after writing is done when there's no error. -inline void -DatabaseBody::reader::finish(boost::system::error_code& ec) -{ - { - std::unique_lock lock(body_.m_); - - // Wait for scheduled DB writes - // to complete. - if (body_.handlerCount_) - { - auto predicate = [&] { return !body_.handlerCount_; }; - body_.c_.wait(lock, predicate); - } - } - - std::ofstream fout; - fout.open(body_.path_.string(), std::ios::binary | std::ios::out); - - { - auto db = body_.conn_->checkoutDb(); - databaseBodyFinish(*db, fout); - } - - // Flush any pending data that hasn't - // been been written to the DB. - if (body_.batch_.size()) - { - fout.write(body_.batch_.data(), body_.batch_.size()); - body_.batch_.clear(); - } - - fout.close(); -} - -} // namespace ripple diff --git a/src/xrpld/net/detail/DatabaseDownloader.cpp b/src/xrpld/net/detail/DatabaseDownloader.cpp deleted file mode 100644 index b39e6904c46..00000000000 --- a/src/xrpld/net/detail/DatabaseDownloader.cpp +++ /dev/null @@ -1,92 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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 - -namespace ripple { - -std::shared_ptr -make_DatabaseDownloader( - boost::asio::io_service& io_service, - Config const& config, - beast::Journal j) -{ - return std::shared_ptr( - new DatabaseDownloader(io_service, config, j)); -} - -DatabaseDownloader::DatabaseDownloader( - boost::asio::io_service& io_service, - Config const& config, - beast::Journal j) - : HTTPDownloader(io_service, config, j) - , config_(config) - , io_service_(io_service) -{ -} - -auto -DatabaseDownloader::getParser( - boost::filesystem::path dstPath, - std::function complete, - boost::system::error_code& ec) -> std::shared_ptr -{ - using namespace boost::beast; - - auto p = std::make_shared>(); - p->body_limit(std::numeric_limits::max()); - p->get().body().open(dstPath, config_, io_service_, ec); - - if (ec) - p->get().body().close(); - - return p; -} - -bool -DatabaseDownloader::checkPath(boost::filesystem::path const& dstPath) -{ - return dstPath.string().size() <= MAX_PATH_LEN; -} - -void -DatabaseDownloader::closeBody(std::shared_ptr p) -{ - using namespace boost::beast; - - auto databaseBodyParser = - std::dynamic_pointer_cast>(p); - assert(databaseBodyParser); - - databaseBodyParser->get().body().close(); -} - -std::uint64_t -DatabaseDownloader::size(std::shared_ptr p) -{ - using namespace boost::beast; - - auto databaseBodyParser = - std::dynamic_pointer_cast>(p); - assert(databaseBodyParser); - - return databaseBodyParser->get().body().size(); -} - -} // namespace ripple diff --git a/src/xrpld/net/detail/HTTPDownloader.cpp b/src/xrpld/net/detail/HTTPDownloader.cpp deleted file mode 100644 index 760aa020e4a..00000000000 --- a/src/xrpld/net/detail/HTTPDownloader.cpp +++ /dev/null @@ -1,340 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 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 -#include - -namespace ripple { - -HTTPDownloader::HTTPDownloader( - boost::asio::io_service& io_service, - Config const& config, - beast::Journal j) - : j_(j) - , config_(config) - , strand_(io_service) - , stop_(false) - , sessionActive_(false) -{ -} - -bool -HTTPDownloader::download( - std::string const& host, - std::string const& port, - std::string const& target, - int version, - boost::filesystem::path const& dstPath, - std::function complete, - bool ssl) -{ - if (!checkPath(dstPath)) - return false; - - if (stop_) - return true; - - { - std::lock_guard lock(m_); - sessionActive_ = true; - } - - if (!strand_.running_in_this_thread()) - strand_.post(std::bind( - &HTTPDownloader::download, - shared_from_this(), - host, - port, - target, - version, - dstPath, - complete, - ssl)); - else - boost::asio::spawn( - strand_, - std::bind( - &HTTPDownloader::do_session, - shared_from_this(), - host, - port, - target, - version, - dstPath, - complete, - ssl, - std::placeholders::_1)); - return true; -} - -void -HTTPDownloader::do_session( - std::string const host, - std::string const port, - std::string const target, - int version, - boost::filesystem::path dstPath, - std::function complete, - bool ssl, - boost::asio::yield_context yield) -{ - using namespace boost::asio; - using namespace boost::beast; - - boost::system::error_code ec; - bool skip = false; - - ////////////////////////////////////////////// - // Define lambdas for encapsulating download - // operations: - auto close = [&](auto p) { - closeBody(p); - - // Gracefully close the stream - stream_->getStream().shutdown(socket_base::shutdown_both, ec); - if (ec == boost::asio::error::eof) - ec.assign(0, ec.category()); - if (ec) - { - // Most web servers don't bother with performing - // the SSL shutdown handshake, for speed. - JLOG(j_.trace()) << "shutdown: " << ec.message(); - } - - // The stream cannot be reused - stream_.reset(); - }; - - // When the downloader is being stopped - // because the server is shutting down, - // this method notifies a caller of `onStop` - // (`RPC::ShardArchiveHandler` to be specific) - // that the session has ended. - auto exit = [this, &dstPath, complete] { - if (!stop_) - complete(std::move(dstPath)); - - std::lock_guard lock(m_); - sessionActive_ = false; - c_.notify_one(); - }; - - auto failAndExit = [&exit, &dstPath, complete, &ec, this]( - std::string const& errMsg, auto p) { - fail(dstPath, ec, errMsg, p); - exit(); - }; - // end lambdas - //////////////////////////////////////////////////////////// - - if (stop_.load()) - return exit(); - - auto p = this->getParser(dstPath, complete, ec); - if (ec) - return failAndExit("getParser", p); - - ////////////////////////////////////////////// - // Prepare for download and establish the - // connection: - if (ssl) - stream_ = std::make_unique(config_, strand_, j_); - else - stream_ = std::make_unique(strand_); - - std::string error; - if (!stream_->connect(error, host, port, yield)) - return failAndExit(error, p); - - // Set up an HTTP HEAD request message to find the file size - http::request req{http::verb::head, target, version}; - req.set(http::field::host, host); - req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING); - - std::uint64_t const rangeStart = size(p); - - // Requesting a portion of the file - if (rangeStart) - { - req.set( - http::field::range, - (boost::format("bytes=%llu-") % rangeStart).str()); - } - - stream_->asyncWrite(req, yield, ec); - if (ec) - return failAndExit("async_write", p); - - { - // Read the response - http::response_parser connectParser; - connectParser.skip(true); - stream_->asyncRead(read_buf_, connectParser, yield, ec); - if (ec) - return failAndExit("async_read", p); - - // Range request was rejected - if (connectParser.get().result() == http::status::range_not_satisfiable) - { - req.erase(http::field::range); - - stream_->asyncWrite(req, yield, ec); - if (ec) - return failAndExit("async_write_range_verify", p); - - http::response_parser rangeParser; - rangeParser.skip(true); - - stream_->asyncRead(read_buf_, rangeParser, yield, ec); - if (ec) - return failAndExit("async_read_range_verify", p); - - // The entire file is downloaded already. - if (rangeParser.content_length() == rangeStart) - skip = true; - else - return failAndExit("range_not_satisfiable", p); - } - else if ( - rangeStart && - connectParser.get().result() != http::status::partial_content) - { - ec.assign( - boost::system::errc::not_supported, - boost::system::generic_category()); - - return failAndExit("Range request ignored", p); - } - else if (auto len = connectParser.content_length()) - { - try - { - // Ensure sufficient space is available - if (*len > space(dstPath.parent_path()).available) - { - return failAndExit( - "Insufficient disk space for download", p); - } - } - catch (std::exception const& e) - { - return failAndExit(std::string("exception: ") + e.what(), p); - } - } - } - - if (!skip) - { - // Set up an HTTP GET request message to download the file - req.method(http::verb::get); - - if (rangeStart) - { - req.set( - http::field::range, - (boost::format("bytes=%llu-") % rangeStart).str()); - } - } - - stream_->asyncWrite(req, yield, ec); - if (ec) - return failAndExit("async_write", p); - - // end prepare and connect - //////////////////////////////////////////////////////////// - - if (skip) - p->skip(true); - - // Download the file - while (!p->is_done()) - { - if (stop_.load()) - { - close(p); - return exit(); - } - - stream_->asyncReadSome(read_buf_, *p, yield, ec); - } - - JLOG(j_.trace()) << "download completed: " << dstPath.string(); - - close(p); - exit(); -} - -void -HTTPDownloader::stop() -{ - stop_ = true; - - std::unique_lock lock(m_); - if (sessionActive_) - { - // Wait for the handler to exit. - c_.wait(lock, [this]() { return !sessionActive_; }); - } -} - -bool -HTTPDownloader::sessionIsActive() const -{ - std::lock_guard lock(m_); - return sessionActive_; -} - -bool -HTTPDownloader::isStopping() const -{ - std::lock_guard lock(m_); - return stop_; -} - -void -HTTPDownloader::fail( - boost::filesystem::path dstPath, - boost::system::error_code const& ec, - std::string const& errMsg, - std::shared_ptr parser) -{ - if (!ec) - { - JLOG(j_.error()) << errMsg; - } - else if (ec != boost::asio::error::operation_aborted) - { - JLOG(j_.error()) << errMsg << ": " << ec.message(); - } - - if (parser) - closeBody(parser); - - try - { - remove(dstPath); - } - catch (std::exception const& e) - { - JLOG(j_.error()) << "exception: " << e.what() - << " in function: " << __func__; - } -} - -} // namespace ripple diff --git a/src/xrpld/net/detail/HTTPStream.cpp b/src/xrpld/net/detail/HTTPStream.cpp deleted file mode 100644 index b94f8959ec9..00000000000 --- a/src/xrpld/net/detail/HTTPStream.cpp +++ /dev/null @@ -1,203 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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 - -namespace ripple { - -SSLStream::SSLStream( - Config const& config, - boost::asio::io_service::strand& strand, - beast::Journal j) - : ssl_ctx_(config, j, boost::asio::ssl::context::tlsv12_client) - , strand_(strand) -{ -} - -boost::asio::ip::tcp::socket& -SSLStream::getStream() -{ - assert(stream_); - return stream_->next_layer(); -} - -bool -SSLStream::connect( - std::string& errorOut, - std::string const& host, - std::string const& port, - boost::asio::yield_context& yield) -{ - using namespace boost::asio; - using namespace boost::beast; - - boost::system::error_code ec; - - auto fail = [&errorOut, &ec]( - std::string const& errorIn, - std::string const& message = "") { - errorOut = errorIn + ": " + (message.empty() ? ec.message() : message); - return false; - }; - - ip::tcp::resolver resolver{strand_.context()}; - auto const endpoints = resolver.async_resolve(host, port, yield[ec]); - if (ec) - return fail("async_resolve"); - - try - { - stream_.emplace(strand_.context(), ssl_ctx_.context()); - } - catch (std::exception const& e) - { - return fail("exception", e.what()); - } - - ec = ssl_ctx_.preConnectVerify(*stream_, host); - if (ec) - return fail("preConnectVerify"); - - boost::asio::async_connect( - stream_->next_layer(), endpoints.begin(), endpoints.end(), yield[ec]); - if (ec) - return fail("async_connect"); - - ec = ssl_ctx_.postConnectVerify(*stream_, host); - if (ec) - return fail("postConnectVerify"); - - stream_->async_handshake(ssl::stream_base::client, yield[ec]); - if (ec) - return fail("async_handshake"); - - return true; -} - -void -SSLStream::asyncWrite( - request& req, - boost::asio::yield_context& yield, - boost::system::error_code& ec) -{ - boost::beast::http::async_write(*stream_, req, yield[ec]); -} - -void -SSLStream::asyncRead( - boost::beast::flat_buffer& buf, - parser& p, - boost::asio::yield_context& yield, - boost::system::error_code& ec) -{ - boost::beast::http::async_read(*stream_, buf, p, yield[ec]); -} - -void -SSLStream::asyncReadSome( - boost::beast::flat_buffer& buf, - parser& p, - boost::asio::yield_context& yield, - boost::system::error_code& ec) -{ - boost::beast::http::async_read_some(*stream_, buf, p, yield[ec]); -} - -RawStream::RawStream(boost::asio::io_service::strand& strand) : strand_(strand) -{ -} - -boost::asio::ip::tcp::socket& -RawStream::getStream() -{ - assert(stream_); - return *stream_; -} - -bool -RawStream::connect( - std::string& errorOut, - std::string const& host, - std::string const& port, - boost::asio::yield_context& yield) -{ - using namespace boost::asio; - using namespace boost::beast; - - boost::system::error_code ec; - - auto fail = [&errorOut, &ec]( - std::string const& errorIn, - std::string const& message = "") { - errorOut = errorIn + ": " + (message.empty() ? ec.message() : message); - return false; - }; - - ip::tcp::resolver resolver{strand_.context()}; - auto const endpoints = resolver.async_resolve(host, port, yield[ec]); - if (ec) - return fail("async_resolve"); - - try - { - stream_.emplace(strand_.context()); - } - catch (std::exception const& e) - { - return fail("exception", e.what()); - } - - boost::asio::async_connect( - *stream_, endpoints.begin(), endpoints.end(), yield[ec]); - if (ec) - return fail("async_connect"); - - return true; -} - -void -RawStream::asyncWrite( - request& req, - boost::asio::yield_context& yield, - boost::system::error_code& ec) -{ - boost::beast::http::async_write(*stream_, req, yield[ec]); -} - -void -RawStream::asyncRead( - boost::beast::flat_buffer& buf, - parser& p, - boost::asio::yield_context& yield, - boost::system::error_code& ec) -{ - boost::beast::http::async_read(*stream_, buf, p, yield[ec]); -} - -void -RawStream::asyncReadSome( - boost::beast::flat_buffer& buf, - parser& p, - boost::asio::yield_context& yield, - boost::system::error_code& ec) -{ - boost::beast::http::async_read_some(*stream_, buf, p, yield[ec]); -} - -} // namespace ripple diff --git a/src/xrpld/net/detail/RPCCall.cpp b/src/xrpld/net/detail/RPCCall.cpp index 533878ab1b0..997d6463f23 100644 --- a/src/xrpld/net/detail/RPCCall.cpp +++ b/src/xrpld/net/detail/RPCCall.cpp @@ -189,36 +189,6 @@ class RPCParser return v; } - Json::Value - parseDownloadShard(Json::Value const& jvParams) - { - Json::Value jvResult(Json::objectValue); - unsigned int sz{jvParams.size()}; - unsigned int i{0}; - - // If odd number of params then 'novalidate' may have been specified - if (sz & 1) - { - if (boost::iequals(jvParams[0u].asString(), "novalidate")) - ++i; - else if (!boost::iequals(jvParams[--sz].asString(), "novalidate")) - return rpcError(rpcINVALID_PARAMS); - } - - // Create the 'shards' array - Json::Value shards(Json::arrayValue); - for (; i < sz; i += 2) - { - Json::Value shard(Json::objectValue); - shard[jss::index] = jvParams[i].asUInt(); - shard[jss::url] = jvParams[i + 1].asString(); - shards.append(std::move(shard)); - } - jvResult[jss::shards] = std::move(shards); - - return jvResult; - } - Json::Value parseInternal(Json::Value const& jvParams) { @@ -870,15 +840,6 @@ class RPCParser return jvRequest; } - Json::Value - parseNodeToShard(Json::Value const& jvParams) - { - Json::Value jvRequest; - jvRequest[jss::action] = jvParams[0u].asString(); - - return jvRequest; - } - // peer_reservations_add [] Json::Value parsePeerReservationsAdd(Json::Value const& jvParams) @@ -1200,9 +1161,7 @@ class RPCParser {"channel_verify", &RPCParser::parseChannelVerify, 4, 4}, {"connect", &RPCParser::parseConnect, 1, 2}, {"consensus_info", &RPCParser::parseAsIs, 0, 0}, - {"crawl_shards", &RPCParser::parseAsIs, 0, 2}, {"deposit_authorized", &RPCParser::parseDepositAuthorized, 2, 3}, - {"download_shard", &RPCParser::parseDownloadShard, 2, -1}, {"feature", &RPCParser::parseFeature, 0, 2}, {"fetch_info", &RPCParser::parseFetchInfo, 0, 1}, {"gateway_balances", &RPCParser::parseGatewayBalances, 1, -1}, @@ -1220,7 +1179,6 @@ class RPCParser {"log_level", &RPCParser::parseLogLevel, 0, 2}, {"logrotate", &RPCParser::parseAsIs, 0, 0}, {"manifest", &RPCParser::parseManifest, 1, 1}, - {"node_to_shard", &RPCParser::parseNodeToShard, 1, 1}, {"owner_info", &RPCParser::parseAccountItems, 1, 3}, {"peers", &RPCParser::parseAsIs, 0, 0}, {"ping", &RPCParser::parseAsIs, 0, 0}, diff --git a/src/xrpld/net/uml/interrupt_sequence.pu b/src/xrpld/net/uml/interrupt_sequence.pu deleted file mode 100644 index ba046d084f8..00000000000 --- a/src/xrpld/net/uml/interrupt_sequence.pu +++ /dev/null @@ -1,233 +0,0 @@ -@startuml - - -skinparam shadowing false - -/' -skinparam sequence { - ArrowColor #e1e4e8 - ActorBorderColor #e1e4e8 - DatabaseBorderColor #e1e4e8 - LifeLineBorderColor Black - LifeLineBackgroundColor #d3d6d9 - - ParticipantBorderColor DeepSkyBlue - ParticipantBackgroundColor DodgerBlue - ParticipantFontName Impact - ParticipantFontSize 17 - ParticipantFontColor #A9DCDF - - NoteBackgroundColor #6a737d - - ActorBackgroundColor #f6f8fa - ActorFontColor #6a737d - ActorFontSize 17 - ActorFontName Aapex - - EntityBackgroundColor #f6f8fa - EntityFontColor #6a737d - EntityFontSize 17 - EntityFontName Aapex - - DatabaseBackgroundColor #f6f8fa - DatabaseFontColor #6a737d - DatabaseFontSize 17 - DatabaseFontName Aapex - - CollectionsBackgroundColor #f6f8fa - ActorFontColor #6a737d - ActorFontSize 17 - ActorFontName Aapex -} - -skinparam note { - BackgroundColor #fafbfc - BorderColor #e1e4e8 -} -'/ - -'skinparam monochrome true - -actor Client as c -entity RippleNode as rn -entity ShardArchiveHandler as sa -entity SSLHTTPDownloader as d -database Database as db -collections Fileserver as s - -c -> rn: Launch RippleNode -activate rn - -c -> rn: Issue download request - -note right of c - **Download Request:** - - { - "method": "download_shard", - "params": - [ - { - "shards": - [ - {"index": 1, "url": "https://example.com/1.tar.lz4"}, - {"index": 2, "url": "https://example.com/2.tar.lz4"}, - {"index": 5, "url": "https://example.com/5.tar.lz4"} - ] - } - ] - } -end note - -rn -> sa: Create instance of Handler -activate sa - -rn -> sa: Add three downloads -sa -> sa: Validate requested downloads - -rn -> sa: Initiate Downloads -sa -> rn: ACK: Initiating -rn -> c: Initiating requested downloads - -sa -> db: Save state to the database\n(Processing three downloads) - -note right of db - - **ArchiveHandler State (SQLite Table):** - - | Index | URL | - | 1 | https://example.com/1.tar.lz4 | - | 2 | https://example.com/2.tar.lz4 | - | 5 | https://example.com/5.tar.lz4 | - -end note - -sa -> d: Create instance of Downloader -activate d - -group Download 1 - - note over sa - **Download 1:** - - This encapsulates the download of the first file - at URL "https://example.com/1.tar.lz4". - - end note - - sa -> d: Start download - - d -> s: Connect and request file - s -> d: Send file - d -> sa: Invoke completion handler - -end - -sa -> sa: Import and validate shard - -sa -> db: Update persisted state\n(Remove download) - -note right of db - **ArchiveHandler State:** - - | Index | URL | - | 2 | https://example.com/2.tar.lz4 | - | 5 | https://example.com/5.tar.lz4 | - -end note - -group Download 2 - - sa -> d: Start download - - d -> s: Connect and request file - -end - -rn -> rn: **RippleNode crashes** - -deactivate sa -deactivate rn -deactivate d - -c -> rn: Restart RippleNode -activate rn - -rn -> db: Detect non-empty state database - -rn -> sa: Create instance of Handler -activate sa - -sa -> db: Load state - -note right of db - **ArchiveHandler State:** - - | Index | URL | - | 2 | https://example.com/2.tar.lz4 | - | 5 | https://example.com/5.tar.lz4 | - -end note - -sa -> d: Create instance of Downloader -activate d - -sa -> sa: Resume Download 2 - -group Download 2 - - sa -> d: Start download - - d -> s: Connect and request file - s -> d: Send file - d -> sa: Invoke completion handler - -end - -sa -> sa: Import and validate shard - -sa -> db: Update persisted state \n(Remove download) - -note right of db - **ArchiveHandler State:** - - | Index | URL | - | 5 | https://example.com/5.tar.lz4 | - -end note - -group Download 3 - - sa -> d: Start download - - d -> s: Connect and request file - s -> d: Send file - d -> sa: Invoke completion handler - -end - -sa -> sa: Import and validate shard - -sa -> db: Update persisted state \n(Remove download) - -note right of db - **ArchiveHandler State:** - - ***empty*** - -end note - -sa -> db: Remove empty database - -sa -> sa: Automatically destroyed -deactivate sa - -d -> d: Destroyed via reference\ncounting -deactivate d - -c -> rn: Poll RippleNode to verify successfull\nimport of all requested shards. -c -> rn: Shutdown RippleNode - -deactivate rn - -@enduml diff --git a/src/xrpld/net/uml/states.pu b/src/xrpld/net/uml/states.pu deleted file mode 100644 index b5db8ee48f4..00000000000 --- a/src/xrpld/net/uml/states.pu +++ /dev/null @@ -1,69 +0,0 @@ -@startuml - -state "Updating Database" as UD4 { - UD4: Update the database to reflect - UD4: the current state. -} -state "Initiating Download" as ID { - ID: Omit the range header to download - ID: the entire file. -} - -state "Evaluate Database" as ED { - ED: Determine the current state - ED: based on the contents of the - ED: database from a previous run. -} - -state "Remove Database" as RD { - RD: The database is destroyed when - RD: empty. -} - -state "Download in Progress" as DP - -state "Download Completed" as DC { - - state "Updating Database" as UD { - UD: Update the database to reflect - UD: the current state. - } - - state "Queue Check" as QC { - QC: Check the queue for any reamining - QC: downloads. - } - - [*] --> UD - UD --> QC -} - -state "Check Resume" as CR { - CR: Determine whether we're resuming - CR: a previous download or starting a - CR: new one. -} - -state "Resuming Download" as IPD { - IPD: Set the range header in the - IPD: HTTP request as needed. -} - -[*] --> ED : State DB is present at\nnode launch -ED --> RD : State DB is empty -ED --> CR : There are downloads queued -RD --> [*] - -[*] --> UD4 : Client invokes <>\ncommand -UD4 --> ID : Database updated -ID --> DP : Download started -DP --> DC : Download completed -DC --> ID : There **are** additional downloads\nqueued -DP --> [*] : A graceful shutdown is\nin progress -DC --> RD : There **are no** additional\ndownloads queued - -CR --> IPD : Resuming an interrupted\ndownload -IPD --> DP: Download started -CR --> ID : Initiating a new\ndownload - -@enduml diff --git a/src/xrpld/nodestore/Database.h b/src/xrpld/nodestore/Database.h index ad843c55d52..daf0483e890 100644 --- a/src/xrpld/nodestore/Database.h +++ b/src/xrpld/nodestore/Database.h @@ -31,8 +31,6 @@ namespace ripple { -class Ledger; - namespace NodeStore { /** Persistency layer for NodeObject @@ -153,7 +151,7 @@ class Database @note This can be called concurrently. @param hash The key of the object to retrieve @param ledgerSeq The sequence of the ledger where the - object is stored, used by the shard store. + object is stored. @param callback Callback function when read completes */ virtual void @@ -162,14 +160,6 @@ class Database std::uint32_t ledgerSeq, std::function const&)>&& callback); - /** Store a ledger from a different database. - - @param srcLedger The ledger to store. - @return true if the operation was successful - */ - virtual bool - storeLedger(std::shared_ptr const& srcLedger) = 0; - /** Remove expired entries from the positive and negative caches. */ virtual void sweep() = 0; @@ -224,14 +214,6 @@ class Database bool isStopping() const; - /** @return The maximum number of ledgers stored in a shard - */ - [[nodiscard]] std::uint32_t - ledgersPerShard() const noexcept - { - return ledgersPerShard_; - } - /** @return The earliest ledger sequence allowed */ [[nodiscard]] std::uint32_t @@ -240,63 +222,6 @@ class Database return earliestLedgerSeq_; } - /** @return The earliest shard index - */ - [[nodiscard]] std::uint32_t - earliestShardIndex() const noexcept - { - return earliestShardIndex_; - } - - /** Calculates the first ledger sequence for a given shard index - - @param shardIndex The shard index considered - @return The first ledger sequence pertaining to the shard index - */ - [[nodiscard]] std::uint32_t - firstLedgerSeq(std::uint32_t shardIndex) const noexcept - { - assert(shardIndex >= earliestShardIndex_); - if (shardIndex <= earliestShardIndex_) - return earliestLedgerSeq_; - return 1 + (shardIndex * ledgersPerShard_); - } - - /** Calculates the last ledger sequence for a given shard index - - @param shardIndex The shard index considered - @return The last ledger sequence pertaining to the shard index - */ - [[nodiscard]] std::uint32_t - lastLedgerSeq(std::uint32_t shardIndex) const noexcept - { - assert(shardIndex >= earliestShardIndex_); - return (shardIndex + 1) * ledgersPerShard_; - } - - /** Calculates the shard index for a given ledger sequence - - @param ledgerSeq ledger sequence - @return The shard index of the ledger sequence - */ - [[nodiscard]] std::uint32_t - seqToShardIndex(std::uint32_t ledgerSeq) const noexcept - { - assert(ledgerSeq >= earliestLedgerSeq_); - return (ledgerSeq - 1) / ledgersPerShard_; - } - - /** Calculates the maximum ledgers for a given shard index - - @param shardIndex The shard index considered - @return The maximum ledgers pertaining to the shard index - - @note The earliest shard may store less if the earliest ledger - sequence truncates its beginning - */ - [[nodiscard]] std::uint32_t - maxLedgers(std::uint32_t shardIndex) const noexcept; - protected: beast::Journal const j_; Scheduler& scheduler_; @@ -305,25 +230,14 @@ class Database std::atomic fetchHitCount_{0}; std::atomic fetchSz_{0}; - // The default is DEFAULT_LEDGERS_PER_SHARD (16384) to match the XRP ledger - // network. Can be set through the configuration file using the - // 'ledgers_per_shard' field under the 'node_db' and 'shard_db' stanzas. - // If specified, the value must be a multiple of 256 and equally assigned - // in both stanzas. Only unit tests or alternate networks should change - // this value. - std::uint32_t const ledgersPerShard_; - // The default is XRP_LEDGER_EARLIEST_SEQ (32570) to match the XRP ledger // network's earliest allowed ledger sequence. Can be set through the // configuration file using the 'earliest_seq' field under the 'node_db' - // and 'shard_db' stanzas. If specified, the value must be greater than zero - // and equally assigned in both stanzas. Only unit tests or alternate + // stanza. If specified, the value must be greater than zero. + // Only unit tests or alternate // networks should change this value. std::uint32_t const earliestLedgerSeq_; - // The earliest shard index - std::uint32_t const earliestShardIndex_; - // The maximum number of requests a thread extracts from the queue in an // attempt to minimize the overhead of mutex acquisition. This is an // advanced tunable, via the config file. The default value is 4. @@ -341,10 +255,6 @@ class Database void importInternal(Backend& dstBackend, Database& srcDB); - // Called by the public storeLedger function - bool - storeLedger(Ledger const& srcLedger, std::shared_ptr dstBackend); - void updateFetchMetrics(uint64_t fetches, uint64_t hits, uint64_t duration) { diff --git a/src/xrpld/nodestore/DatabaseShard.h b/src/xrpld/nodestore/DatabaseShard.h deleted file mode 100644 index 408ac3501d3..00000000000 --- a/src/xrpld/nodestore/DatabaseShard.h +++ /dev/null @@ -1,298 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2017 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_NODESTORE_DATABASESHARD_H_INCLUDED -#define RIPPLE_NODESTORE_DATABASESHARD_H_INCLUDED - -#include -#include -#include -#include -#include - -#include -#include - -namespace ripple { -namespace NodeStore { - -/** A collection of historical shards - */ -class DatabaseShard : public Database -{ -public: - /** Construct a shard store - - @param scheduler The scheduler to use for performing asynchronous tasks - @param readThreads The number of asynchronous read threads to create - @param config The shard configuration section for the database - @param journal Destination for logging output - */ - DatabaseShard( - Scheduler& scheduler, - int readThreads, - Section const& config, - beast::Journal journal) - : Database(scheduler, readThreads, config, journal) - { - } - - /** Initialize the database - - @return `true` if the database initialized without error - */ - [[nodiscard]] virtual bool - init() = 0; - - /** Prepare to store a new ledger in the shard being acquired - - @param validLedgerSeq The sequence of the maximum valid ledgers - @return If a ledger should be fetched and stored, then returns the - ledger sequence of the ledger to request. Otherwise returns - std::nullopt. - Some reasons this may return std::nullopt are: all shards are - stored and full, max allowed disk space would be exceeded, or a - ledger was recently requested and not enough time has passed - between requests. - @implNote adds a new writable shard if necessary - */ - [[nodiscard]] virtual std::optional - prepareLedger(std::uint32_t validLedgerSeq) = 0; - - /** Prepare one or more shard indexes to be imported into the database - - @param shardIndexes Shard indexes to be prepared for import - @return true if all shard indexes successfully prepared for import - */ - [[nodiscard]] virtual bool - prepareShards(std::vector const& shardIndexes) = 0; - - /** Remove a previously prepared shard index for import - - @param shardIndex Shard index to be removed from import - */ - virtual void - removePreShard(std::uint32_t shardIndex) = 0; - - /** Get shard indexes being imported - - @return a string representing the shards prepared for import - */ - [[nodiscard]] virtual std::string - getPreShards() = 0; - - /** Import a shard from the shard archive handler into the - shard database. This differs from 'importDatabase' which - imports the contents of the NodeStore - - @param shardIndex Shard index to import - @param srcDir The directory to import from - @return true If the shard was successfully imported - @implNote if successful, srcDir is moved to the database directory - */ - [[nodiscard]] virtual bool - importShard( - std::uint32_t shardIndex, - boost::filesystem::path const& srcDir) = 0; - - /** Fetch a ledger from the shard store - - @param hash The key of the ledger to retrieve - @param seq The sequence of the ledger - @return The ledger if found, nullptr otherwise - */ - [[nodiscard]] virtual std::shared_ptr - fetchLedger(uint256 const& hash, std::uint32_t seq) = 0; - - /** Notifies the database that the given ledger has been - fully acquired and stored. - - @param ledger The stored ledger to be marked as complete - */ - virtual void - setStored(std::shared_ptr const& ledger) = 0; - - /** Invoke a callback on the SQLite db holding the - corresponding ledger - - @return Value returned by callback function. - */ - virtual bool - callForLedgerSQLByLedgerSeq( - LedgerIndex ledgerSeq, - std::function const& callback) = 0; - - /** Invoke a callback on the ledger SQLite db for the - corresponding shard - - @return Value returned by callback function. - */ - virtual bool - callForLedgerSQLByShardIndex( - std::uint32_t shardIndex, - std::function const& callback) = 0; - - /** Invoke a callback on the transaction SQLite db - for the corresponding ledger - - @return Value returned by callback function. - */ - virtual bool - callForTransactionSQLByLedgerSeq( - LedgerIndex ledgerSeq, - std::function const& callback) = 0; - - /** Invoke a callback on the transaction SQLite db - for the corresponding shard - - @return Value returned by callback function. - */ - virtual bool - callForTransactionSQLByShardIndex( - std::uint32_t shardIndex, - std::function const& callback) = 0; - - /** - * @brief iterateLedgerSQLsForward Checks out ledger databases for all - * shards in ascending order starting from given shard index until - * shard with the largest index visited or callback returned false. - * For each visited shard calls given callback function passing - * shard index and session with the database to it. - * @param minShardIndex Start shard index to visit or none if all shards - * should be visited. - * @param callback Callback function to call. - * @return True if each callback function returns true, false otherwise. - */ - virtual bool - iterateLedgerSQLsForward( - std::optional minShardIndex, - std::function< - bool(soci::session& session, std::uint32_t shardIndex)> const& - callback) = 0; - - /** - * @brief iterateTransactionSQLsForward Checks out transaction databases for - * all shards in ascending order starting from given shard index - * until shard with the largest index visited or callback returned - * false. For each visited shard calls given callback function - * passing shard index and session with the database to it. - * @param minShardIndex Start shard index to visit or none if all shards - * should be visited. - * @param callback Callback function to call. - * @return True if each callback function returns true, false otherwise. - */ - virtual bool - iterateTransactionSQLsForward( - std::optional minShardIndex, - std::function< - bool(soci::session& session, std::uint32_t shardIndex)> const& - callback) = 0; - - /** - * @brief iterateLedgerSQLsBack Checks out ledger databases for - * all shards in descending order starting from given shard index - * until shard with the smallest index visited or callback returned - * false. For each visited shard calls given callback function - * passing shard index and session with the database to it. - * @param maxShardIndex Start shard index to visit or none if all shards - * should be visited. - * @param callback Callback function to call. - * @return True if each callback function returns true, false otherwise. - */ - virtual bool - iterateLedgerSQLsBack( - std::optional maxShardIndex, - std::function< - bool(soci::session& session, std::uint32_t shardIndex)> const& - callback) = 0; - - /** - * @brief iterateTransactionSQLsBack Checks out transaction databases for - * all shards in descending order starting from given shard index - * until shard with the smallest index visited or callback returned - * false. For each visited shard calls given callback function - * passing shard index and session with the database to it. - * @param maxShardIndex Start shard index to visit or none if all shards - * should be visited. - * @param callback Callback function to call. - * @return True if each callback function returns true, false otherwise. - */ - virtual bool - iterateTransactionSQLsBack( - std::optional maxShardIndex, - std::function< - bool(soci::session& session, std::uint32_t shardIndex)> const& - callback) = 0; - - /** Query information about shards held - - @return Information about shards held by this node - */ - [[nodiscard]] virtual std::unique_ptr - getShardInfo() const = 0; - - /** Returns the root database directory - */ - [[nodiscard]] virtual boost::filesystem::path const& - getRootDir() const = 0; - - /** Returns a JSON object detailing the status of an ongoing - database import if one is running, otherwise an error - object. - */ - virtual Json::Value - getDatabaseImportStatus() const = 0; - - /** Initiates a NodeStore to ShardStore import and returns - the result in a JSON object. - */ - virtual Json::Value - startNodeToShard() = 0; - - /** Terminates a NodeStore to ShardStore import and returns - the result in a JSON object. - */ - virtual Json::Value - stopNodeToShard() = 0; - - /** Returns the first ledger sequence of the shard currently being imported - from the NodeStore - - @return The ledger sequence or an unseated value if no import is running - */ - virtual std::optional - getDatabaseImportSequence() const = 0; - - /** Returns the number of queued tasks - */ - [[nodiscard]] virtual size_t - getNumTasks() const = 0; -}; - -extern std::unique_ptr -make_ShardStore( - Application& app, - Scheduler& scheduler, - int readThreads, - beast::Journal j); - -} // namespace NodeStore -} // namespace ripple - -#endif diff --git a/src/xrpld/nodestore/DeterministicShard.md b/src/xrpld/nodestore/DeterministicShard.md deleted file mode 100644 index 70d0584567b..00000000000 --- a/src/xrpld/nodestore/DeterministicShard.md +++ /dev/null @@ -1,162 +0,0 @@ -# Deterministic Database Shards - -This doc describes the standard way to assemble the database shard. -A shard assembled using this approach becomes deterministic i.e. -if two independent sides assemble a shard consisting of the same ledgers, -accounts and transactions, then they will obtain the same shard files -`nudb.dat` and `nudb.key`. The approach deals with the `NuDB` database -format only, refer to `https://github.com/vinniefalco/NuDB`. - - -## Headers - -Due to NuDB database definition, the following headers are used for -database files: - -nudb.key: -``` -char[8] Type The characters "nudb.key" -uint16 Version Holds the version number -uint64 UID Unique ID generated on creation -uint64 Appnum Application defined constant -uint16 KeySize Key size in bytes -uint64 Salt A random seed -uint64 Pepper The salt hashed -uint16 BlockSize size of a file block in bytes -uint16 LoadFactor Target fraction in 65536ths -uint8[56] Reserved Zeroes -uint8[] Reserved Zero-pad to block size -``` - -nudb.dat: -``` -char[8] Type The characters "nudb.dat" -uint16 Version Holds the version number -uint64 UID Unique ID generated on creation -uint64 Appnum Application defined constant -uint16 KeySize Key size in bytes -uint8[64] (reserved) Zeroes -``` -All of these fields are saved using network byte order -(bigendian: most significant byte first). - -To make the shard deterministic the following parameters are used -as values of header field both for `nudb.key` and `nudb.dat` files. -``` -Version 2 -UID digest(0) -Appnum digest(2) | 0x5348524400000000 /* 'SHRD' */ -KeySize 32 -Salt digest(1) -Pepper XXH64(Salt) -BlockSize 0x1000 (4096 bytes) -LoadFactor 0.5 (numeric 0x8000) -``` -Note: XXH64() is well-known hash algorithm. - -The `digest(i)` mentioned above defined as the follows: - -First, RIPEMD160 hash `H` calculated of the following structure -(the same as final Key of the shard): -``` -uint32 version Version of shard, 2 at the present -uint32 firstSeq Sequence number of first ledger in the shard -uint32 lastSeq Sequence number of last ledger in the shard -uint256 lastHash Hash of last ledger in shard -``` -there all 32-bit integers are hashed in network byte order -(bigendian: most significant byte first). - -Then, `digest(i)` is defined as the following part of the above hash `H`: -``` -digest(0) = H[0] << 56 | H[1] << 48 | ... | H[7] << 0, -digest(1) = H[8] << 56 | H[9] << 48 | ... | H[15] << 0, -digest(2) = H[16] << 24 | H[17] << 16 | ... | H[19] << 0, -``` -where `H[i]` denotes `i`-th byte of hash `H`. - - -## Contents - -After deterministic shard is created using the above mentioned headers, -it filled with objects using the following steps. - -1. All objects within the shard are visited in the order described in the -next section. Here the objects are: ledger headers, SHAmap tree nodes -including state and transaction nodes, final key. - -2. Set of all visited objects is divided into groups. Each group except of -the last contains 16384 objects in the order of their visiting. Last group -may contain less than 16384 objects. - -3. All objects within each group are sorted in according to their hashes. -Objects are sorted by increasing of their hashes, precisely, by increasing -of hex representations of hashes in lexicographic order. For example, -the following is an example of sorted hashes in their hex representation: -``` -0000000000000000000000000000000000000000000000000000000000000000 -154F29A919B30F50443A241C466691B046677C923EE7905AB97A4DBE8A5C2429 -2231553FC01D37A66C61BBEEACBB8C460994493E5659D118E19A8DDBB1444273 -272DCBFD8E4D5D786CF11A5444B30FB35435933B5DE6C660AA46E68CF0F5C441 -3C062FD9F0BCDCA31ACEBCD8E530D0BDAD1F1D1257B89C435616506A3EE6CB9E -58A0E5AE427CDDC1C7C06448E8C3E4BF718DE036D827881624B20465C3E1336F -... -``` - -4. Finally, objects added to the deterministic shard group by group in the -sorted order within each group from low to high hashes. - - -## Order of visiting objects - -The shard consists of 16384 ledgers and the final key with the hash 0. -Each ledger has the header object and two SMAmaps: state and transaction. -SHAmap is a rooted tree in which each node has maximum of 16 descendants -enumerating by indexes 0..15. Visiting each node in the SHAmap -is performing by functions visitNodes and visitDifferences implemented -in the file `ripple/shamap/impl/ShaMapSync.cpp`. - -Here is how the function visitNodes works: it visit the root at first. -Then it visit all nodes in the 1st layer, i. e. the nodes which are -immediately descendants of the root sequentially from index 0 to 15. -Then it visit all nodes in 2nd layer i.e. the nodes which are immediately -descendants the nodes from 1st layer. The order of visiting 2nd layer nodes -is the following. First, descendants of the 1st layer node with index 0 -are visited sequintially from index 0 to 15. Then descendents of 1st layer -node with index 1 are visited etc. After visiting all nodes of 2nd layer -the nodes from 3rd layer are visited etc. - -The function visitDifferences works similar to visitNodes with the following -exceptions. The first exception is that visitDifferences get 2 arguments: -current SHAmap and previous SHAmap and visit only the nodes from current -SHAmap which and not present in previous SHAmap. The second exception is -that visitDifferences visits all non-leaf nodes in the order of visitNodes -function, but all leaf nodes are visited immedeately after visiting of their -parent node sequentially from index 0 to 15. - -Finally, all objects within the shard are visited in the following order. -All ledgers are visited from the ledger with high index to the ledger with -low index in descending order. For each ledger the state SHAmap is visited -first using visitNode function for the ledger with highest index and -visitDifferences function for other ledgers. Then transaction SHAmap is visited -using visitNodes function. At last, the ledger header object is visited. -Final key of the shard is visited at the end. - - -## Tests - -To perform test to deterministic shards implementation one can enter -the following command: -``` -rippled --unittest ripple.NodeStore.DatabaseShard -``` - -The following is the right output of deterministic shards test: -``` -ripple.NodeStore.DatabaseShard DatabaseShard deterministic_shard -with backend nudb -Iteration 0: RIPEMD160[nudb.key] = F96BF2722AB2EE009FFAE4A36AAFC4F220E21951 -Iteration 0: RIPEMD160[nudb.dat] = FAE6AE84C15968B0419FDFC014931EA12A396C71 -Iteration 1: RIPEMD160[nudb.key] = F96BF2722AB2EE009FFAE4A36AAFC4F220E21951 -Iteration 1: RIPEMD160[nudb.dat] = FAE6AE84C15968B0419FDFC014931EA12A396C71 -``` diff --git a/src/xrpld/nodestore/Manager.h b/src/xrpld/nodestore/Manager.h index 5a4d46068be..89ed165b483 100644 --- a/src/xrpld/nodestore/Manager.h +++ b/src/xrpld/nodestore/Manager.h @@ -21,7 +21,6 @@ #define RIPPLE_NODESTORE_MANAGER_H_INCLUDED #include -#include #include namespace ripple { diff --git a/src/xrpld/nodestore/README.md b/src/xrpld/nodestore/README.md index 7b004f67a42..1549c1ef968 100644 --- a/src/xrpld/nodestore/README.md +++ b/src/xrpld/nodestore/README.md @@ -1,8 +1,6 @@ # Database Documentation * [NodeStore](#nodestore) * [Benchmarks](#benchmarks) -* [Downloaded Shard Validation](#downloaded-shard-validation) -* [Shard Storage Paths](#shard-storage-paths) # NodeStore @@ -176,195 +174,3 @@ instruction not being used. * Important point to note that is if this factory is tested with an existing set of sst files none of the old sst files will benefit from indexing changes until they are compacted at a future point in time. - -# Downloaded Shard Validation - -## Overview - -In order to validate shards that have been downloaded from file servers (as -opposed to shards acquired from peers), the application must confirm the -validity of the downloaded shard's last ledger. So before initiating the -download, we first confirm that we are able to retrieve the shard's last ledger -hash. The following sections describe this confirmation process in greater -detail. - -## Hash Verification - -### Flag Ledger - -Since the number of ledgers contained in each shard is always a multiple of 256, -a shard's last ledger is always a flag ledger. Conveniently, the skip list -stored within a ledger will provide us with a series of flag ledger hashes, -enabling the software to corroborate a shard's last ledger hash. We access the -skip list by calling `LedgerMaster::walkHashBySeq` and providing the sequence of -a shard's last ledger: - -```C++ -std::optional expectedHash; -expectedHash = - app_.getLedgerMaster().walkHashBySeq(lastLedgerSeq(shardIndex)); -``` - -When a user requests a shard download, the `ShardArchiveHandler` will first use -this function to retrieve the hash of the shard's last ledger. If the function -returns a hash, downloading the shard can proceed. Once the download completes, -the server can reliably retrieve this last ledger hash to complete validation of -the shard. - -### Caveats - -#### Later Ledger - -The `walkHashBySeq` function will provide the hash of a flag ledger only if the -application has stored a later ledger. When verifying the last ledger hash of a -pending shard download, if there is no later ledger stored, the download will be -deferred until a later ledger has been stored. - -We use the presence (or absence) of a validated ledger with a sequence number -later than the sequence of the shard's last ledger as a heuristic for -determining whether or not we should have the shard's last ledger hash. A later -ledger must be present in order to reliably retrieve the hash of the shard's -last ledger. The hash will only be retrieved when a later ledger is present. -Otherwise verification of the shard will be deferred. - -### Retries - -#### Retry Limit - -If the server must defer hash verification, the software will initiate a timer -that upon expiration, will re-attempt verifying the last ledger hash. We place -an upper limit on the number of attempts the server makes to achieve this -verification. When the maximum number of attempts has been reached, the download -request will fail, and the `ShardArchiveHandler` will proceed with any remaining -downloads. An attempt counts toward the limit only when we are able to get a -later validated ledger (implying a current view of the network), but are unable -to retrieve the last ledger hash. Retries that occur because no validated ledger -was available are not counted. - -# Shard Storage Paths - -## Overview - -The shard database stores validated ledgers in logical groups called shards. As -of June 2020, a shard stores 16384 ledgers by default. In order to allow users -to store shards on multiple devices, the shard database can be configured with -several file system paths. Each path provided should refer to a directory on a -distinct filesystem, and no two paths should ever correspond to the same -filesystem. Violating this restriction will cause the server to inaccurately -estimate the amount of space available for storing shards. In the absence of a -suitable platform agnostic solution, this requirement is enforced only on -Linux. However, on other platforms we employ a heuristic that issues a warning -if we suspect that this restriction is violated. - -## Configuration - -The `shard_db` and `historical_shard_paths` sections of the server's -configuration file will be used to determine where the server stores shards. -Minimally, the `shard_db` section must contain a single `path` key. -If this is the only storage path provided, all shards will be stored at this -location. If the configuration also lists one or more lines in the -`historical_shard_paths` section, all older shards will be stored at these -locations, and the `path` will be used only to store the current -and previous shards. The goal is to allow users to provide an efficient SSD for -storing recent shards, as these will be accessed more frequently, while using -large mechanical drives for storing older shards that will be accessed less -frequently. - -Below is a sample configuration snippet that provides a path for main storage -and several paths for historical storage: - -```dosini -# This is the persistent datastore for shards. It is important for the health -# of the network that server operators shard as much as practical. -# NuDB requires SSD storage. Helpful information can be found on -# https://xrpl.org/history-sharding.html -[shard_db] -type=NuDB - -# A single path for storing -# the current and previous -# shards: -# ------------------------- -path=/var/lib/rippled/db/shards/nudb - -# Path where shards are stored -# while being downloaded: -# ---------------------------- -download_path=/var/lib/rippled/db/shards/ - -# The number of historical shards to store. -# The default value is 0, which means that -# the server won't store any historical -# shards - only the current and previous -# shards will be stored. -# ------------------------------------ -max_historical_shards=100 - -# List of paths for storing older shards. -[historical_shard_paths] -/mnt/disk1 -/mnt/disk2 -/mnt/disk3 - -``` -## Shard Migration - -When a new shard (*current shard*) is confirmed by the network, the recent -shards will shift. The *previous shard* will become a *historical shard*, the -*current shard* will become the *previous shard*, and the new shard will become -the *current shard*. These are just logical labels, and the shards themselves -don't change to reflect being current, previous, or historical. However, if the -server's configuration specifies one or more paths for historical storage, -during this shift the formerly *previous shard* will be migrated to one of the -historical paths. If multiple paths are provided, the server dynamically -chooses one with sufficient space for storing the shard. - -**Note:** As of June 2020, the shard database does not store the partial shard -currently being built by live network transactions, but this is planned to -change. When this feature is implemented, the *current shard* will refer to this -partial shard, and the *previous shard* will refer to the most recently -validated shard. - -### Selecting a Historical Storage Path - -When storing historical shards, if multiple historical paths are provided, the -path to use for each shard will be selected in a random fashion. By using all -available storage devices, we create a uniform distribution of disk utilization -for disks of equivalent size, (provided that the disks are used only to store -shards). In theory, selecting devices in this manner will also increase our -chances for concurrent access to stored shards, however as of June 2020 -concurrent shard access is not implemented. Lastly, a storage path is included -in the random distribution only if it has enough storage capacity to hold the -next shard. - -## Shard Acquisition - -When the server is acquiring shard history, these acquired shards will be stored -at a path designated for historical storage (`historical_storage_path`). If no -such path is provided, acquired shards will be stored at the -`path`. - -## Storage capacity - -### Filesystem Capacity - -When the shard database updates its record of disk utilization, it trusts that -the provided historical paths refer to distinct devices, or at least distinct -filesystems. If this requirement is violated, the database will operate with an -inaccurate view of how many shards it can store. Violation of this requirement -won't necessarily impede database operations, but the database will fail to -identify scenarios wherein storing the maximum number of historical shards (as -per the 'historical_shard_count' parameter in the configuration file) would -exceed the amount of storage space available. - -### Shard Migration - -During a "recent shard shift", if the server has already reached the configured -limit of stored historical shards, instead of moving the formerly *previous -shard* to a historical drive (or keeping it at the 'path') the -shard will be dropped and removed from the filesystem. - -### Shard Acquisition - -Once the configured limit of stored historical shards has been reached, shard -acquisition halts, and no additional shards will be acquired. diff --git a/src/xrpld/nodestore/ShardInfo.h b/src/xrpld/nodestore/ShardInfo.h deleted file mode 100644 index b894ddc34a3..00000000000 --- a/src/xrpld/nodestore/ShardInfo.h +++ /dev/null @@ -1,122 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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_NODESTORE_SHARDINFO_H_INCLUDED -#define RIPPLE_NODESTORE_SHARDINFO_H_INCLUDED - -#include -#include -#include - -namespace ripple { -namespace NodeStore { - -/* Contains information on the status of shards for a node - */ -class ShardInfo -{ -private: - class Incomplete - { - public: - Incomplete() = delete; - Incomplete(ShardState state, std::uint32_t percentProgress) - : state_(state), percentProgress_(percentProgress) - { - } - - [[nodiscard]] ShardState - state() const noexcept - { - return state_; - } - - [[nodiscard]] std::uint32_t - percentProgress() const noexcept - { - return percentProgress_; - } - - private: - ShardState state_; - std::uint32_t percentProgress_; - }; - -public: - [[nodiscard]] NetClock::time_point const& - msgTimestamp() const - { - return msgTimestamp_; - } - - void - setMsgTimestamp(NetClock::time_point const& timestamp) - { - msgTimestamp_ = timestamp; - } - - [[nodiscard]] std::string - finalizedToString() const; - - [[nodiscard]] bool - setFinalizedFromString(std::string const& str) - { - return from_string(finalized_, str); - } - - [[nodiscard]] RangeSet const& - finalized() const - { - return finalized_; - } - - [[nodiscard]] std::string - incompleteToString() const; - - [[nodiscard]] std::map const& - incomplete() const - { - return incomplete_; - } - - // Returns true if successful or false because of a duplicate index - bool - update( - std::uint32_t shardIndex, - ShardState state, - std::uint32_t percentProgress); - - [[nodiscard]] protocol::TMPeerShardInfoV2 - makeMessage(Application& app); - -private: - // Finalized immutable shards - RangeSet finalized_; - - // Incomplete shards being acquired or finalized - std::map incomplete_; - - // Message creation time - NetClock::time_point msgTimestamp_; -}; - -} // namespace NodeStore -} // namespace ripple - -#endif diff --git a/src/xrpld/nodestore/ShardPool.md b/src/xrpld/nodestore/ShardPool.md deleted file mode 100644 index 2079feabb4e..00000000000 --- a/src/xrpld/nodestore/ShardPool.md +++ /dev/null @@ -1,43 +0,0 @@ -# Open Shard Management - -## Overview - -Shard NuDB and SQLite databases consume server resources. This can be unnecessarily taxing on servers with many shards. The open shard management feature aims to improve the situation by managing a limited number of open shard database connections. The feature, which is integrated into the existing DatabaseShardImp and Shard classes, maintains a limited pool of open databases prioritized by their last use time stamp. The following sections describe the feature in greater detail. - -### Open Shard Management - -The open shard management feature is integrated into the DatabaseShardImp and Shard classes. As the DatabaseShardImp sweep function is periodically called, the number of finalized open shards, which constitutes the open pool, are examined. Upon the pool exceeding a pool limit, an attempt is made to close enough open shards to remain within the limit. Shards to be closed are selected based on their last use time stamp, which is automatically updated on database access. If necessary, shards will automatically open their databases when accessed. - -```C++ - if (openFinals.size() > openFinalLimit_) - { - // Try to close enough shards to be within the limit. - // Sort on largest elapsed time since last use. - std::sort( - openFinals.begin(), - openFinals.end(), - [&](std::shared_ptr const& lhsShard, - std::shared_ptr const& rhsShard) { - return lhsShard->getLastUse() > rhsShard->getLastUse(); - }); - - for (auto it{openFinals.cbegin()}; - it != openFinals.cend() && openFinals.size() > openFinalLimit_;) - { - if ((*it)->tryClose()) - it = openFinals.erase(it); - else - ++it; - } - } -``` - -### Shard - -When closing an open shard, DatabaseShardImp will call the Shard 'tryClose' function. This function will only close the shard databases if there are no outstanding references. - -DatabaseShardImp will use the Shard 'isOpen' function to determine the state of a shard's database. - -### Caveats - -The Shard class must check the state of its databases before use. Prior use assumed databases were always open, that is no longer the case with the open shard management feature. diff --git a/src/xrpld/nodestore/ShardSizeTuning.md b/src/xrpld/nodestore/ShardSizeTuning.md deleted file mode 100644 index bded73c43c5..00000000000 --- a/src/xrpld/nodestore/ShardSizeTuning.md +++ /dev/null @@ -1,213 +0,0 @@ -# Shard size Tuning - -The purpose of this document is to compare the sizes of shards containing -varying amounts of ledgers. - -## Methodology - -One can see visually from a block explorer that a typical mainnet ledger -consists of about 30 offer transactions issued by about 8 different accounts, -and several transactions of other types. To simulate this situation and -similar situations we have constructed deterministic shards of differenet -sizes, with varying amounts of offers per ledger and varying amounts of -accounts issuing these offers. - -In the following results table, the number of ledgers per shard ranges from 256 -to 16K with the size doubling the size at each step. We considered the -following numbers of offers per ledger: 0, 1, 5, 10 and 30. Also we considered -case of 1 and 8 accounts issuing offers. For each constructed deterministic -shard we counted its size. Finally we compared doubled size of the shard with -N ledgers and the size of a shard with 2*N ledgers where othere parameters such -as number of offers and accounts are the same. This comparison is sufficient to -determine which number of ledgers per shard leads to less storage size on the -disk. - -Note that we minimize total storage size on the disk, but not the size of each -shard because data below shows that the size of a typical shard is not larger -than 10G, but sizes of modern disks, even SSDs, start from 250G. So there is -no problem to fit a single shard to a disk, even small. - - -## Raw results table - -All sizes of constructed shards are shown in the following table. -Rows corresponds to shard sizes (S) counted in ledgers, columns corresponds -to numbers of offers (O) per ledger. In each cell there are two numbers: -first number corresponds to the case of 1 account issuing offers, the second -number corresponds to 8 accounts. Each number is a size of the shard with -given parameters measured in megabytes. - -|S\O|0|1|5|10|30| -|---|---|---|---|---|---| -|256|2.2/2.2|3.4/3.3|5.3/7.3|7.7/10.9|17.1/21.9| -|512|4.4/4.5|7.0/7.0|11.2/15.6|16.4/23.7|36.9/47.9| -|1K|8.9/9.0|14.7/14.6|23.7/33.6|35.0/51.0|78.2/ 102.9| -|2K|17.8/18.0|30.5/30.7|50.4/72.2|74.3/ 111.9|166.2/ 221.0| -|4K|35.5/35.9|63.6/64.2|106.2/ 154.8|156.1/ 238.7|354.7/ 476.0| -|8K|71.1/71.9|133.4/ 134.5|222.2/ 328.1|329.1/ 511.2|754.6/ 1021.0| -|16K|142.3/ 143.9|279/9 280.8|465.7/ 698.1|696.4/ 1094.2|1590.5/ 2166.6| - -## Preliminary conclusion - -If one compares a doubled size of shard with N ledgers and a size of shard -with 2*N ledgers anywhere in the above table than the conlusion will be that -the second number is greater. For example, the following table shows the -percentage by which the second number is greater for the most interesting case -of 30 offers per ledger. The first row corresponds to the case of 1 account -issuing offers, and the second row corresponds to the case of 8 issuing -accounts. - -|A\N|256|512|1K|2K|4K|8K| -|---|---|---|---|---|---|---| -|1|8%|6%|6%|6%|7%|6%|5%| -|8|9%|7%|7%|8%|6%|7%|6%| - -The common conclusion in this model is that if one doubled the number of -the ledgers in a shard then the total disk space utilized will raise by 5-9%. - -## Adding accounts into consideration - -Previous model does not take into account that there are large number of -XRP accounts in the mainnet, and each shard should contain information -about each of these accounts. As of January 2020, there were about 1.9 million -XRP accounts, and stored information about each of them is not less than 133 -bytes. The constant 133 was obtained from debug print of rippled program when -it saves account object to the database. So the actual size of each shard from -raw table should be increased by at least 1.9M * 133 = 252.7M. Thus we obtained -the following table of shard sizes for the most interesting case (30 offers -per ledger and 8 issuing accounts) where S is shard size in ledgers and M is -shard size in megabytes - -|S|256|512|1K|2K|4K|8K|16K| -|---|---|---|---|---|---|---|---| -|M|274.6|300.6|355.6|473.7|728.7|1273.7|2419.3| - -Now we can see from the last table that even considering minimum assumption -about number of accounts and corresponding additional size of a shard, -doubled size of shard with N ledgers is larger than size of a shard with -2*N ledgers. If number of accounts increase then this inequality will be -even stronger. - -## Using mainnet data - -Next idea to improve model is to count real shard sizes from mainnet. -We used real 16k-ledgers shards with indexes from 2600 to 3600 with step 100, -and corresponding real 8k-ledgers shards. Each 16k-ledgers shard consists -of two 8k-ledgers shards which are called "corresponding". For example, -16k-ledgers shard with index 2600 consists of two 8k-ledgers shards with -indexes 5200 and 5201. - -In the following table we compare size of a 16k-ledgers shard with sum of sizes -of two corresponding 8k-ledgers shards. There we only count size of nudb.dat -file, sizes are in GB. Ratio is the size of two 8k-ledgers shards divided -to the size of 16k-ledgers shard. - -|Index|16k-ledgers|8k-ledgers sum|Ratio| -|---|---|---|---| -|2600|2.39|1.49 + 1.63 = 3.12|1.31| -|2700|2.95|1.77 + 1.94 = 3.71|1.26| -|2800|2.53|1.54 + 1.75 = 3.29|1.30| -|2900|3.83|2.26 + 2.35 = 4.61|1.20| -|3000|4.49|2.70 + 2.59 = 5.29|1.18| -|3100|3.79|2.35 + 2.25 = 4.60|1.21| -|3200|4.15|2.54 + 2.43 = 4.97|1.20| -|3300|5.19|3.23 + 2.80 = 6.03|1.16| -|3400|4.18|2.53 + 2.51 = 5.04|1.21| -|3500|5.06|2.90 + 3.04 = 5.94|1.17| -|3600|4.18|2.56 + 2.51 = 5.07|1.21| -|Average|3.89|2.35 + 2.35 = 4.70|1.21| - -Note that shard on the disk consists of 4 files each of which can be large too. -These files are nudb.dat, nudb.key, ledger.db, transaction.db. Next table is -similar to previous with the following exception: each number is total size -of these 2 files: nudb.dat and nudb.key. We decided not to count sizes of -ledger.db and transaction.db since these sizes are not permanent instead of -sizes of nudb.* which are permanent for deterministic shards. - -|Index|16k-ledgers|8k-ledgers sum|Ratio| -|---|---|---|---| -|2600|2.76|1.73 + 1.89 = 3.62|1.31| -|2700|3.40|2.05 + 2.25 = 4.30|1.26| -|2800|2.91|1.79 + 2.02 = 3.81|1.31| -|2900|4.40|2.62 + 2.71 = 5.33|1.21| -|3000|5.09|3.09 + 2.96 = 6.05|1.19| -|3100|4.29|2.69 + 2.57 = 5.26|1.23| -|3200|4.69|2.90 + 2.78 = 5.68|1.21| -|3300|5.92|3.72 + 3.21 = 6.93|1.17| -|3400|4.77|2.91 + 2.89 = 5.80|1.22| -|3500|5.73|3.31 + 3.47 = 6.78|1.18| -|3600|4.77|2.95 + 2.90 = 5.85|1.23| -|Average|4.43|2.70 + 2.70 = 5.40|1.22| - -We can see that in all tables ratio is greater then 1, so using shards with -16 ledgers is preferred. - -## Compare 16K shards and 32K shards - -To claim that shards with 16K ledgers are the best choice, we also assembled -shards with 32k ledgers per shard with indexes from 1300 to 1800 with step 50 -and corresponding shards with 16k ledgers per shard. For example, 32k-ledgers -shard 1800 correnspond to 16k-ledgers shards with indexes 3600 and 3601 etc. - -Here are result tables for these shards similar to tables from previous part. -In the first table we only take into consideration sizes of nudb.dat files. - -|Index|32k-ledgers|16k-ledgers sum|Ratio| -|---|---|---|---| -|1300|4.00|2.39 + 2.32 = 4.71|1.18| -|1350|5.23|2.95 + 3.02 = 5.97|1.14| -|1400|4.37|2.53 + 2.59 = 5.12|1.17| -|1450|7.02|3.83 + 3.98 = 7.81|1.11| -|1500|7.53|4.49 + 3.86 = 8.35|1.11| -|1550|6.85|3.79 + 3.89 = 7.68|1.12| -|1600|7.28|4.15 + 3.99 = 8.14|1.12| -|1650|8.10|5.19 + 3.76 = 8.95|1.10| -|1700|7.58|4.18 + 4.27 = 8.45|1.11| -|1750|8.95|5.06 + 4.77 = 9.83|1.10| -|1800|7.29|4.18 + 4.02 = 8.20|1.12| -|Average|6.75|3.88 + 3.68 = 7.56|1.12| - -In the second table we take into consideration total sizes of files nudb.dat -and nudb.key. - -|Index|32k-ledgers|16k-ledgers sum|Ratio| -|---|---|---|---| -|1300|4.59|2.76 + 2.68 = 5.44|1.19| -|1350|5.98|3.40 + 3.47 = 6.87|1.15| -|1400|4.99|2.91 + 2.98 = 5.89|1.18| -|1450|8.02|4.40 + 4.56 = 8.96|1.12| -|1500|8.51|5.09 + 4.39 = 9.48|1.11| -|1550|7.73|4.29 + 4.42 = 8.71|1.13| -|1600|8.20|4.69 + 4.52 = 9.21|1.12| -|1650|9.20|5.92 + 4.29 = 10.21|1.11| -|1700|8.61|4.77 + 4.87 = 9.64|1.12| -|1750|10.09|5.73 + 5.41 = 11.14|1.10| -|1800|8.27|4.77 + 4.59 = 9.36|1.13| -|Average|7.69|4.43 + 4.20 = 8.63|1.12| - -## Conclusion - -We showed that using shards with 8k ledgers leads to raising required disk size -by 22% in comparison with using shards with 16k ledgers. In the same way, -using shards with 16k ledgers leads to raising required disk space by 12% -in comparison with using shards with 32k ledgers. Note that increase ratio 12% -is much less than 22% so using 32k-ledgers shards will bring us not so much -economy in disk space. - -At the same time, size is one thing to compare but there are other aspects. -Smaller shards have an advantage that they take less time to acquire and -finalize. They also make for smaller archived shards which take less time to -download and import. Having more/smaller shards might also lead to better -database concurrency/performance. - -It is hard to maintain both size and time parameters by a single optimization -formulae because different choices for weights of size and time may lead to -different results. But using "common sense" arguments we can compare -16k-ledgers shards and 32k-ledgers as follows: using 32k-ledgers shards give us -12% advantage in size, and about 44% disadvantage in time, because average size -of 16k-ledgers shard is about 56% of average 32k-ledgers shard. At the same, -if we compare 16k-ledgers shards with 8k-ledgers, then the first has 22% -advantage in size and 39% disadvantage in time. So the balance of -advantages/disadvantages is better when we use 16k-ledgers shards. - -Thus we recommend use shards with 16K ledgers. diff --git a/src/xrpld/nodestore/Types.h b/src/xrpld/nodestore/Types.h index 39104f946e3..a5792fe7df3 100644 --- a/src/xrpld/nodestore/Types.h +++ b/src/xrpld/nodestore/Types.h @@ -56,15 +56,6 @@ using Batch = std::vector>; } // namespace NodeStore -/** Shard states. */ -enum class ShardState : std::uint32_t { - acquire, // Acquiring ledgers - complete, // Backend is ledger complete, database is unverified - finalizing, // Verifying database - finalized, // Database verified, shard is immutable - queued // Queued to be finalized -}; - } // namespace ripple #endif diff --git a/src/xrpld/nodestore/backend/NuDBFactory.cpp b/src/xrpld/nodestore/backend/NuDBFactory.cpp index 742bf05031b..14cd84a1ad7 100644 --- a/src/xrpld/nodestore/backend/NuDBFactory.cpp +++ b/src/xrpld/nodestore/backend/NuDBFactory.cpp @@ -38,11 +38,11 @@ namespace NodeStore { class NuDBBackend : public Backend { public: - static constexpr std::uint64_t currentType = 1; - static constexpr std::uint64_t deterministicMask = 0xFFFFFFFF00000000ull; - - /* "SHRD" in ASCII */ - static constexpr std::uint64_t deterministicType = 0x5348524400000000ull; + // "appnum" is an application-defined constant stored in the header of a + // NuDB database. We used it to identify shard databases before that code + // was removed. For now, its only use is a sanity check that the database + // was created by xrpld. + static constexpr std::uint64_t appnum = 1; beast::Journal const j_; size_t const keyBytes_; @@ -149,16 +149,7 @@ class NuDBBackend : public Backend if (ec) Throw(ec); - /** Old value currentType is accepted for appnum in traditional - * databases, new value is used for deterministic shard databases. - * New 64-bit value is constructed from fixed and random parts. - * Fixed part is bounded by bitmask deterministicMask, - * and the value of fixed part is deterministicType. - * Random part depends on the contents of the shard and may be any. - * The contents of appnum field should match either old or new rule. - */ - if (db_.appnum() != currentType && - (db_.appnum() & deterministicMask) != deterministicType) + if (db_.appnum() != appnum) Throw("nodestore: unknown appnum"); db_.set_burst(burstSize_); } @@ -172,7 +163,7 @@ class NuDBBackend : public Backend void open(bool createIfMissing) override { - open(createIfMissing, currentType, nudb::make_uid(), nudb::make_salt()); + open(createIfMissing, appnum, nudb::make_uid(), nudb::make_salt()); } void diff --git a/src/xrpld/nodestore/detail/Database.cpp b/src/xrpld/nodestore/detail/Database.cpp index 93468eb6084..60cfb35051c 100644 --- a/src/xrpld/nodestore/detail/Database.cpp +++ b/src/xrpld/nodestore/detail/Database.cpp @@ -17,7 +17,6 @@ */ //============================================================================== -#include #include #include #include @@ -36,21 +35,13 @@ Database::Database( beast::Journal journal) : j_(journal) , scheduler_(scheduler) - , ledgersPerShard_(get( - config, - "ledgers_per_shard", - DEFAULT_LEDGERS_PER_SHARD)) , earliestLedgerSeq_( get(config, "earliest_seq", XRP_LEDGER_EARLIEST_SEQ)) - , earliestShardIndex_((earliestLedgerSeq_ - 1) / ledgersPerShard_) , requestBundle_(get(config, "rq_bundle", 4)) , readThreads_(std::max(1, readThreads)) { assert(readThreads != 0); - if (ledgersPerShard_ == 0 || ledgersPerShard_ % 256 != 0) - Throw("Invalid ledgers_per_shard"); - if (earliestLedgerSeq_ < 1) Throw("Invalid earliest_seq"); @@ -148,19 +139,6 @@ Database::isStopping() const return readStopping_.load(std::memory_order_relaxed); } -std::uint32_t -Database::maxLedgers(std::uint32_t shardIndex) const noexcept -{ - if (shardIndex > earliestShardIndex_) - return ledgersPerShard_; - - if (shardIndex == earliestShardIndex_) - return lastLedgerSeq(shardIndex) - firstLedgerSeq(shardIndex) + 1; - - assert(!"Invalid shard index"); - return 0; -} - void Database::stop() { @@ -275,105 +253,6 @@ Database::fetchNodeObject( return nodeObject; } -bool -Database::storeLedger( - Ledger const& srcLedger, - std::shared_ptr dstBackend) -{ - auto fail = [&](std::string const& msg) { - JLOG(j_.error()) << "Source ledger sequence " << srcLedger.info().seq - << ". " << msg; - return false; - }; - - if (srcLedger.info().hash.isZero()) - return fail("Invalid hash"); - if (srcLedger.info().accountHash.isZero()) - return fail("Invalid account hash"); - - auto& srcDB = const_cast(srcLedger.stateMap().family().db()); - if (&srcDB == this) - return fail("Source and destination databases are the same"); - - Batch batch; - batch.reserve(batchWritePreallocationSize); - auto storeBatch = [&, fname = __func__]() { - std::uint64_t sz{0}; - for (auto const& nodeObject : batch) - sz += nodeObject->getData().size(); - - try - { - dstBackend->storeBatch(batch); - } - catch (std::exception const& e) - { - fail( - std::string("Exception caught in function ") + fname + - ". Error: " + e.what()); - return false; - } - - storeStats(batch.size(), sz); - batch.clear(); - return true; - }; - - // Store ledger header - { - Serializer s(sizeof(std::uint32_t) + sizeof(LedgerInfo)); - s.add32(HashPrefix::ledgerMaster); - addRaw(srcLedger.info(), s); - auto nObj = NodeObject::createObject( - hotLEDGER, std::move(s.modData()), srcLedger.info().hash); - batch.emplace_back(std::move(nObj)); - } - - bool error = false; - auto visit = [&](SHAMapTreeNode& node) { - if (!isStopping()) - { - if (auto nodeObject = srcDB.fetchNodeObject( - node.getHash().as_uint256(), srcLedger.info().seq)) - { - batch.emplace_back(std::move(nodeObject)); - if (batch.size() < batchWritePreallocationSize || storeBatch()) - return true; - } - } - - error = true; - return false; - }; - - // Store the state map - if (srcLedger.stateMap().getHash().isNonZero()) - { - if (!srcLedger.stateMap().isValid()) - return fail("Invalid state map"); - - srcLedger.stateMap().snapShot(false)->visitNodes(visit); - if (error) - return fail("Failed to store state map"); - } - - // Store the transaction map - if (srcLedger.info().txHash.isNonZero()) - { - if (!srcLedger.txMap().isValid()) - return fail("Invalid transaction map"); - - srcLedger.txMap().snapShot(false)->visitNodes(visit); - if (error) - return fail("Failed to store transaction map"); - } - - if (!batch.empty() && !storeBatch()) - return fail("Failed to store"); - - return true; -} - void Database::getCountsJson(Json::Value& obj) { diff --git a/src/xrpld/nodestore/detail/DatabaseNodeImp.cpp b/src/xrpld/nodestore/detail/DatabaseNodeImp.cpp index d61c68e759a..85e5d3c0da9 100644 --- a/src/xrpld/nodestore/detail/DatabaseNodeImp.cpp +++ b/src/xrpld/nodestore/detail/DatabaseNodeImp.cpp @@ -17,7 +17,6 @@ */ //============================================================================== -#include #include #include diff --git a/src/xrpld/nodestore/detail/DatabaseNodeImp.h b/src/xrpld/nodestore/detail/DatabaseNodeImp.h index f5f5f64bd1d..c2bf237b943 100644 --- a/src/xrpld/nodestore/detail/DatabaseNodeImp.h +++ b/src/xrpld/nodestore/detail/DatabaseNodeImp.h @@ -128,12 +128,6 @@ class DatabaseNodeImp : public Database std::function const&)>&& callback) override; - bool - storeLedger(std::shared_ptr const& srcLedger) override - { - return Database::storeLedger(*srcLedger, backend_); - } - void sweep() override; diff --git a/src/xrpld/nodestore/detail/DatabaseRotatingImp.cpp b/src/xrpld/nodestore/detail/DatabaseRotatingImp.cpp index b1283d7de71..58cc3599dc6 100644 --- a/src/xrpld/nodestore/detail/DatabaseRotatingImp.cpp +++ b/src/xrpld/nodestore/detail/DatabaseRotatingImp.cpp @@ -17,7 +17,6 @@ */ //============================================================================== -#include #include #include @@ -79,17 +78,6 @@ DatabaseRotatingImp::importDatabase(Database& source) importInternal(*backend, source); } -bool -DatabaseRotatingImp::storeLedger(std::shared_ptr const& srcLedger) -{ - auto const backend = [&] { - std::lock_guard lock(mutex_); - return writableBackend_; - }(); - - return Database::storeLedger(*srcLedger, backend); -} - void DatabaseRotatingImp::sync() { diff --git a/src/xrpld/nodestore/detail/DatabaseRotatingImp.h b/src/xrpld/nodestore/detail/DatabaseRotatingImp.h index ec46fc687be..0c17dc59ceb 100644 --- a/src/xrpld/nodestore/detail/DatabaseRotatingImp.h +++ b/src/xrpld/nodestore/detail/DatabaseRotatingImp.h @@ -75,9 +75,6 @@ class DatabaseRotatingImp : public DatabaseRotating void sync() override; - bool - storeLedger(std::shared_ptr const& srcLedger) override; - void sweep() override; diff --git a/src/xrpld/nodestore/detail/DatabaseShardImp.cpp b/src/xrpld/nodestore/detail/DatabaseShardImp.cpp deleted file mode 100644 index c7e45641d7f..00000000000 --- a/src/xrpld/nodestore/detail/DatabaseShardImp.cpp +++ /dev/null @@ -1,2253 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2017 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#if BOOST_OS_LINUX -#include -#endif - -namespace ripple { - -namespace NodeStore { - -DatabaseShardImp::DatabaseShardImp( - Application& app, - Scheduler& scheduler, - int readThreads, - beast::Journal j) - : DatabaseShard( - scheduler, - readThreads, - app.config().section(ConfigSection::shardDatabase()), - j) - , app_(app) - , avgShardFileSz_(ledgersPerShard_ * kilobytes(192ull)) - , openFinalLimit_( - app.config().getValueFor(SizedItem::openFinalLimit, std::nullopt)) -{ - if (app.config().reporting()) - { - Throw( - "Attempted to create DatabaseShardImp in reporting mode. Reporting " - "does not support shards. Remove shards info from config"); - } -} - -bool -DatabaseShardImp::init() -{ - { - std::lock_guard lock(mutex_); - if (init_) - { - JLOG(j_.error()) << "already initialized"; - return false; - } - - if (!initConfig(lock)) - { - JLOG(j_.error()) << "invalid configuration file settings"; - return false; - } - - try - { - using namespace boost::filesystem; - - // Consolidate the main storage path and all historical paths - std::vector paths{dir_}; - paths.insert( - paths.end(), historicalPaths_.begin(), historicalPaths_.end()); - - for (auto const& path : paths) - { - if (exists(path)) - { - if (!is_directory(path)) - { - JLOG(j_.error()) << path << " must be a directory"; - return false; - } - } - else if (!create_directories(path)) - { - JLOG(j_.error()) - << "failed to create path: " + path.string(); - return false; - } - } - - if (!app_.config().standalone() && !historicalPaths_.empty()) - { - // Check historical paths for duplicated file systems - if (!checkHistoricalPaths(lock)) - return false; - } - - ctx_ = std::make_unique(); - ctx_->start(); - - // Find shards - std::uint32_t openFinals{0}; - for (auto const& path : paths) - { - for (auto const& it : directory_iterator(path)) - { - // Ignore files - if (!is_directory(it)) - continue; - - // Ignore nonnumerical directory names - auto const shardDir{it.path()}; - auto dirName{shardDir.stem().string()}; - if (!std::all_of( - dirName.begin(), dirName.end(), [](auto c) { - return ::isdigit(static_cast(c)); - })) - { - continue; - } - - // Ignore values below the earliest shard index - auto const shardIndex{std::stoul(dirName)}; - if (shardIndex < earliestShardIndex_) - { - JLOG(j_.debug()) - << "shard " << shardIndex - << " ignored, comes before earliest shard index " - << earliestShardIndex_; - continue; - } - - // Check if a previous database import failed - if (is_regular_file(shardDir / databaseImportMarker_)) - { - JLOG(j_.warn()) - << "shard " << shardIndex - << " previously failed database import, removing"; - remove_all(shardDir); - continue; - } - - auto shard{std::make_shared( - app_, *this, shardIndex, shardDir.parent_path(), j_)}; - if (!shard->init(scheduler_, *ctx_)) - { - // Remove corrupted or legacy shard - shard->removeOnDestroy(); - JLOG(j_.warn()) - << "shard " << shardIndex << " removed, " - << (shard->isLegacy() ? "legacy" : "corrupted") - << " shard"; - continue; - } - - switch (shard->getState()) - { - case ShardState::finalized: - if (++openFinals > openFinalLimit_) - shard->tryClose(); - shards_.emplace(shardIndex, std::move(shard)); - break; - - case ShardState::complete: - finalizeShard( - shards_.emplace(shardIndex, std::move(shard)) - .first->second, - true, - std::nullopt); - break; - - case ShardState::acquire: - if (acquireIndex_ != 0) - { - JLOG(j_.error()) - << "more than one shard being acquired"; - return false; - } - - shards_.emplace(shardIndex, std::move(shard)); - acquireIndex_ = shardIndex; - break; - - default: - JLOG(j_.error()) - << "shard " << shardIndex << " invalid state"; - return false; - } - } - } - } - catch (std::exception const& e) - { - JLOG(j_.fatal()) << "Exception caught in function " << __func__ - << ". Error: " << e.what(); - return false; - } - - init_ = true; - } - - updateFileStats(); - return true; -} - -std::optional -DatabaseShardImp::prepareLedger(std::uint32_t validLedgerSeq) -{ - std::optional shardIndex; - - { - std::lock_guard lock(mutex_); - assert(init_); - - if (acquireIndex_ != 0) - { - if (auto const it{shards_.find(acquireIndex_)}; it != shards_.end()) - return it->second->prepare(); - - // Should never get here - assert(false); - return std::nullopt; - } - - if (!canAdd_) - return std::nullopt; - - shardIndex = findAcquireIndex(validLedgerSeq, lock); - } - - if (!shardIndex) - { - JLOG(j_.debug()) << "no new shards to add"; - { - std::lock_guard lock(mutex_); - canAdd_ = false; - } - return std::nullopt; - } - - auto const pathDesignation = [this, shardIndex = *shardIndex]() { - std::lock_guard lock(mutex_); - return prepareForNewShard(shardIndex, numHistoricalShards(lock), lock); - }(); - - if (!pathDesignation) - return std::nullopt; - - auto const needsHistoricalPath = - *pathDesignation == PathDesignation::historical; - - auto shard = [this, shardIndex, needsHistoricalPath] { - std::lock_guard lock(mutex_); - return std::make_unique( - app_, - *this, - *shardIndex, - (needsHistoricalPath ? chooseHistoricalPath(lock) : ""), - j_); - }(); - - if (!shard->init(scheduler_, *ctx_)) - return std::nullopt; - - auto const ledgerSeq{shard->prepare()}; - { - std::lock_guard lock(mutex_); - shards_.emplace(*shardIndex, std::move(shard)); - acquireIndex_ = *shardIndex; - updatePeers(lock); - } - - return ledgerSeq; -} - -bool -DatabaseShardImp::prepareShards(std::vector const& shardIndexes) -{ - auto fail = [j = j_, &shardIndexes]( - std::string const& msg, - std::optional shardIndex = std::nullopt) { - auto multipleIndexPrequel = [&shardIndexes] { - std::vector indexesAsString(shardIndexes.size()); - std::transform( - shardIndexes.begin(), - shardIndexes.end(), - indexesAsString.begin(), - [](uint32_t const index) { return std::to_string(index); }); - - return std::string("shard") + - (shardIndexes.size() > 1 ? "s " : " ") + - boost::algorithm::join(indexesAsString, ", "); - }; - - JLOG(j.error()) << (shardIndex ? "shard " + std::to_string(*shardIndex) - : multipleIndexPrequel()) - << " " << msg; - return false; - }; - - if (shardIndexes.empty()) - return fail("invalid shard indexes"); - - std::lock_guard lock(mutex_); - assert(init_); - - if (!canAdd_) - return fail("cannot be stored at this time"); - - auto historicalShardsToPrepare = 0; - - for (auto const shardIndex : shardIndexes) - { - if (shardIndex < earliestShardIndex_) - { - return fail( - "comes before earliest shard index " + - std::to_string(earliestShardIndex_), - shardIndex); - } - - // If we are synced to the network, check if the shard index is - // greater or equal to the current or validated shard index. - auto seqCheck = [&](std::uint32_t ledgerSeq) { - if (ledgerSeq >= earliestLedgerSeq_ && - shardIndex >= seqToShardIndex(ledgerSeq)) - { - return fail("invalid index", shardIndex); - } - return true; - }; - if (!seqCheck(app_.getLedgerMaster().getValidLedgerIndex() + 1) || - !seqCheck(app_.getLedgerMaster().getCurrentLedgerIndex())) - { - return fail("invalid index", shardIndex); - } - - if (shards_.find(shardIndex) != shards_.end()) - return fail("is already stored", shardIndex); - - if (preparedIndexes_.find(shardIndex) != preparedIndexes_.end()) - return fail( - "is already queued for import from the shard archive handler", - shardIndex); - - if (databaseImportStatus_) - { - if (auto shard = databaseImportStatus_->currentShard.lock(); shard) - { - if (shard->index() == shardIndex) - return fail( - "is being imported from the nodestore", shardIndex); - } - } - - // Any shard earlier than the two most recent shards - // is a historical shard - if (shardIndex < shardBoundaryIndex()) - ++historicalShardsToPrepare; - } - - auto const numHistShards = numHistoricalShards(lock); - - // Check shard count and available storage space - if (numHistShards + historicalShardsToPrepare > maxHistoricalShards_) - return fail("maximum number of historical shards reached"); - - if (historicalShardsToPrepare) - { - // Check available storage space for historical shards - if (!sufficientStorage( - historicalShardsToPrepare, PathDesignation::historical, lock)) - return fail("insufficient storage space available"); - } - - if (auto const recentShardsToPrepare = - shardIndexes.size() - historicalShardsToPrepare; - recentShardsToPrepare) - { - // Check available storage space for recent shards - if (!sufficientStorage( - recentShardsToPrepare, PathDesignation::none, lock)) - return fail("insufficient storage space available"); - } - - for (auto const shardIndex : shardIndexes) - preparedIndexes_.emplace(shardIndex); - - updatePeers(lock); - return true; -} - -void -DatabaseShardImp::removePreShard(std::uint32_t shardIndex) -{ - std::lock_guard lock(mutex_); - assert(init_); - - if (preparedIndexes_.erase(shardIndex)) - updatePeers(lock); -} - -std::string -DatabaseShardImp::getPreShards() -{ - RangeSet rs; - { - std::lock_guard lock(mutex_); - assert(init_); - - for (auto const& shardIndex : preparedIndexes_) - rs.insert(shardIndex); - } - - if (rs.empty()) - return {}; - - return ripple::to_string(rs); -}; - -bool -DatabaseShardImp::importShard( - std::uint32_t shardIndex, - boost::filesystem::path const& srcDir) -{ - auto fail = [&](std::string const& msg, - std::lock_guard const& lock) { - JLOG(j_.error()) << "shard " << shardIndex << " " << msg; - - // Remove the failed import shard index so it can be retried - preparedIndexes_.erase(shardIndex); - updatePeers(lock); - return false; - }; - - using namespace boost::filesystem; - try - { - if (!is_directory(srcDir) || is_empty(srcDir)) - { - return fail( - "invalid source directory " + srcDir.string(), - std::lock_guard(mutex_)); - } - } - catch (std::exception const& e) - { - return fail( - std::string(". Exception caught in function ") + __func__ + - ". Error: " + e.what(), - std::lock_guard(mutex_)); - } - - auto const expectedHash{app_.getLedgerMaster().walkHashBySeq( - lastLedgerSeq(shardIndex), InboundLedger::Reason::GENERIC)}; - if (!expectedHash) - return fail("expected hash not found", std::lock_guard(mutex_)); - - path dstDir; - { - std::lock_guard lock(mutex_); - if (shards_.find(shardIndex) != shards_.end()) - return fail("already exists", lock); - - // Check shard was prepared for import - if (preparedIndexes_.find(shardIndex) == preparedIndexes_.end()) - return fail("was not prepared for import", lock); - - auto const pathDesignation{ - prepareForNewShard(shardIndex, numHistoricalShards(lock), lock)}; - if (!pathDesignation) - return fail("failed to import", lock); - - if (*pathDesignation == PathDesignation::historical) - dstDir = chooseHistoricalPath(lock); - else - dstDir = dir_; - } - dstDir /= std::to_string(shardIndex); - - auto renameDir = [&, fname = __func__](path const& src, path const& dst) { - try - { - rename(src, dst); - } - catch (std::exception const& e) - { - return fail( - std::string(". Exception caught in function ") + fname + - ". Error: " + e.what(), - std::lock_guard(mutex_)); - } - return true; - }; - - // Rename source directory to the shard database directory - if (!renameDir(srcDir, dstDir)) - return false; - - // Create the new shard - auto shard{std::make_unique( - app_, *this, shardIndex, dstDir.parent_path(), j_)}; - - if (!shard->init(scheduler_, *ctx_) || - shard->getState() != ShardState::complete) - { - shard.reset(); - renameDir(dstDir, srcDir); - return fail("failed to import", std::lock_guard(mutex_)); - } - - auto const [it, inserted] = [&]() { - std::lock_guard lock(mutex_); - preparedIndexes_.erase(shardIndex); - return shards_.emplace(shardIndex, std::move(shard)); - }(); - - if (!inserted) - { - shard.reset(); - renameDir(dstDir, srcDir); - return fail("failed to import", std::lock_guard(mutex_)); - } - - finalizeShard(it->second, true, expectedHash); - return true; -} - -std::shared_ptr -DatabaseShardImp::fetchLedger(uint256 const& hash, std::uint32_t ledgerSeq) -{ - auto const shardIndex{seqToShardIndex(ledgerSeq)}; - { - std::shared_ptr shard; - { - std::lock_guard lock(mutex_); - assert(init_); - - auto const it{shards_.find(shardIndex)}; - if (it == shards_.end()) - return nullptr; - shard = it->second; - } - - // Ledger must be stored in a final or acquiring shard - switch (shard->getState()) - { - case ShardState::finalized: - break; - case ShardState::acquire: - if (shard->containsLedger(ledgerSeq)) - break; - [[fallthrough]]; - default: - return nullptr; - } - } - - auto const nodeObject{Database::fetchNodeObject(hash, ledgerSeq)}; - if (!nodeObject) - return nullptr; - - auto fail = [&](std::string const& msg) -> std::shared_ptr { - JLOG(j_.error()) << "shard " << shardIndex << " " << msg; - return nullptr; - }; - - auto ledger{std::make_shared( - deserializePrefixedHeader(makeSlice(nodeObject->getData())), - app_.config(), - *app_.getShardFamily())}; - - if (ledger->info().seq != ledgerSeq) - { - return fail( - "encountered invalid ledger sequence " + std::to_string(ledgerSeq)); - } - if (ledger->info().hash != hash) - { - return fail( - "encountered invalid ledger hash " + to_string(hash) + - " on sequence " + std::to_string(ledgerSeq)); - } - - ledger->setFull(); - if (!ledger->stateMap().fetchRoot( - SHAMapHash{ledger->info().accountHash}, nullptr)) - { - return fail( - "is missing root STATE node on hash " + to_string(hash) + - " on sequence " + std::to_string(ledgerSeq)); - } - - if (ledger->info().txHash.isNonZero()) - { - if (!ledger->txMap().fetchRoot( - SHAMapHash{ledger->info().txHash}, nullptr)) - { - return fail( - "is missing root TXN node on hash " + to_string(hash) + - " on sequence " + std::to_string(ledgerSeq)); - } - } - return ledger; -} - -void -DatabaseShardImp::setStored(std::shared_ptr const& ledger) -{ - auto const ledgerSeq{ledger->info().seq}; - if (ledger->info().hash.isZero()) - { - JLOG(j_.error()) << "zero ledger hash for ledger sequence " - << ledgerSeq; - return; - } - if (ledger->info().accountHash.isZero()) - { - JLOG(j_.error()) << "zero account hash for ledger sequence " - << ledgerSeq; - return; - } - if (ledger->stateMap().getHash().isNonZero() && - !ledger->stateMap().isValid()) - { - JLOG(j_.error()) << "invalid state map for ledger sequence " - << ledgerSeq; - return; - } - if (ledger->info().txHash.isNonZero() && !ledger->txMap().isValid()) - { - JLOG(j_.error()) << "invalid transaction map for ledger sequence " - << ledgerSeq; - return; - } - - auto const shardIndex{seqToShardIndex(ledgerSeq)}; - std::shared_ptr shard; - { - std::lock_guard lock(mutex_); - assert(init_); - - if (shardIndex != acquireIndex_) - { - JLOG(j_.trace()) - << "shard " << shardIndex << " is not being acquired"; - return; - } - - auto const it{shards_.find(shardIndex)}; - if (it == shards_.end()) - { - JLOG(j_.error()) - << "shard " << shardIndex << " is not being acquired"; - return; - } - shard = it->second; - } - - if (shard->containsLedger(ledgerSeq)) - { - JLOG(j_.trace()) << "shard " << shardIndex << " ledger already stored"; - return; - } - - setStoredInShard(shard, ledger); -} - -std::unique_ptr -DatabaseShardImp::getShardInfo() const -{ - std::lock_guard lock(mutex_); - return getShardInfo(lock); -} - -void -DatabaseShardImp::stop() -{ - // Stop read threads in base before data members are destroyed - Database::stop(); - std::vector> shards; - { - std::lock_guard lock(mutex_); - shards.reserve(shards_.size()); - for (auto const& [_, shard] : shards_) - { - shards.push_back(shard); - shard->stop(); - } - shards_.clear(); - } - taskQueue_.stop(); - - // All shards should be expired at this point - for (auto const& wptr : shards) - { - if (auto const shard{wptr.lock()}) - { - JLOG(j_.warn()) << " shard " << shard->index() << " unexpired"; - } - } - - std::unique_lock lock(mutex_); - - // Notify the shard being imported - // from the node store to stop - if (databaseImportStatus_) - { - // A node store import is in progress - if (auto importShard = databaseImportStatus_->currentShard.lock(); - importShard) - importShard->stop(); - } - - // Wait for the node store import thread - // if necessary - if (databaseImporter_.joinable()) - { - // Tells the import function to halt - haltDatabaseImport_ = true; - - // Wait for the function to exit - while (databaseImportStatus_) - { - // Unlock just in case the import - // function is waiting on the mutex - lock.unlock(); - - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - lock.lock(); - } - - // Calling join while holding the mutex_ without - // first making sure that doImportDatabase has - // exited could lead to deadlock via the mutex - // acquisition that occurs in that function - if (databaseImporter_.joinable()) - databaseImporter_.join(); - } -} - -void -DatabaseShardImp::importDatabase(Database& source) -{ - std::lock_guard lock(mutex_); - assert(init_); - - // Only the application local node store can be imported - assert(&source == &app_.getNodeStore()); - - if (databaseImporter_.joinable()) - { - assert(false); - JLOG(j_.error()) << "database import already in progress"; - return; - } - - startDatabaseImportThread(lock); -} - -void -DatabaseShardImp::doImportDatabase() -{ - auto shouldHalt = [this] { - bool expected = true; - return haltDatabaseImport_.compare_exchange_strong(expected, false) || - isStopping(); - }; - - if (shouldHalt()) - return; - - auto loadLedger = - [this](char const* const sortOrder) -> std::optional { - std::shared_ptr ledger; - std::uint32_t ledgerSeq{0}; - std::optional info; - if (sortOrder == std::string("asc")) - { - info = dynamic_cast(&app_.getRelationalDatabase()) - ->getLimitedOldestLedgerInfo(earliestLedgerSeq()); - } - else - { - info = dynamic_cast(&app_.getRelationalDatabase()) - ->getLimitedNewestLedgerInfo(earliestLedgerSeq()); - } - if (info) - { - ledger = loadLedgerHelper(*info, app_, false); - ledgerSeq = info->seq; - } - if (!ledger || ledgerSeq == 0) - { - JLOG(j_.error()) << "no suitable ledgers were found in" - " the SQLite database to import"; - return std::nullopt; - } - return ledgerSeq; - }; - - // Find earliest ledger sequence stored - auto const earliestLedgerSeq{loadLedger("asc")}; - if (!earliestLedgerSeq) - return; - - auto const earliestIndex = [&] { - auto earliestIndex = seqToShardIndex(*earliestLedgerSeq); - - // Consider only complete shards - if (earliestLedgerSeq != firstLedgerSeq(earliestIndex)) - ++earliestIndex; - - return earliestIndex; - }(); - - // Find last ledger sequence stored - auto const latestLedgerSeq = loadLedger("desc"); - if (!latestLedgerSeq) - return; - - auto const latestIndex = [&] { - auto latestIndex = seqToShardIndex(*latestLedgerSeq); - - // Consider only complete shards - if (latestLedgerSeq != lastLedgerSeq(latestIndex)) - --latestIndex; - - return latestIndex; - }(); - - if (latestIndex < earliestIndex) - { - JLOG(j_.error()) << "no suitable ledgers were found in" - " the SQLite database to import"; - return; - } - - JLOG(j_.debug()) << "Importing ledgers for shards " << earliestIndex - << " through " << latestIndex; - - { - std::lock_guard lock(mutex_); - - assert(!databaseImportStatus_); - databaseImportStatus_ = std::make_unique( - earliestIndex, latestIndex, 0); - } - - // Import the shards - for (std::uint32_t shardIndex = earliestIndex; shardIndex <= latestIndex; - ++shardIndex) - { - if (shouldHalt()) - return; - - auto const pathDesignation = [this, shardIndex] { - std::lock_guard lock(mutex_); - - auto const numHistShards = numHistoricalShards(lock); - auto const pathDesignation = - prepareForNewShard(shardIndex, numHistShards, lock); - - return pathDesignation; - }(); - - if (!pathDesignation) - break; - - { - std::lock_guard lock(mutex_); - - // Skip if being acquired - if (shardIndex == acquireIndex_) - { - JLOG(j_.debug()) - << "shard " << shardIndex << " already being acquired"; - continue; - } - - // Skip if being imported from the shard archive handler - if (preparedIndexes_.find(shardIndex) != preparedIndexes_.end()) - { - JLOG(j_.debug()) - << "shard " << shardIndex << " already being imported"; - continue; - } - - // Skip if stored - if (shards_.find(shardIndex) != shards_.end()) - { - JLOG(j_.debug()) << "shard " << shardIndex << " already stored"; - continue; - } - } - - std::uint32_t const firstSeq = firstLedgerSeq(shardIndex); - std::uint32_t const lastSeq = - std::max(firstSeq, lastLedgerSeq(shardIndex)); - - // Verify SQLite ledgers are in the node store - { - auto const ledgerHashes{ - app_.getRelationalDatabase().getHashesByIndex( - firstSeq, lastSeq)}; - if (ledgerHashes.size() != maxLedgers(shardIndex)) - continue; - - auto& source = app_.getNodeStore(); - bool valid{true}; - - for (std::uint32_t n = firstSeq; n <= lastSeq; ++n) - { - if (!source.fetchNodeObject(ledgerHashes.at(n).ledgerHash, n)) - { - JLOG(j_.warn()) << "SQLite ledger sequence " << n - << " mismatches node store"; - valid = false; - break; - } - } - if (!valid) - continue; - } - - if (shouldHalt()) - return; - - bool const needsHistoricalPath = - *pathDesignation == PathDesignation::historical; - - auto const path = needsHistoricalPath - ? chooseHistoricalPath(std::lock_guard(mutex_)) - : dir_; - - // Create the new shard - auto shard{std::make_shared(app_, *this, shardIndex, path, j_)}; - if (!shard->init(scheduler_, *ctx_)) - continue; - - { - std::lock_guard lock(mutex_); - - if (shouldHalt()) - return; - - databaseImportStatus_->currentIndex = shardIndex; - databaseImportStatus_->currentShard = shard; - databaseImportStatus_->firstSeq = firstSeq; - databaseImportStatus_->lastSeq = lastSeq; - } - - // Create a marker file to signify a database import in progress - auto const shardDir{path / std::to_string(shardIndex)}; - auto const markerFile{shardDir / databaseImportMarker_}; - { - std::ofstream ofs{markerFile.string()}; - if (!ofs.is_open()) - { - JLOG(j_.error()) << "shard " << shardIndex - << " failed to create temp marker file"; - shard->removeOnDestroy(); - continue; - } - } - - // Copy the ledgers from node store - std::shared_ptr recentStored; - std::optional lastLedgerHash; - - while (auto const ledgerSeq = shard->prepare()) - { - if (shouldHalt()) - return; - - // Not const so it may be moved later - auto ledger{loadByIndex(*ledgerSeq, app_, false)}; - if (!ledger || ledger->info().seq != ledgerSeq) - break; - - auto const result{shard->storeLedger(ledger, recentStored)}; - storeStats(result.count, result.size); - if (result.error) - break; - - if (!shard->setLedgerStored(ledger)) - break; - - if (!lastLedgerHash && ledgerSeq == lastSeq) - lastLedgerHash = ledger->info().hash; - - recentStored = std::move(ledger); - } - - if (shouldHalt()) - return; - - using namespace boost::filesystem; - bool success{false}; - if (lastLedgerHash && shard->getState() == ShardState::complete) - { - // Store shard final key - Serializer s; - s.add32(Shard::version); - s.add32(firstLedgerSeq(shardIndex)); - s.add32(lastLedgerSeq(shardIndex)); - s.addBitString(*lastLedgerHash); - auto const nodeObject{NodeObject::createObject( - hotUNKNOWN, std::move(s.modData()), Shard::finalKey)}; - - if (shard->storeNodeObject(nodeObject)) - { - try - { - std::lock_guard lock(mutex_); - - // The database import process is complete and the - // marker file is no longer required - remove_all(markerFile); - - JLOG(j_.debug()) << "shard " << shardIndex - << " was successfully imported" - " from the NodeStore"; - finalizeShard( - shards_.emplace(shardIndex, std::move(shard)) - .first->second, - true, - std::nullopt); - - // This variable is meant to capture the success - // of everything up to the point of shard finalization. - // If the shard fails to finalize, this condition will - // be handled by the finalization function itself, and - // not here. - success = true; - } - catch (std::exception const& e) - { - JLOG(j_.fatal()) << "shard index " << shardIndex - << ". Exception caught in function " - << __func__ << ". Error: " << e.what(); - } - } - } - - if (!success) - { - JLOG(j_.error()) << "shard " << shardIndex - << " failed to import from the NodeStore"; - - if (shard) - shard->removeOnDestroy(); - } - } - - if (shouldHalt()) - return; - - updateFileStats(); -} - -std::int32_t -DatabaseShardImp::getWriteLoad() const -{ - std::shared_ptr shard; - { - std::lock_guard lock(mutex_); - assert(init_); - - auto const it{shards_.find(acquireIndex_)}; - if (it == shards_.end()) - return 0; - shard = it->second; - } - - return shard->getWriteLoad(); -} - -void -DatabaseShardImp::store( - NodeObjectType type, - Blob&& data, - uint256 const& hash, - std::uint32_t ledgerSeq) -{ - auto const shardIndex{seqToShardIndex(ledgerSeq)}; - std::shared_ptr shard; - { - std::lock_guard lock(mutex_); - if (shardIndex != acquireIndex_) - { - JLOG(j_.trace()) - << "shard " << shardIndex << " is not being acquired"; - return; - } - - auto const it{shards_.find(shardIndex)}; - if (it == shards_.end()) - { - JLOG(j_.error()) - << "shard " << shardIndex << " is not being acquired"; - return; - } - shard = it->second; - } - - auto const nodeObject{ - NodeObject::createObject(type, std::move(data), hash)}; - if (shard->storeNodeObject(nodeObject)) - storeStats(1, nodeObject->getData().size()); -} - -bool -DatabaseShardImp::storeLedger(std::shared_ptr const& srcLedger) -{ - auto const ledgerSeq{srcLedger->info().seq}; - auto const shardIndex{seqToShardIndex(ledgerSeq)}; - std::shared_ptr shard; - { - std::lock_guard lock(mutex_); - assert(init_); - - if (shardIndex != acquireIndex_) - { - JLOG(j_.trace()) - << "shard " << shardIndex << " is not being acquired"; - return false; - } - - auto const it{shards_.find(shardIndex)}; - if (it == shards_.end()) - { - JLOG(j_.error()) - << "shard " << shardIndex << " is not being acquired"; - return false; - } - shard = it->second; - } - - auto const result{shard->storeLedger(srcLedger, nullptr)}; - storeStats(result.count, result.size); - if (result.error || result.count == 0 || result.size == 0) - return false; - - return setStoredInShard(shard, srcLedger); -} - -void -DatabaseShardImp::sweep() -{ - std::vector> shards; - { - std::lock_guard lock(mutex_); - assert(init_); - - shards.reserve(shards_.size()); - for (auto const& e : shards_) - shards.push_back(e.second); - } - - std::vector> openFinals; - openFinals.reserve(openFinalLimit_); - - for (auto const& weak : shards) - { - if (auto const shard{weak.lock()}; shard && shard->isOpen()) - { - if (shard->getState() == ShardState::finalized) - openFinals.emplace_back(std::move(shard)); - } - } - - if (openFinals.size() > openFinalLimit_) - { - JLOG(j_.trace()) << "Open shards exceed configured limit of " - << openFinalLimit_ << " by " - << (openFinals.size() - openFinalLimit_); - - // Try to close enough shards to be within the limit. - // Sort ascending on last use so the oldest are removed first. - std::sort( - openFinals.begin(), - openFinals.end(), - [&](std::shared_ptr const& lhsShard, - std::shared_ptr const& rhsShard) { - return lhsShard->getLastUse() < rhsShard->getLastUse(); - }); - - for (auto it{openFinals.cbegin()}; - it != openFinals.cend() && openFinals.size() > openFinalLimit_;) - { - if ((*it)->tryClose()) - it = openFinals.erase(it); - else - ++it; - } - } -} - -Json::Value -DatabaseShardImp::getDatabaseImportStatus() const -{ - if (std::lock_guard lock(mutex_); databaseImportStatus_) - { - Json::Value ret(Json::objectValue); - - ret[jss::firstShardIndex] = databaseImportStatus_->earliestIndex; - ret[jss::lastShardIndex] = databaseImportStatus_->latestIndex; - ret[jss::currentShardIndex] = databaseImportStatus_->currentIndex; - - Json::Value currentShard(Json::objectValue); - currentShard[jss::firstSequence] = databaseImportStatus_->firstSeq; - currentShard[jss::lastSequence] = databaseImportStatus_->lastSeq; - - if (auto shard = databaseImportStatus_->currentShard.lock(); shard) - currentShard[jss::storedSeqs] = shard->getStoredSeqs(); - - ret[jss::currentShard] = currentShard; - - if (haltDatabaseImport_) - ret[jss::message] = "Database import halt initiated..."; - - return ret; - } - - return RPC::make_error(rpcINTERNAL, "Database import not running"); -} - -Json::Value -DatabaseShardImp::startNodeToShard() -{ - std::lock_guard lock(mutex_); - - if (!init_) - return RPC::make_error(rpcINTERNAL, "Shard store not initialized"); - - if (databaseImporter_.joinable()) - return RPC::make_error( - rpcINTERNAL, "Database import already in progress"); - - if (isStopping()) - return RPC::make_error(rpcINTERNAL, "Node is shutting down"); - - startDatabaseImportThread(lock); - - Json::Value result(Json::objectValue); - result[jss::message] = "Database import initiated..."; - - return result; -} - -Json::Value -DatabaseShardImp::stopNodeToShard() -{ - std::lock_guard lock(mutex_); - - if (!init_) - return RPC::make_error(rpcINTERNAL, "Shard store not initialized"); - - if (!databaseImporter_.joinable()) - return RPC::make_error(rpcINTERNAL, "Database import not running"); - - if (isStopping()) - return RPC::make_error(rpcINTERNAL, "Node is shutting down"); - - haltDatabaseImport_ = true; - - Json::Value result(Json::objectValue); - result[jss::message] = "Database import halt initiated..."; - - return result; -} - -std::optional -DatabaseShardImp::getDatabaseImportSequence() const -{ - std::lock_guard lock(mutex_); - - if (!databaseImportStatus_) - return {}; - - return databaseImportStatus_->firstSeq; -} - -bool -DatabaseShardImp::initConfig(std::lock_guard const&) -{ - auto fail = [j = j_](std::string const& msg) { - JLOG(j.error()) << "[" << ConfigSection::shardDatabase() << "] " << msg; - return false; - }; - - Config const& config{app_.config()}; - Section const& section{config.section(ConfigSection::shardDatabase())}; - - auto compare = [&](std::string const& name, std::uint32_t defaultValue) { - std::uint32_t shardDBValue{defaultValue}; - get_if_exists(section, name, shardDBValue); - - std::uint32_t nodeDBValue{defaultValue}; - get_if_exists( - config.section(ConfigSection::nodeDatabase()), name, nodeDBValue); - - return shardDBValue == nodeDBValue; - }; - - // If ledgers_per_shard or earliest_seq are specified, - // they must be equally assigned in 'node_db' - if (!compare("ledgers_per_shard", DEFAULT_LEDGERS_PER_SHARD)) - { - return fail( - "and [" + ConfigSection::nodeDatabase() + "] define different '" + - "ledgers_per_shard" + "' values"); - } - if (!compare("earliest_seq", XRP_LEDGER_EARLIEST_SEQ)) - { - return fail( - "and [" + ConfigSection::nodeDatabase() + "] define different '" + - "earliest_seq" + "' values"); - } - - using namespace boost::filesystem; - if (!get_if_exists(section, "path", dir_)) - return fail("'path' missing"); - - { - get_if_exists(section, "max_historical_shards", maxHistoricalShards_); - - Section const& historicalShardPaths = - config.section(SECTION_HISTORICAL_SHARD_PATHS); - - auto values = historicalShardPaths.values(); - - std::sort(values.begin(), values.end()); - values.erase(std::unique(values.begin(), values.end()), values.end()); - - for (auto const& s : values) - { - auto const dir = path(s); - if (dir_ == dir) - { - return fail( - "the 'path' cannot also be in the " - "'historical_shard_path' section"); - } - - historicalPaths_.push_back(s); - } - } - - // NuDB is the default and only supported permanent storage backend - backendName_ = get(section, "type", "nudb"); - if (!boost::iequals(backendName_, "NuDB")) - return fail("'type' value unsupported"); - - return true; -} - -std::shared_ptr -DatabaseShardImp::fetchNodeObject( - uint256 const& hash, - std::uint32_t ledgerSeq, - FetchReport& fetchReport, - bool duplicate) -{ - auto const shardIndex{seqToShardIndex(ledgerSeq)}; - std::shared_ptr shard; - { - std::lock_guard lock(mutex_); - auto const it{shards_.find(shardIndex)}; - if (it == shards_.end()) - return nullptr; - shard = it->second; - } - - return shard->fetchNodeObject(hash, fetchReport); -} - -std::optional -DatabaseShardImp::findAcquireIndex( - std::uint32_t validLedgerSeq, - std::lock_guard const&) -{ - if (validLedgerSeq < earliestLedgerSeq_) - return std::nullopt; - - auto const maxShardIndex{[this, validLedgerSeq]() { - auto shardIndex{seqToShardIndex(validLedgerSeq)}; - if (validLedgerSeq != lastLedgerSeq(shardIndex)) - --shardIndex; - return shardIndex; - }()}; - auto const maxNumShards{maxShardIndex - earliestShardIndex_ + 1}; - - // Check if the shard store has all shards - if (shards_.size() >= maxNumShards) - return std::nullopt; - - if (maxShardIndex < 1024 || - static_cast(shards_.size()) / maxNumShards > 0.5f) - { - // Small or mostly full index space to sample - // Find the available indexes and select one at random - std::vector available; - available.reserve(maxNumShards - shards_.size()); - - for (auto shardIndex = earliestShardIndex_; shardIndex <= maxShardIndex; - ++shardIndex) - { - if (shards_.find(shardIndex) == shards_.end() && - preparedIndexes_.find(shardIndex) == preparedIndexes_.end()) - { - available.push_back(shardIndex); - } - } - - if (available.empty()) - return std::nullopt; - - if (available.size() == 1) - return available.front(); - - return available[rand_int( - 0u, static_cast(available.size() - 1))]; - } - - // Large, sparse index space to sample - // Keep choosing indexes at random until an available one is found - // chances of running more than 30 times is less than 1 in a billion - for (int i = 0; i < 40; ++i) - { - auto const shardIndex{rand_int(earliestShardIndex_, maxShardIndex)}; - if (shards_.find(shardIndex) == shards_.end() && - preparedIndexes_.find(shardIndex) == preparedIndexes_.end()) - { - return shardIndex; - } - } - - assert(false); - return std::nullopt; -} - -void -DatabaseShardImp::finalizeShard( - std::shared_ptr& shard, - bool const writeSQLite, - std::optional const& expectedHash) -{ - taskQueue_.addTask([this, - wptr = std::weak_ptr(shard), - writeSQLite, - expectedHash]() { - if (isStopping()) - return; - - auto shard{wptr.lock()}; - if (!shard) - { - JLOG(j_.debug()) << "Shard removed before being finalized"; - return; - } - - if (!shard->finalize(writeSQLite, expectedHash)) - { - if (isStopping()) - return; - - // Invalid or corrupt shard, remove it - removeFailedShard(shard); - return; - } - - if (isStopping()) - return; - - { - auto const boundaryIndex{shardBoundaryIndex()}; - std::lock_guard lock(mutex_); - - if (shard->index() < boundaryIndex) - { - // This is a historical shard - if (!historicalPaths_.empty() && - shard->getDir().parent_path() == dir_) - { - // Shard wasn't placed at a separate historical path - JLOG(j_.warn()) << "shard " << shard->index() - << " is not stored at a historical path"; - } - } - else - { - // Not a historical shard. Shift recent shards if necessary - assert(!boundaryIndex || shard->index() - boundaryIndex <= 1); - relocateOutdatedShards(lock); - - // Set the appropriate recent shard index - if (shard->index() == boundaryIndex) - secondLatestShardIndex_ = shard->index(); - else - latestShardIndex_ = shard->index(); - - if (shard->getDir().parent_path() != dir_) - { - JLOG(j_.warn()) << "shard " << shard->index() - << " is not stored at the path"; - } - } - - updatePeers(lock); - } - - updateFileStats(); - }); -} - -void -DatabaseShardImp::updateFileStats() -{ - std::vector> shards; - { - std::lock_guard lock(mutex_); - if (shards_.empty()) - return; - - shards.reserve(shards_.size()); - for (auto const& e : shards_) - shards.push_back(e.second); - } - - std::uint64_t sumSz{0}; - std::uint32_t sumFd{0}; - std::uint32_t numShards{0}; - for (auto const& weak : shards) - { - if (auto const shard{weak.lock()}; shard) - { - auto const [sz, fd] = shard->getFileInfo(); - sumSz += sz; - sumFd += fd; - ++numShards; - } - } - - std::lock_guard lock(mutex_); - fileSz_ = sumSz; - fdRequired_ = sumFd; - avgShardFileSz_ = (numShards == 0 ? fileSz_ : fileSz_ / numShards); - - if (!canAdd_) - return; - - if (auto const count = numHistoricalShards(lock); - count >= maxHistoricalShards_) - { - if (maxHistoricalShards_) - { - // In order to avoid excessive output, don't produce - // this warning if the server isn't configured to - // store historical shards. - JLOG(j_.warn()) << "maximum number of historical shards reached"; - } - - canAdd_ = false; - } - else if (!sufficientStorage( - maxHistoricalShards_ - count, - PathDesignation::historical, - lock)) - { - JLOG(j_.warn()) - << "maximum shard store size exceeds available storage space"; - - canAdd_ = false; - } -} - -bool -DatabaseShardImp::sufficientStorage( - std::uint32_t numShards, - PathDesignation pathDesignation, - std::lock_guard const&) const -{ - try - { - std::vector capacities; - - if (pathDesignation == PathDesignation::historical && - !historicalPaths_.empty()) - { - capacities.reserve(historicalPaths_.size()); - - for (auto const& path : historicalPaths_) - { - // Get the available storage for each historical path - auto const availableSpace = - boost::filesystem::space(path).available; - - capacities.push_back(availableSpace); - } - } - else - { - // Get the available storage for the main shard path - capacities.push_back(boost::filesystem::space(dir_).available); - } - - for (std::uint64_t const capacity : capacities) - { - // Leverage all the historical shard paths to - // see if collectively they can fit the specified - // number of shards. For this to work properly, - // each historical path must correspond to a separate - // physical device or filesystem. - - auto const shardCap = capacity / avgShardFileSz_; - if (numShards <= shardCap) - return true; - - numShards -= shardCap; - } - } - catch (std::exception const& e) - { - JLOG(j_.fatal()) << "Exception caught in function " << __func__ - << ". Error: " << e.what(); - return false; - } - - return false; -} - -bool -DatabaseShardImp::setStoredInShard( - std::shared_ptr& shard, - std::shared_ptr const& ledger) -{ - if (!shard->setLedgerStored(ledger)) - { - // Invalid or corrupt shard, remove it - removeFailedShard(shard); - return false; - } - - if (shard->getState() == ShardState::complete) - { - std::lock_guard lock(mutex_); - if (auto const it{shards_.find(shard->index())}; it != shards_.end()) - { - if (shard->index() == acquireIndex_) - acquireIndex_ = 0; - - finalizeShard(it->second, false, std::nullopt); - } - else - { - JLOG(j_.debug()) - << "shard " << shard->index() << " is no longer being acquired"; - } - } - - updateFileStats(); - return true; -} - -void -DatabaseShardImp::removeFailedShard(std::shared_ptr& shard) -{ - { - std::lock_guard lock(mutex_); - - if (shard->index() == acquireIndex_) - acquireIndex_ = 0; - - if (shard->index() == latestShardIndex_) - latestShardIndex_ = std::nullopt; - - if (shard->index() == secondLatestShardIndex_) - secondLatestShardIndex_ = std::nullopt; - } - - shard->removeOnDestroy(); - - // Reset the shared_ptr to invoke the shard's - // destructor and remove it from the server - shard.reset(); - updateFileStats(); -} - -std::uint32_t -DatabaseShardImp::shardBoundaryIndex() const -{ - auto const validIndex = app_.getLedgerMaster().getValidLedgerIndex(); - - if (validIndex < earliestLedgerSeq_) - return 0; - - // Shards with an index earlier than the recent shard boundary index - // are considered historical. The three shards at or later than - // this index consist of the two most recently validated shards - // and the shard still in the process of being built by live - // transactions. - return seqToShardIndex(validIndex) - 1; -} - -std::uint32_t -DatabaseShardImp::numHistoricalShards( - std::lock_guard const& lock) const -{ - auto const boundaryIndex{shardBoundaryIndex()}; - return std::count_if( - shards_.begin(), shards_.end(), [boundaryIndex](auto const& entry) { - return entry.first < boundaryIndex; - }); -} - -void -DatabaseShardImp::relocateOutdatedShards( - std::lock_guard const& lock) -{ - auto& cur{latestShardIndex_}; - auto& prev{secondLatestShardIndex_}; - if (!cur && !prev) - return; - - auto const latestShardIndex = - seqToShardIndex(app_.getLedgerMaster().getValidLedgerIndex()); - auto const separateHistoricalPath = !historicalPaths_.empty(); - - auto const removeShard = [this](std::uint32_t const shardIndex) -> void { - canAdd_ = false; - - if (auto it = shards_.find(shardIndex); it != shards_.end()) - { - if (it->second) - removeFailedShard(it->second); - else - { - JLOG(j_.warn()) << "can't find shard to remove"; - } - } - else - { - JLOG(j_.warn()) << "can't find shard to remove"; - } - }; - - auto const keepShard = [this, &lock, removeShard, separateHistoricalPath]( - std::uint32_t const shardIndex) -> bool { - if (numHistoricalShards(lock) >= maxHistoricalShards_) - { - JLOG(j_.error()) << "maximum number of historical shards reached"; - removeShard(shardIndex); - return false; - } - if (separateHistoricalPath && - !sufficientStorage(1, PathDesignation::historical, lock)) - { - JLOG(j_.error()) << "insufficient storage space available"; - removeShard(shardIndex); - return false; - } - - return true; - }; - - // Move a shard from the main shard path to a historical shard - // path by copying the contents, and creating a new shard. - auto const moveShard = [this, - &lock](std::uint32_t const shardIndex) -> void { - auto it{shards_.find(shardIndex)}; - if (it == shards_.end()) - { - JLOG(j_.warn()) << "can't find shard to move to historical path"; - return; - } - - auto& shard{it->second}; - - // Close any open file descriptors before moving the shard - // directory. Don't call removeOnDestroy since that would - // attempt to close the fds after the directory has been moved. - if (!shard->tryClose()) - { - JLOG(j_.warn()) << "can't close shard to move to historical path"; - return; - } - - auto const dst{chooseHistoricalPath(lock)}; - try - { - // Move the shard directory to the new path - boost::filesystem::rename( - shard->getDir().string(), dst / std::to_string(shardIndex)); - } - catch (...) - { - JLOG(j_.error()) << "shard " << shardIndex - << " failed to move to historical storage"; - return; - } - - // Create a shard instance at the new location - shard = std::make_shared(app_, *this, shardIndex, dst, j_); - - // Open the new shard - if (!shard->init(scheduler_, *ctx_)) - { - JLOG(j_.error()) << "shard " << shardIndex - << " failed to open in historical storage"; - shard->removeOnDestroy(); - shard.reset(); - } - }; - - // See if either of the recent shards needs to be updated - bool const curNotSynched = - latestShardIndex_ && *latestShardIndex_ != latestShardIndex; - bool const prevNotSynched = secondLatestShardIndex_ && - *secondLatestShardIndex_ != latestShardIndex - 1; - - // A new shard has been published. Move outdated - // shards to historical storage as needed - if (curNotSynched || prevNotSynched) - { - if (prev) - { - // Move the formerly second latest shard to historical storage - if (keepShard(*prev) && separateHistoricalPath) - moveShard(*prev); - - prev = std::nullopt; - } - - if (cur) - { - // The formerly latest shard is now the second latest - if (cur == latestShardIndex - 1) - prev = cur; - - // The formerly latest shard is no longer a 'recent' shard - else - { - // Move the formerly latest shard to historical storage - if (keepShard(*cur) && separateHistoricalPath) - moveShard(*cur); - } - - cur = std::nullopt; - } - } -} - -auto -DatabaseShardImp::prepareForNewShard( - std::uint32_t shardIndex, - std::uint32_t numHistoricalShards, - std::lock_guard const& lock) -> std::optional -{ - // Any shard earlier than the two most recent shards is a historical shard - auto const boundaryIndex{shardBoundaryIndex()}; - auto const isHistoricalShard = shardIndex < boundaryIndex; - - auto const designation = isHistoricalShard && !historicalPaths_.empty() - ? PathDesignation::historical - : PathDesignation::none; - - // Check shard count and available storage space - if (isHistoricalShard && numHistoricalShards >= maxHistoricalShards_) - { - JLOG(j_.error()) << "maximum number of historical shards reached"; - canAdd_ = false; - return std::nullopt; - } - if (!sufficientStorage(1, designation, lock)) - { - JLOG(j_.error()) << "insufficient storage space available"; - canAdd_ = false; - return std::nullopt; - } - - return designation; -} - -boost::filesystem::path -DatabaseShardImp::chooseHistoricalPath(std::lock_guard const&) const -{ - // If not configured with separate historical paths, - // use the main path (dir_) by default. - if (historicalPaths_.empty()) - return dir_; - - boost::filesystem::path historicalShardPath; - std::vector potentialPaths; - - for (boost::filesystem::path const& path : historicalPaths_) - { - if (boost::filesystem::space(path).available >= avgShardFileSz_) - potentialPaths.push_back(path); - } - - if (potentialPaths.empty()) - { - JLOG(j_.error()) << "failed to select a historical shard path"; - return ""; - } - - std::sample( - potentialPaths.begin(), - potentialPaths.end(), - &historicalShardPath, - 1, - default_prng()); - - return historicalShardPath; -} - -bool -DatabaseShardImp::checkHistoricalPaths(std::lock_guard const&) const -{ -#if BOOST_OS_LINUX - // Each historical shard path must correspond - // to a directory on a distinct device or file system. - // Currently, this constraint is enforced only on Linux. - std::unordered_map> filesystemIDs( - historicalPaths_.size()); - - for (auto const& path : historicalPaths_) - { - struct statvfs buffer; - if (statvfs(path.c_str(), &buffer)) - { - JLOG(j_.error()) - << "failed to acquire stats for 'historical_shard_path': " - << path; - return false; - } - - filesystemIDs[buffer.f_fsid].push_back(path.string()); - } - - bool ret = true; - for (auto const& entry : filesystemIDs) - { - // Check to see if any of the paths are stored on the same file system - if (entry.second.size() > 1) - { - // Two or more historical storage paths - // correspond to the same file system. - JLOG(j_.error()) - << "The following paths correspond to the same filesystem: " - << boost::algorithm::join(entry.second, ", ") - << ". Each configured historical storage path should" - " be on a unique device or filesystem."; - - ret = false; - } - } - - return ret; - -#else - // The requirement that each historical storage path - // corresponds to a distinct device or file system is - // enforced only on Linux, so on other platforms - // keep track of the available capacities for each - // path. Issue a warning if we suspect any of the paths - // may violate this requirement. - - // Map byte counts to each path that shares that byte count. - std::unordered_map> - uniqueCapacities(historicalPaths_.size()); - - for (auto const& path : historicalPaths_) - uniqueCapacities[boost::filesystem::space(path).available].push_back( - path.string()); - - for (auto const& entry : uniqueCapacities) - { - // Check to see if any paths have the same amount of available bytes. - if (entry.second.size() > 1) - { - // Two or more historical storage paths may - // correspond to the same device or file system. - JLOG(j_.warn()) - << "Each of the following paths have " << entry.first - << " bytes free, and may be located on the same device" - " or file system: " - << boost::algorithm::join(entry.second, ", ") - << ". Each configured historical storage path should" - " be on a unique device or file system."; - } - } -#endif - - return true; -} - -bool -DatabaseShardImp::callForLedgerSQLByLedgerSeq( - LedgerIndex ledgerSeq, - std::function const& callback) -{ - if (ledgerSeq < earliestLedgerSeq_) - { - JLOG(j_.warn()) << "callForLedgerSQLByLedgerSeq ledger seq too early: " - << ledgerSeq; - return false; - } - - return callForLedgerSQLByShardIndex(seqToShardIndex(ledgerSeq), callback); -} - -bool -DatabaseShardImp::callForLedgerSQLByShardIndex( - const uint32_t shardIndex, - std::function const& callback) -{ - std::lock_guard lock(mutex_); - - auto const it{shards_.find(shardIndex)}; - - return it != shards_.end() && - it->second->getState() == ShardState::finalized && - it->second->callForLedgerSQL(callback); -} - -bool -DatabaseShardImp::callForTransactionSQLByLedgerSeq( - LedgerIndex ledgerSeq, - std::function const& callback) -{ - return callForTransactionSQLByShardIndex( - seqToShardIndex(ledgerSeq), callback); -} - -bool -DatabaseShardImp::callForTransactionSQLByShardIndex( - std::uint32_t const shardIndex, - std::function const& callback) -{ - std::lock_guard lock(mutex_); - - auto const it{shards_.find(shardIndex)}; - - return it != shards_.end() && - it->second->getState() == ShardState::finalized && - it->second->callForTransactionSQL(callback); -} - -bool -DatabaseShardImp::iterateShardsForward( - std::optional minShardIndex, - std::function const& visit) -{ - std::lock_guard lock(mutex_); - - std::map>::iterator it, eit; - - if (!minShardIndex) - it = shards_.begin(); - else - it = shards_.lower_bound(*minShardIndex); - - eit = shards_.end(); - - for (; it != eit; it++) - { - if (it->second->getState() == ShardState::finalized) - { - if (!visit(*it->second)) - return false; - } - } - - return true; -} - -bool -DatabaseShardImp::iterateLedgerSQLsForward( - std::optional minShardIndex, - std::function const& - callback) -{ - return iterateShardsForward( - minShardIndex, [&callback](Shard& shard) -> bool { - return shard.callForLedgerSQL(callback); - }); -} - -bool -DatabaseShardImp::iterateTransactionSQLsForward( - std::optional minShardIndex, - std::function const& - callback) -{ - return iterateShardsForward( - minShardIndex, [&callback](Shard& shard) -> bool { - return shard.callForTransactionSQL(callback); - }); -} - -bool -DatabaseShardImp::iterateShardsBack( - std::optional maxShardIndex, - std::function const& visit) -{ - std::lock_guard lock(mutex_); - - std::map>::reverse_iterator it, eit; - - if (!maxShardIndex) - it = shards_.rbegin(); - else - it = std::make_reverse_iterator(shards_.upper_bound(*maxShardIndex)); - - eit = shards_.rend(); - - for (; it != eit; it++) - { - if (it->second->getState() == ShardState::finalized && - (!maxShardIndex || it->first <= *maxShardIndex)) - { - if (!visit(*it->second)) - return false; - } - } - - return true; -} - -bool -DatabaseShardImp::iterateLedgerSQLsBack( - std::optional maxShardIndex, - std::function const& - callback) -{ - return iterateShardsBack(maxShardIndex, [&callback](Shard& shard) -> bool { - return shard.callForLedgerSQL(callback); - }); -} - -bool -DatabaseShardImp::iterateTransactionSQLsBack( - std::optional maxShardIndex, - std::function const& - callback) -{ - return iterateShardsBack(maxShardIndex, [&callback](Shard& shard) -> bool { - return shard.callForTransactionSQL(callback); - }); -} - -std::unique_ptr -DatabaseShardImp::getShardInfo(std::lock_guard const&) const -{ - auto shardInfo{std::make_unique()}; - for (auto const& [_, shard] : shards_) - { - shardInfo->update( - shard->index(), shard->getState(), shard->getPercentProgress()); - } - - for (auto const shardIndex : preparedIndexes_) - shardInfo->update(shardIndex, ShardState::queued, 0); - - return shardInfo; -} - -size_t -DatabaseShardImp::getNumTasks() const -{ - std::lock_guard lock(mutex_); - return taskQueue_.size(); -} - -void -DatabaseShardImp::updatePeers(std::lock_guard const& lock) const -{ - if (!app_.config().standalone() && - app_.getOPs().getOperatingMode() != OperatingMode::DISCONNECTED) - { - auto const message{getShardInfo(lock)->makeMessage(app_)}; - app_.overlay().foreach(send_always(std::make_shared( - message, protocol::mtPEER_SHARD_INFO_V2))); - } -} - -void -DatabaseShardImp::startDatabaseImportThread(std::lock_guard const&) -{ - // Run the lengthy node store import process in the background - // on a dedicated thread. - databaseImporter_ = std::thread([this] { - doImportDatabase(); - - std::lock_guard lock(mutex_); - - // Make sure to clear this in case the import - // exited early. - databaseImportStatus_.reset(); - - // Detach the thread so subsequent attempts - // to start the import won't get held up by - // the old thread of execution - databaseImporter_.detach(); - }); -} - -//------------------------------------------------------------------------------ - -std::unique_ptr -make_ShardStore( - Application& app, - Scheduler& scheduler, - int readThreads, - beast::Journal j) -{ - // The shard store is optional. Future changes will require it. - Section const& section{ - app.config().section(ConfigSection::shardDatabase())}; - if (section.empty()) - return nullptr; - - return std::make_unique(app, scheduler, readThreads, j); -} - -} // namespace NodeStore -} // namespace ripple diff --git a/src/xrpld/nodestore/detail/DatabaseShardImp.h b/src/xrpld/nodestore/detail/DatabaseShardImp.h deleted file mode 100644 index df740cf407c..00000000000 --- a/src/xrpld/nodestore/detail/DatabaseShardImp.h +++ /dev/null @@ -1,429 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2017 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_NODESTORE_DATABASESHARDIMP_H_INCLUDED -#define RIPPLE_NODESTORE_DATABASESHARDIMP_H_INCLUDED - -#include -#include -#include - -#include - -namespace ripple { -namespace NodeStore { - -class DatabaseShardImp : public DatabaseShard -{ -public: - DatabaseShardImp() = delete; - DatabaseShardImp(DatabaseShardImp const&) = delete; - DatabaseShardImp(DatabaseShardImp&&) = delete; - DatabaseShardImp& - operator=(DatabaseShardImp const&) = delete; - DatabaseShardImp& - operator=(DatabaseShardImp&&) = delete; - - DatabaseShardImp( - Application& app, - Scheduler& scheduler, - int readThreads, - beast::Journal j); - - ~DatabaseShardImp() - { - stop(); - } - - [[nodiscard]] bool - init() override; - - std::optional - prepareLedger(std::uint32_t validLedgerSeq) override; - - bool - prepareShards(std::vector const& shardIndexes) override; - - void - removePreShard(std::uint32_t shardIndex) override; - - std::string - getPreShards() override; - - bool - importShard(std::uint32_t shardIndex, boost::filesystem::path const& srcDir) - override; - - std::shared_ptr - fetchLedger(uint256 const& hash, std::uint32_t ledgerSeq) override; - - void - setStored(std::shared_ptr const& ledger) override; - - std::unique_ptr - getShardInfo() const override; - - size_t - getNumTasks() const override; - - boost::filesystem::path const& - getRootDir() const override - { - return dir_; - } - - std::string - getName() const override - { - return backendName_; - } - - void - stop() override; - - /** Import the application local node store - - @param source The application node store. - */ - void - importDatabase(Database& source) override; - - void - doImportDatabase(); - - std::int32_t - getWriteLoad() const override; - - bool - isSameDB(std::uint32_t s1, std::uint32_t s2) override - { - return seqToShardIndex(s1) == seqToShardIndex(s2); - } - - void - store( - NodeObjectType type, - Blob&& data, - uint256 const& hash, - std::uint32_t ledgerSeq) override; - - void - sync() override{}; - - bool - storeLedger(std::shared_ptr const& srcLedger) override; - - void - sweep() override; - - Json::Value - getDatabaseImportStatus() const override; - - Json::Value - startNodeToShard() override; - - Json::Value - stopNodeToShard() override; - - std::optional - getDatabaseImportSequence() const override; - - bool - callForLedgerSQLByLedgerSeq( - LedgerIndex ledgerSeq, - std::function const& callback) override; - - bool - callForLedgerSQLByShardIndex( - std::uint32_t const shardIndex, - std::function const& callback) override; - - bool - callForTransactionSQLByLedgerSeq( - LedgerIndex ledgerSeq, - std::function const& callback) override; - - bool - callForTransactionSQLByShardIndex( - std::uint32_t const shardIndex, - std::function const& callback) override; - - bool - iterateLedgerSQLsForward( - std::optional minShardIndex, - std::function< - bool(soci::session& session, std::uint32_t shardIndex)> const& - callback) override; - - bool - iterateTransactionSQLsForward( - std::optional minShardIndex, - std::function< - bool(soci::session& session, std::uint32_t shardIndex)> const& - callback) override; - - bool - iterateLedgerSQLsBack( - std::optional maxShardIndex, - std::function< - bool(soci::session& session, std::uint32_t shardIndex)> const& - callback) override; - - bool - iterateTransactionSQLsBack( - std::optional maxShardIndex, - std::function< - bool(soci::session& session, std::uint32_t shardIndex)> const& - callback) override; - -private: - enum class PathDesignation : uint8_t { - none, // No path specified - historical // Needs a historical path - }; - - struct DatabaseImportStatus - { - DatabaseImportStatus( - std::uint32_t const earliestIndex, - std::uint32_t const latestIndex, - std::uint32_t const currentIndex) - : earliestIndex(earliestIndex) - , latestIndex(latestIndex) - , currentIndex(currentIndex) - { - } - - // Index of the first shard to be imported - std::uint32_t earliestIndex{0}; - - // Index of the last shard to be imported - std::uint32_t latestIndex{0}; - - // Index of the shard currently being imported - std::uint32_t currentIndex{0}; - - // First ledger sequence of the current shard - std::uint32_t firstSeq{0}; - - // Last ledger sequence of the current shard - std::uint32_t lastSeq{0}; - - // The shard currently being imported - std::weak_ptr currentShard; - }; - - Application& app_; - mutable std::mutex mutex_; - bool init_{false}; - - // The context shared with all shard backend databases - std::unique_ptr ctx_; - - // Queue of background tasks to be performed - TaskQueue taskQueue_; - - // Shards held by this server - std::map> shards_; - - // Shard indexes being imported from the shard archive handler - std::set preparedIndexes_; - - // Shard index being acquired from the peer network - std::uint32_t acquireIndex_{0}; - - // The shard store root directory - boost::filesystem::path dir_; - - // If new shards can be stored - bool canAdd_{true}; - - // The name associated with the backend used with the shard store - std::string backendName_; - - // Maximum number of historical shards to store. - std::uint32_t maxHistoricalShards_{0}; - - // Contains historical shard paths - std::vector historicalPaths_; - - // Storage space utilized by the shard store (in bytes) - std::uint64_t fileSz_{0}; - - // Average storage space required by a shard (in bytes) - std::uint64_t avgShardFileSz_; - - // The limit of final shards with open databases at any time - std::uint32_t const openFinalLimit_; - - // File name used to mark shards being imported from node store - static constexpr auto databaseImportMarker_ = "database_import"; - - // latestShardIndex_ and secondLatestShardIndex hold the indexes - // of the shards most recently confirmed by the network. These - // values are not updated in real time and are modified only - // when adding shards to the database, in order to determine where - // pending shards will be stored on the filesystem. A value of - // std::nullopt indicates that the corresponding shard is not held - // by the database. - std::optional latestShardIndex_; - std::optional secondLatestShardIndex_; - - // Struct used for node store import progress - std::unique_ptr databaseImportStatus_; - - // Thread for running node store import - std::thread databaseImporter_; - - // Indicates whether the import should stop - std::atomic_bool haltDatabaseImport_{false}; - - // Initialize settings from the configuration file - // Lock must be held - bool - initConfig(std::lock_guard const&); - - std::shared_ptr - fetchNodeObject( - uint256 const& hash, - std::uint32_t ledgerSeq, - FetchReport& fetchReport, - bool duplicate) override; - - void - for_each(std::function)> f) override - { - Throw("Import from shard store not supported"); - } - - // Randomly select a shard index not stored - // Lock must be held - std::optional - findAcquireIndex( - std::uint32_t validLedgerSeq, - std::lock_guard const&); - - // Queue a task to finalize a shard by verifying its databases - // Lock must be held - void - finalizeShard( - std::shared_ptr& shard, - bool writeSQLite, - std::optional const& expectedHash); - - // Update storage and file descriptor usage stats - void - updateFileStats(); - - // Returns true if the file system has enough storage - // available to hold the specified number of shards. - // The value of pathDesignation determines whether - // the shard(s) in question are historical and thus - // meant to be stored at a path designated for historical - // shards. - bool - sufficientStorage( - std::uint32_t numShards, - PathDesignation pathDesignation, - std::lock_guard const&) const; - - bool - setStoredInShard( - std::shared_ptr& shard, - std::shared_ptr const& ledger); - - void - removeFailedShard(std::shared_ptr& shard); - - // Returns the index that represents the logical - // partition between historical and recent shards - std::uint32_t - shardBoundaryIndex() const; - - std::uint32_t - numHistoricalShards(std::lock_guard const& lock) const; - - // Shifts the recent and second most recent (by index) - // shards as new shards become available on the network. - // Older shards are moved to a historical shard path. - void - relocateOutdatedShards(std::lock_guard const& lock); - - // Checks whether the shard can be stored. If - // the new shard can't be stored, returns - // std::nullopt. Otherwise returns an enum - // indicating whether the new shard should be - // placed in a separate directory for historical - // shards. - std::optional - prepareForNewShard( - std::uint32_t shardIndex, - std::uint32_t numHistoricalShards, - std::lock_guard const& lock); - - boost::filesystem::path - chooseHistoricalPath(std::lock_guard const&) const; - - /** - * @brief iterateShardsForward Visits all shards starting from given - * in ascending order and calls given callback function to each - * of them passing shard as parameter. - * @param minShardIndex Start shard index to visit or none if all shards - * should be visited. - * @param visit Callback function to call. - * @return True if each callback function returned true, false otherwise. - */ - bool - iterateShardsForward( - std::optional minShardIndex, - std::function const& visit); - - /** - * @brief iterateShardsBack Visits all shards starting from given - * in descending order and calls given callback function to each - * of them passing shard as parameter. - * @param maxShardIndex Start shard index to visit or none if all shards - * should be visited. - * @param visit Callback function to call. - * @return True if each callback function returned true, false otherwise. - */ - bool - iterateShardsBack( - std::optional maxShardIndex, - std::function const& visit); - - bool - checkHistoricalPaths(std::lock_guard const&) const; - - std::unique_ptr - getShardInfo(std::lock_guard const&) const; - - // Update peers with the status of every complete and incomplete shard - void - updatePeers(std::lock_guard const& lock) const; - - // Start the node store import process - void - startDatabaseImportThread(std::lock_guard const&); -}; - -} // namespace NodeStore -} // namespace ripple - -#endif diff --git a/src/xrpld/nodestore/detail/DeterministicShard.cpp b/src/xrpld/nodestore/detail/DeterministicShard.cpp deleted file mode 100644 index c575a685ded..00000000000 --- a/src/xrpld/nodestore/detail/DeterministicShard.cpp +++ /dev/null @@ -1,216 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { -namespace NodeStore { - -DeterministicShard::DeterministicShard( - Application& app, - boost::filesystem::path const& dir, - std::uint32_t index, - beast::Journal j) - : app_(app) - , index_(index) - , dir_(dir / "tmp") - , ctx_(std::make_unique()) - , j_(j) - , curMemObjs_(0) - , maxMemObjs_( - app_.getShardStore()->ledgersPerShard() <= 256 ? maxMemObjsTest - : maxMemObjsDefault) -{ -} - -DeterministicShard::~DeterministicShard() -{ - close(true); -} - -bool -DeterministicShard::init(Serializer const& finalKey) -{ - auto db = app_.getShardStore(); - - auto fail = [&](std::string const& msg) { - JLOG(j_.error()) << "deterministic shard " << index_ - << " not created: " << msg; - backend_.reset(); - try - { - remove_all(dir_); - } - catch (std::exception const& e) - { - JLOG(j_.error()) << "deterministic shard " << index_ - << ". Exception caught in function " << __func__ - << ". Error: " << e.what(); - } - return false; - }; - - if (!db) - return fail("shard store not exists"); - - if (index_ < db->earliestShardIndex()) - return fail("Invalid shard index"); - - Config const& config{app_.config()}; - Section section{config.section(ConfigSection::shardDatabase())}; - auto const type{get(section, "type", "nudb")}; - auto const factory{Manager::instance().find(type)}; - if (!factory) - return fail("failed to find factory for " + type); - - section.set("path", dir_.string()); - backend_ = factory->createInstance( - NodeObject::keyBytes, section, 1, scheduler_, *ctx_, j_); - - if (!backend_) - return fail("failed to create database"); - - ripemd160_hasher h; - h(finalKey.data(), finalKey.size()); - auto const result{static_cast(h)}; - auto const hash{uint160::fromVoid(result.data())}; - - auto digest = [&](int n) { - auto const data{hash.data()}; - std::uint64_t result{0}; - - switch (n) - { - case 0: - case 1: - // Construct 64 bits from sequential eight bytes - for (int i = 0; i < 8; i++) - result = (result << 8) + data[n * 8 + i]; - break; - - case 2: - // Construct 64 bits using the last four bytes of data - result = (static_cast(data[16]) << 24) + - (static_cast(data[17]) << 16) + - (static_cast(data[18]) << 8) + - (static_cast(data[19])); - break; - } - - return result; - }; - auto const uid{digest(0)}; - auto const salt{digest(1)}; - auto const appType{digest(2) | deterministicType}; - - // Open or create the NuDB key/value store - try - { - if (exists(dir_)) - remove_all(dir_); - - backend_->open(true, appType, uid, salt); - } - catch (std::exception const& e) - { - return fail( - std::string(". Exception caught in function ") + __func__ + - ". Error: " + e.what()); - } - - return true; -} - -std::shared_ptr -make_DeterministicShard( - Application& app, - boost::filesystem::path const& shardDir, - std::uint32_t shardIndex, - Serializer const& finalKey, - beast::Journal j) -{ - std::shared_ptr dShard( - new DeterministicShard(app, shardDir, shardIndex, j)); - if (!dShard->init(finalKey)) - return {}; - return dShard; -} - -void -DeterministicShard::close(bool cancel) -{ - try - { - if (cancel) - { - backend_.reset(); - remove_all(dir_); - } - else - { - ctx_->flush(); - curMemObjs_ = 0; - backend_.reset(); - } - } - catch (std::exception const& e) - { - JLOG(j_.error()) << "deterministic shard " << index_ - << ". Exception caught in function " << __func__ - << ". Error: " << e.what(); - } -} - -bool -DeterministicShard::store(std::shared_ptr const& nodeObject) -{ - try - { - backend_->store(nodeObject); - - // Flush to the backend if at threshold - if (++curMemObjs_ >= maxMemObjs_) - { - ctx_->flush(); - curMemObjs_ = 0; - } - } - catch (std::exception const& e) - { - JLOG(j_.error()) << "deterministic shard " << index_ - << ". Exception caught in function " << __func__ - << ". Error: " << e.what(); - return false; - } - - return true; -} - -} // namespace NodeStore -} // namespace ripple diff --git a/src/xrpld/nodestore/detail/DeterministicShard.h b/src/xrpld/nodestore/detail/DeterministicShard.h deleted file mode 100644 index 3eb5eaa8144..00000000000 --- a/src/xrpld/nodestore/detail/DeterministicShard.h +++ /dev/null @@ -1,174 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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_NODESTORE_DETERMINISTICSHARD_H_INCLUDED -#define RIPPLE_NODESTORE_DETERMINISTICSHARD_H_INCLUDED - -#include -#include -#include -#include - -namespace ripple { -namespace NodeStore { - -/** DeterministicShard class. - * - * 1. The init() method creates temporary folder dir_, - * and the deterministic shard is initialized in that folder. - * 2. The store() method adds object to memory pool. - * 3. The flush() method stores all objects from memory pool to the shard - * located in dir_ in sorted order. - * 4. The close(true) method closes the backend and removes the directory. - */ -class DeterministicShard -{ - constexpr static std::uint32_t maxMemObjsDefault = 16384u; - constexpr static std::uint32_t maxMemObjsTest = 16u; - - /* "SHRD" in ASCII */ - constexpr static std::uint64_t deterministicType = 0x5348524400000000ll; - -private: - DeterministicShard(DeterministicShard const&) = delete; - DeterministicShard& - operator=(DeterministicShard const&) = delete; - - /** Creates the object for shard database - * - * @param app Application object - * @param dir Directory where shard is located - * @param index Index of the shard - * @param j Journal to logging - */ - DeterministicShard( - Application& app, - boost::filesystem::path const& dir, - std::uint32_t index, - beast::Journal j); - - /** Initializes the deterministic shard. - * - * @param finalKey Serializer of shard's final key which consists of: - * shard version (32 bit) - * first ledger sequence in the shard (32 bit) - * last ledger sequence in the shard (32 bit) - * hash of last ledger (256 bits) - * @return true if no error, false if error - */ - bool - init(Serializer const& finalKey); - -public: - ~DeterministicShard(); - - /** Finalizes and closes the shard. - */ - void - close() - { - close(false); - } - - [[nodiscard]] boost::filesystem::path const& - getDir() const - { - return dir_; - } - - /** Store a node object in memory. - * - * @param nodeObject The node object to store - * @return true on success. - * @note Flushes all objects in memory to the backend when the number - * of node objects held in memory exceed a threshold - */ - [[nodiscard]] bool - store(std::shared_ptr const& nodeObject); - -private: - /** Finalizes and closes the shard. - * - * @param cancel True if reject the shard and delete all files, - * false if finalize the shard and store them - */ - void - close(bool cancel); - - // Application reference - Application& app_; - - // Shard Index - std::uint32_t const index_; - - // Path to temporary database files - boost::filesystem::path const dir_; - - // Dummy scheduler for deterministic write - DummyScheduler scheduler_; - - // NuDB context - std::unique_ptr ctx_; - - // NuDB key/value store for node objects - std::shared_ptr backend_; - - // Journal - beast::Journal const j_; - - // Current number of in-cache objects - std::uint32_t curMemObjs_; - - // Maximum number of in-cache objects - std::uint32_t const maxMemObjs_; - - friend std::shared_ptr - make_DeterministicShard( - Application& app, - boost::filesystem::path const& shardDir, - std::uint32_t shardIndex, - Serializer const& finalKey, - beast::Journal j); -}; - -/** Creates shared pointer to deterministic shard and initializes it. - * - * @param app Application object - * @param shardDir Directory where shard is located - * @param shardIndex Index of the shard - * @param finalKey Serializer of shard's ginal key which consists of: - * shard version (32 bit) - * first ledger sequence in the shard (32 bit) - * last ledger sequence in the shard (32 bit) - * hash of last ledger (256 bits) - * @param j Journal to logging - * @return Shared pointer to deterministic shard or {} in case of error. - */ -std::shared_ptr -make_DeterministicShard( - Application& app, - boost::filesystem::path const& shardDir, - std::uint32_t shardIndex, - Serializer const& finalKey, - beast::Journal j); - -} // namespace NodeStore -} // namespace ripple - -#endif diff --git a/src/xrpld/nodestore/detail/Shard.cpp b/src/xrpld/nodestore/detail/Shard.cpp deleted file mode 100644 index 8c2e9997fbf..00000000000 --- a/src/xrpld/nodestore/detail/Shard.cpp +++ /dev/null @@ -1,1272 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2017 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { -namespace NodeStore { - -uint256 const Shard::finalKey{0}; - -Shard::Shard( - Application& app, - DatabaseShard const& db, - std::uint32_t index, - beast::Journal j) - : Shard(app, db, index, "", j) -{ -} - -Shard::Shard( - Application& app, - DatabaseShard const& db, - std::uint32_t index, - boost::filesystem::path const& dir, - beast::Journal j) - : app_(app) - , j_(j) - , index_(index) - , firstSeq_(db.firstLedgerSeq(index)) - , lastSeq_(std::max(firstSeq_, db.lastLedgerSeq(index))) - , maxLedgers_(db.maxLedgers(index)) - , dir_((dir.empty() ? db.getRootDir() : dir) / std::to_string(index_)) -{ -} - -Shard::~Shard() -{ - if (!removeOnDestroy_) - return; - - if (backend_) - { - // Abort removal if the backend is in use - if (backendCount_ > 0) - { - JLOG(j_.error()) << "shard " << index_ - << " backend in use, unable to remove directory"; - return; - } - - // Release database files first otherwise remove_all may fail - backend_.reset(); - lgrSQLiteDB_.reset(); - txSQLiteDB_.reset(); - acquireInfo_.reset(); - } - - try - { - boost::filesystem::remove_all(dir_); - } - catch (std::exception const& e) - { - JLOG(j_.fatal()) << "shard " << index_ - << ". Exception caught in function " << __func__ - << ". Error: " << e.what(); - } -} - -bool -Shard::init(Scheduler& scheduler, nudb::context& context) -{ - Section section{app_.config().section(ConfigSection::shardDatabase())}; - std::string const type{get(section, "type", "nudb")}; - auto const factory{Manager::instance().find(type)}; - if (!factory) - { - JLOG(j_.error()) << "shard " << index_ << " failed to find factory for " - << type; - return false; - } - section.set("path", dir_.string()); - - std::lock_guard lock{mutex_}; - if (backend_) - { - JLOG(j_.error()) << "shard " << index_ << " already initialized"; - return false; - } - backend_ = factory->createInstance( - NodeObject::keyBytes, - section, - megabytes( - app_.config().getValueFor(SizedItem::burstSize, std::nullopt)), - scheduler, - context, - j_); - - return open(lock); -} - -bool -Shard::isOpen() const -{ - std::lock_guard lock(mutex_); - if (!backend_) - { - JLOG(j_.error()) << "shard " << index_ << " not initialized"; - return false; - } - - return backend_->isOpen(); -} - -bool -Shard::tryClose() -{ - // Keep database open if being acquired or finalized - if (state_ != ShardState::finalized) - return false; - - std::lock_guard lock(mutex_); - - // Keep database open if in use - if (backendCount_ > 0) - return false; - - if (!backend_) - { - JLOG(j_.error()) << "shard " << index_ << " not initialized"; - return false; - } - if (!backend_->isOpen()) - return false; - - try - { - backend_->close(); - } - catch (std::exception const& e) - { - JLOG(j_.fatal()) << "shard " << index_ - << ". Exception caught in function " << __func__ - << ". Error: " << e.what(); - return false; - } - - lgrSQLiteDB_.reset(); - txSQLiteDB_.reset(); - acquireInfo_.reset(); - - // Reset caches to reduce memory use - app_.getShardFamily()->getFullBelowCache(lastSeq_)->reset(); - app_.getShardFamily()->getTreeNodeCache(lastSeq_)->reset(); - - return true; -} - -std::optional -Shard::prepare() -{ - if (state_ != ShardState::acquire) - { - JLOG(j_.warn()) << "shard " << index_ - << " prepare called when not acquiring"; - return std::nullopt; - } - - std::lock_guard lock(mutex_); - if (!acquireInfo_) - { - JLOG(j_.error()) << "shard " << index_ - << " missing acquire SQLite database"; - return std::nullopt; - } - - if (acquireInfo_->storedSeqs.empty()) - return lastSeq_; - return prevMissing(acquireInfo_->storedSeqs, 1 + lastSeq_, firstSeq_); -} - -bool -Shard::storeNodeObject(std::shared_ptr const& nodeObject) -{ - if (state_ != ShardState::acquire) - { - // The import node store case is an exception - if (nodeObject->getHash() != finalKey) - { - // Ignore residual calls from InboundLedgers - JLOG(j_.trace()) << "shard " << index_ << " not acquiring"; - return false; - } - } - - auto const scopedCount{makeBackendCount()}; - if (!scopedCount) - return false; - - try - { - std::lock_guard lock(mutex_); - backend_->store(nodeObject); - } - catch (std::exception const& e) - { - JLOG(j_.fatal()) << "shard " << index_ - << ". Exception caught in function " << __func__ - << ". Error: " << e.what(); - return false; - } - - return true; -} - -std::shared_ptr -Shard::fetchNodeObject(uint256 const& hash, FetchReport& fetchReport) -{ - auto const scopedCount{makeBackendCount()}; - if (!scopedCount) - return nullptr; - - std::shared_ptr nodeObject; - - // Try the backend - Status status; - try - { - std::lock_guard lock(mutex_); - status = backend_->fetch(hash.data(), &nodeObject); - } - catch (std::exception const& e) - { - JLOG(j_.fatal()) << "shard " << index_ - << ". Exception caught in function " << __func__ - << ". Error: " << e.what(); - return nullptr; - } - - switch (status) - { - case ok: - case notFound: - break; - case dataCorrupt: { - JLOG(j_.fatal()) - << "shard " << index_ << ". Corrupt node object at hash " - << to_string(hash); - break; - } - default: { - JLOG(j_.warn()) - << "shard " << index_ << ". Unknown status=" << status - << " fetching node object at hash " << to_string(hash); - break; - } - } - - if (nodeObject) - fetchReport.wasFound = true; - - return nodeObject; -} - -Shard::StoreLedgerResult -Shard::storeLedger( - std::shared_ptr const& srcLedger, - std::shared_ptr const& next) -{ - StoreLedgerResult result; - if (state_ != ShardState::acquire) - { - // Ignore residual calls from InboundLedgers - JLOG(j_.trace()) << "shard " << index_ << ". Not acquiring"; - return result; - } - if (containsLedger(srcLedger->info().seq)) - { - JLOG(j_.trace()) << "shard " << index_ << ". Ledger already stored"; - return result; - } - - auto fail = [&](std::string const& msg) { - JLOG(j_.error()) << "shard " << index_ << ". Source ledger sequence " - << srcLedger->info().seq << ". " << msg; - result.error = true; - return result; - }; - - if (srcLedger->info().hash.isZero()) - return fail("Invalid hash"); - if (srcLedger->info().accountHash.isZero()) - return fail("Invalid account hash"); - - auto& srcDB{const_cast(srcLedger->stateMap().family().db())}; - if (&srcDB == &(app_.getShardFamily()->db())) - return fail("Source and destination databases are the same"); - - auto const scopedCount{makeBackendCount()}; - if (!scopedCount) - return fail("Failed to lock backend"); - - Batch batch; - batch.reserve(batchWritePreallocationSize); - auto storeBatch = [&]() { - std::uint64_t sz{0}; - for (auto const& nodeObject : batch) - sz += nodeObject->getData().size(); - - try - { - std::lock_guard lock(mutex_); - backend_->storeBatch(batch); - } - catch (std::exception const& e) - { - fail( - std::string(". Exception caught in function ") + __func__ + - ". Error: " + e.what()); - return false; - } - - result.count += batch.size(); - result.size += sz; - batch.clear(); - return true; - }; - - // Store ledger header - { - Serializer s(sizeof(std::uint32_t) + sizeof(LedgerInfo)); - s.add32(HashPrefix::ledgerMaster); - addRaw(srcLedger->info(), s); - auto nodeObject = NodeObject::createObject( - hotLEDGER, std::move(s.modData()), srcLedger->info().hash); - batch.emplace_back(std::move(nodeObject)); - } - - bool error = false; - auto visit = [&](SHAMapTreeNode const& node) { - if (!stop_) - { - if (auto nodeObject = srcDB.fetchNodeObject( - node.getHash().as_uint256(), srcLedger->info().seq)) - { - batch.emplace_back(std::move(nodeObject)); - if (batch.size() < batchWritePreallocationSize || storeBatch()) - return true; - } - } - - error = true; - return false; - }; - - // Store the state map - if (srcLedger->stateMap().getHash().isNonZero()) - { - if (!srcLedger->stateMap().isValid()) - return fail("Invalid state map"); - - if (next && next->info().parentHash == srcLedger->info().hash) - { - auto have = next->stateMap().snapShot(false); - srcLedger->stateMap().snapShot(false)->visitDifferences( - &(*have), visit); - } - else - srcLedger->stateMap().snapShot(false)->visitNodes(visit); - if (error) - return fail("Failed to store state map"); - } - - // Store the transaction map - if (srcLedger->info().txHash.isNonZero()) - { - if (!srcLedger->txMap().isValid()) - return fail("Invalid transaction map"); - - srcLedger->txMap().snapShot(false)->visitNodes(visit); - if (error) - return fail("Failed to store transaction map"); - } - - if (!batch.empty() && !storeBatch()) - return fail("Failed to store"); - - return result; -} - -bool -Shard::setLedgerStored(std::shared_ptr const& ledger) -{ - if (state_ != ShardState::acquire) - { - // Ignore residual calls from InboundLedgers - JLOG(j_.trace()) << "shard " << index_ << " not acquiring"; - return false; - } - - auto fail = [&](std::string const& msg) { - JLOG(j_.error()) << "shard " << index_ << ". " << msg; - return false; - }; - - auto const ledgerSeq{ledger->info().seq}; - if (ledgerSeq < firstSeq_ || ledgerSeq > lastSeq_) - return fail("Invalid ledger sequence " + std::to_string(ledgerSeq)); - - auto const scopedCount{makeBackendCount()}; - if (!scopedCount) - return false; - - // This lock is used as an optimization to prevent unneeded - // calls to storeSQLite before acquireInfo_ is updated - std::lock_guard storedLock(storedMutex_); - - { - std::lock_guard lock(mutex_); - if (!acquireInfo_) - return fail("Missing acquire SQLite database"); - - if (boost::icl::contains(acquireInfo_->storedSeqs, ledgerSeq)) - { - // Ignore redundant calls - JLOG(j_.debug()) << "shard " << index_ << " ledger sequence " - << ledgerSeq << " already stored"; - return true; - } - } - - if (!storeSQLite(ledger)) - return fail("Failed to store ledger"); - - std::lock_guard lock(mutex_); - - // Update the acquire database - acquireInfo_->storedSeqs.insert(ledgerSeq); - - try - { - auto session{acquireInfo_->SQLiteDB->checkoutDb()}; - soci::blob sociBlob(*session); - convert(to_string(acquireInfo_->storedSeqs), sociBlob); - if (ledgerSeq == lastSeq_) - { - // Store shard's last ledger hash - auto const sHash{to_string(ledger->info().hash)}; - *session << "UPDATE Shard " - "SET LastLedgerHash = :lastLedgerHash," - "StoredLedgerSeqs = :storedLedgerSeqs " - "WHERE ShardIndex = :shardIndex;", - soci::use(sHash), soci::use(sociBlob), soci::use(index_); - } - else - { - *session << "UPDATE Shard " - "SET StoredLedgerSeqs = :storedLedgerSeqs " - "WHERE ShardIndex = :shardIndex;", - soci::use(sociBlob), soci::use(index_); - } - } - catch (std::exception const& e) - { - acquireInfo_->storedSeqs.erase(ledgerSeq); - return fail( - std::string(". Exception caught in function ") + __func__ + - ". Error: " + e.what()); - } - - // Update progress - progress_ = boost::icl::length(acquireInfo_->storedSeqs); - if (progress_ == maxLedgers_) - state_ = ShardState::complete; - - setFileStats(lock); - JLOG(j_.trace()) << "shard " << index_ << " stored ledger sequence " - << ledgerSeq; - return true; -} - -bool -Shard::containsLedger(std::uint32_t ledgerSeq) const -{ - if (ledgerSeq < firstSeq_ || ledgerSeq > lastSeq_) - return false; - if (state_ != ShardState::acquire) - return true; - - std::lock_guard lock(mutex_); - if (!acquireInfo_) - { - JLOG(j_.error()) << "shard " << index_ - << " missing acquire SQLite database"; - return false; - } - return boost::icl::contains(acquireInfo_->storedSeqs, ledgerSeq); -} - -std::chrono::steady_clock::time_point -Shard::getLastUse() const -{ - std::lock_guard lock(mutex_); - return lastAccess_; -} - -std::pair -Shard::getFileInfo() const -{ - std::lock_guard lock(mutex_); - return {fileSz_, fdRequired_}; -} - -std::int32_t -Shard::getWriteLoad() -{ - auto const scopedCount{makeBackendCount()}; - if (!scopedCount) - return 0; - std::lock_guard lock(mutex_); - return backend_->getWriteLoad(); -} - -bool -Shard::isLegacy() const -{ - std::lock_guard lock(mutex_); - return legacy_; -} - -bool -Shard::finalize(bool writeSQLite, std::optional const& referenceHash) -{ - auto const scopedCount{makeBackendCount()}; - if (!scopedCount) - return false; - - uint256 hash{0}; - std::uint32_t ledgerSeq{0}; - auto fail = [&](std::string const& msg) { - JLOG(j_.fatal()) << "shard " << index_ << ". " << msg - << (hash.isZero() ? "" - : ". Ledger hash " + to_string(hash)) - << (ledgerSeq == 0 ? "" - : ". Ledger sequence " + - std::to_string(ledgerSeq)); - state_ = ShardState::finalizing; - progress_ = 0; - busy_ = false; - return false; - }; - - try - { - std::lock_guard lock(mutex_); - - state_ = ShardState::finalizing; - progress_ = 0; - - // Check if a final key has been stored - if (std::shared_ptr nodeObject; - backend_->fetch(finalKey.data(), &nodeObject) == Status::ok) - { - // Check final key's value - SerialIter sIt( - nodeObject->getData().data(), nodeObject->getData().size()); - if (sIt.get32() != version) - return fail("invalid version"); - - if (sIt.get32() != firstSeq_ || sIt.get32() != lastSeq_) - return fail("out of range ledger sequences"); - - if (hash = sIt.get256(); hash.isZero()) - return fail("invalid last ledger hash"); - } - else - { - // In the absence of a final key, an acquire SQLite database - // must be present in order to verify the shard - if (!acquireInfo_) - return fail("missing acquire SQLite database"); - - auto [res, seqshash] = selectAcquireDBLedgerSeqsHash( - *acquireInfo_->SQLiteDB->checkoutDb(), index_); - - if (!res) - return fail("missing or invalid ShardIndex"); - - if (!seqshash.hash) - return fail("missing LastLedgerHash"); - - if (!hash.parseHex(*seqshash.hash) || hash.isZero()) - return fail("invalid LastLedgerHash"); - - if (!seqshash.sequences) - return fail("missing StoredLedgerSeqs"); - - auto& storedSeqs{acquireInfo_->storedSeqs}; - if (!from_string(storedSeqs, *seqshash.sequences) || - boost::icl::first(storedSeqs) != firstSeq_ || - boost::icl::last(storedSeqs) != lastSeq_ || - storedSeqs.size() != maxLedgers_) - { - return fail("invalid StoredLedgerSeqs"); - } - } - } - catch (std::exception const& e) - { - return fail( - std::string(". Exception caught in function ") + __func__ + - ". Error: " + e.what()); - } - - // Verify the last ledger hash of a downloaded shard - // using a ledger hash obtained from the peer network - if (referenceHash && *referenceHash != hash) - return fail("invalid last ledger hash"); - - // Verify every ledger stored in the backend - Config const& config{app_.config()}; - std::shared_ptr ledger; - std::shared_ptr next; - auto const lastLedgerHash{hash}; - auto& shardFamily{*app_.getShardFamily()}; - auto const fullBelowCache{shardFamily.getFullBelowCache(lastSeq_)}; - auto const treeNodeCache{shardFamily.getTreeNodeCache(lastSeq_)}; - - // Reset caches to reduce memory usage - fullBelowCache->reset(); - treeNodeCache->reset(); - - Serializer s; - s.add32(version); - s.add32(firstSeq_); - s.add32(lastSeq_); - s.addBitString(lastLedgerHash); - - std::shared_ptr dShard{ - make_DeterministicShard(app_, dir_, index_, s, j_)}; - if (!dShard) - return fail("Failed to create deterministic shard"); - - // Start with the last ledger in the shard and walk backwards from - // child to parent until we reach the first ledger - ledgerSeq = lastSeq_; - while (ledgerSeq >= firstSeq_) - { - if (stop_) - return false; - - auto nodeObject{verifyFetch(hash)}; - if (!nodeObject) - return fail("invalid ledger"); - - ledger = std::make_shared( - deserializePrefixedHeader(makeSlice(nodeObject->getData())), - config, - shardFamily); - if (ledger->info().seq != ledgerSeq) - return fail("invalid ledger sequence"); - if (ledger->info().hash != hash) - return fail("invalid ledger hash"); - - ledger->stateMap().setLedgerSeq(ledgerSeq); - ledger->txMap().setLedgerSeq(ledgerSeq); - ledger->setImmutable(); - if (!ledger->stateMap().fetchRoot( - SHAMapHash{ledger->info().accountHash}, nullptr)) - { - return fail("missing root STATE node"); - } - if (ledger->info().txHash.isNonZero() && - !ledger->txMap().fetchRoot( - SHAMapHash{ledger->info().txHash}, nullptr)) - { - return fail("missing root TXN node"); - } - - if (!verifyLedger(ledger, next, dShard)) - return fail("failed to verify ledger"); - - if (!dShard->store(nodeObject)) - return fail("failed to store node object"); - - if (writeSQLite && !storeSQLite(ledger)) - return fail("failed storing to SQLite databases"); - - assert( - ledger->info().seq == ledgerSeq && - (ledger->info().seq < XRP_LEDGER_EARLIEST_FEES || - ledger->read(keylet::fees()))); - - hash = ledger->info().parentHash; - next = std::move(ledger); - - // Update progress - progress_ = maxLedgers_ - (ledgerSeq - firstSeq_); - - --ledgerSeq; - - fullBelowCache->reset(); - treeNodeCache->reset(); - } - - JLOG(j_.debug()) << "shard " << index_ << " is valid"; - - /* - TODO MP - SQLite VACUUM blocks all database access while processing. - Depending on the file size, that can take a while. Until we find - a non-blocking way of doing this, we cannot enable vacuum as - it can desync a server. - - try - { - // VACUUM the SQLite databases - auto const tmpDir {dir_ / "tmp_vacuum"}; - create_directory(tmpDir); - - auto vacuum = [&tmpDir](std::unique_ptr& sqliteDB) - { - auto session {sqliteDB->checkoutDb()}; - *session << "PRAGMA synchronous=OFF;"; - *session << "PRAGMA journal_mode=OFF;"; - *session << "PRAGMA temp_store_directory='" << - tmpDir.string() << "';"; - *session << "VACUUM;"; - }; - vacuum(lgrSQLiteDB_); - vacuum(txSQLiteDB_); - remove_all(tmpDir); - } - catch (std::exception const& e) - { - return fail( - std::string(". Exception caught in function ") + __func__ + - ". Error: " + e.what()); - } - */ - - auto const nodeObject{ - NodeObject::createObject(hotUNKNOWN, std::move(s.modData()), finalKey)}; - if (!dShard->store(nodeObject)) - return fail("failed to store node object"); - - try - { - { - // Store final key's value, may already be stored - std::lock_guard lock(mutex_); - backend_->store(nodeObject); - } - - // Do not allow all other threads work with the shard - busy_ = true; - - // Wait until all other threads leave the shard - while (backendCount_ > 1) - std::this_thread::yield(); - - std::lock_guard lock(mutex_); - - // Close original backend - backend_->close(); - - // Close SQL databases - lgrSQLiteDB_.reset(); - txSQLiteDB_.reset(); - - // Remove the acquire SQLite database - if (acquireInfo_) - { - acquireInfo_.reset(); - remove_all(dir_ / AcquireShardDBName); - } - - // Close deterministic backend - dShard->close(); - - // Replace original backend with deterministic backend - remove(dir_ / "nudb.key"); - remove(dir_ / "nudb.dat"); - rename(dShard->getDir() / "nudb.key", dir_ / "nudb.key"); - rename(dShard->getDir() / "nudb.dat", dir_ / "nudb.dat"); - - // Re-open deterministic shard - if (!open(lock)) - return fail("failed to open"); - - assert(state_ == ShardState::finalized); - - // Allow all other threads work with the shard - busy_ = false; - } - catch (std::exception const& e) - { - return fail( - std::string(". Exception caught in function ") + __func__ + - ". Error: " + e.what()); - } - - return true; -} - -bool -Shard::open(std::lock_guard const& lock) -{ - using namespace boost::filesystem; - Config const& config{app_.config()}; - auto preexist{false}; - auto fail = [this, &preexist](std::string const& msg) REQUIRES(mutex_) { - backend_->close(); - lgrSQLiteDB_.reset(); - txSQLiteDB_.reset(); - acquireInfo_.reset(); - - state_ = ShardState::acquire; - progress_ = 0; - - if (!preexist) - remove_all(dir_); - - if (!msg.empty()) - { - JLOG(j_.fatal()) << "shard " << index_ << " " << msg; - } - return false; - }; - auto createAcquireInfo = [this, &config]() REQUIRES(mutex_) { - DatabaseCon::Setup setup; - setup.startUp = config.standalone() ? config.LOAD : config.START_UP; - setup.standAlone = config.standalone(); - setup.dataDir = dir_; - setup.useGlobalPragma = true; - - acquireInfo_ = std::make_unique(); - acquireInfo_->SQLiteDB = makeAcquireDB( - setup, - DatabaseCon::CheckpointerSetup{&app_.getJobQueue(), &app_.logs()}); - - state_ = ShardState::acquire; - progress_ = 0; - }; - - try - { - // Open or create the NuDB key/value store - preexist = exists(dir_); - backend_->open(!preexist); - - if (!preexist) - { - // A new shard - createAcquireInfo(); - insertAcquireDBIndex(acquireInfo_->SQLiteDB->getSession(), index_); - } - else if (exists(dir_ / AcquireShardDBName)) - { - // A shard being acquired, backend is likely incomplete - createAcquireInfo(); - auto [res, s] = selectAcquireDBLedgerSeqs( - acquireInfo_->SQLiteDB->getSession(), index_); - - if (!res) - return fail("invalid acquire SQLite database"); - - if (s) - { - auto& storedSeqs{acquireInfo_->storedSeqs}; - if (!from_string(storedSeqs, *s)) - return fail("invalid StoredLedgerSeqs"); - - if (boost::icl::first(storedSeqs) < firstSeq_ || - boost::icl::last(storedSeqs) > lastSeq_) - { - return fail("invalid StoredLedgerSeqs"); - } - - // Check if backend is complete - progress_ = boost::icl::length(storedSeqs); - if (progress_ == maxLedgers_) - state_ = ShardState::complete; - } - } - else - { - // A shard with a finalized or complete state - std::shared_ptr nodeObject; - if (backend_->fetch(finalKey.data(), &nodeObject) != Status::ok) - { - legacy_ = true; - return fail("incompatible, missing backend final key"); - } - - // Check final key's value - SerialIter sIt( - nodeObject->getData().data(), nodeObject->getData().size()); - if (sIt.get32() != version) - return fail("invalid version"); - - if (sIt.get32() != firstSeq_ || sIt.get32() != lastSeq_) - return fail("out of range ledger sequences"); - - if (sIt.get256().isZero()) - return fail("invalid last ledger hash"); - - if (exists(dir_ / LgrDBName) && exists(dir_ / TxDBName)) - { - lastAccess_ = std::chrono::steady_clock::now(); - state_ = ShardState::finalized; - } - else - state_ = ShardState::complete; - - progress_ = maxLedgers_; - } - } - catch (std::exception const& e) - { - return fail( - std::string(". Exception caught in function ") + __func__ + - ". Error: " + e.what()); - } - - if (!initSQLite(lock)) - return fail({}); - - setFileStats(lock); - return true; -} - -bool -Shard::initSQLite(std::lock_guard const&) -{ - Config const& config{app_.config()}; - DatabaseCon::Setup const setup = [&]() { - DatabaseCon::Setup setup; - setup.startUp = config.standalone() ? config.LOAD : config.START_UP; - setup.standAlone = config.standalone(); - setup.dataDir = dir_; - setup.useGlobalPragma = (state_ != ShardState::complete); - return setup; - }(); - - try - { - if (lgrSQLiteDB_) - lgrSQLiteDB_.reset(); - - if (txSQLiteDB_) - txSQLiteDB_.reset(); - - switch (state_) - { - case ShardState::complete: - case ShardState::finalizing: - case ShardState::finalized: { - auto [lgr, tx] = makeShardCompleteLedgerDBs(config, setup); - - lgrSQLiteDB_ = std::move(lgr); - lgrSQLiteDB_->getSession() << boost::str( - boost::format("PRAGMA cache_size=-%d;") % - kilobytes(config.getValueFor( - SizedItem::lgrDBCache, std::nullopt))); - - txSQLiteDB_ = std::move(tx); - txSQLiteDB_->getSession() << boost::str( - boost::format("PRAGMA cache_size=-%d;") % - kilobytes(config.getValueFor( - SizedItem::txnDBCache, std::nullopt))); - break; - } - - // case ShardState::acquire: - // case ShardState::queued: - default: { - // Incomplete shards use a Write Ahead Log for performance - auto [lgr, tx] = makeShardIncompleteLedgerDBs( - config, - setup, - DatabaseCon::CheckpointerSetup{ - &app_.getJobQueue(), &app_.logs()}); - - lgrSQLiteDB_ = std::move(lgr); - lgrSQLiteDB_->getSession() << boost::str( - boost::format("PRAGMA cache_size=-%d;") % - kilobytes(config.getValueFor(SizedItem::lgrDBCache))); - - txSQLiteDB_ = std::move(tx); - txSQLiteDB_->getSession() << boost::str( - boost::format("PRAGMA cache_size=-%d;") % - kilobytes(config.getValueFor(SizedItem::txnDBCache))); - break; - } - } - } - catch (std::exception const& e) - { - JLOG(j_.fatal()) << "shard " << index_ - << ". Exception caught in function " << __func__ - << ". Error: " << e.what(); - return false; - } - - return true; -} - -bool -Shard::storeSQLite(std::shared_ptr const& ledger) -{ - if (stop_) - return false; - - try - { - std::lock_guard lock(mutex_); - - auto res = updateLedgerDBs( - *txSQLiteDB_->checkoutDb(), - *lgrSQLiteDB_->checkoutDb(), - ledger, - index_, - stop_, - j_); - - if (!res) - return false; - - // Update the acquire database if present - if (acquireInfo_) - { - std::optional s; - if (!acquireInfo_->storedSeqs.empty()) - s = to_string(acquireInfo_->storedSeqs); - - updateAcquireDB( - acquireInfo_->SQLiteDB->getSession(), - ledger, - index_, - lastSeq_, - s); - } - } - catch (std::exception const& e) - { - JLOG(j_.fatal()) << "shard " << index_ - << ". Exception caught in function " << __func__ - << ". Error: " << e.what(); - return false; - } - - return true; -} - -void -Shard::setFileStats(std::lock_guard const&) -{ - fileSz_ = 0; - fdRequired_ = 0; - try - { - using namespace boost::filesystem; - for (auto const& d : directory_iterator(dir_)) - { - if (is_regular_file(d)) - { - fileSz_ += file_size(d); - ++fdRequired_; - } - } - } - catch (std::exception const& e) - { - JLOG(j_.fatal()) << "shard " << index_ - << ". Exception caught in function " << __func__ - << ". Error: " << e.what(); - } -} - -bool -Shard::verifyLedger( - std::shared_ptr const& ledger, - std::shared_ptr const& next, - std::shared_ptr const& dShard) const -{ - auto fail = [j = j_, index = index_, &ledger](std::string const& msg) { - JLOG(j.error()) << "shard " << index << ". " << msg - << (ledger->info().hash.isZero() ? "" - : ". Ledger hash " + - to_string(ledger->info().hash)) - << (ledger->info().seq == 0 ? "" - : ". Ledger sequence " + - std::to_string(ledger->info().seq)); - return false; - }; - - if (ledger->info().hash.isZero()) - return fail("Invalid ledger hash"); - if (ledger->info().accountHash.isZero()) - return fail("Invalid ledger account hash"); - - bool error{false}; - auto visit = [this, &error, &dShard](SHAMapTreeNode const& node) { - if (stop_) - return false; - - auto nodeObject{verifyFetch(node.getHash().as_uint256())}; - if (!nodeObject || !dShard->store(nodeObject)) - error = true; - - return !error; - }; - - // Verify the state map - if (ledger->stateMap().getHash().isNonZero()) - { - if (!ledger->stateMap().isValid()) - return fail("Invalid state map"); - - try - { - if (next && next->info().parentHash == ledger->info().hash) - ledger->stateMap().visitDifferences(&next->stateMap(), visit); - else - ledger->stateMap().visitNodes(visit); - } - catch (std::exception const& e) - { - return fail( - std::string(". Exception caught in function ") + __func__ + - ". Error: " + e.what()); - } - - if (stop_) - return false; - if (error) - return fail("Invalid state map"); - } - - // Verify the transaction map - if (ledger->info().txHash.isNonZero()) - { - if (!ledger->txMap().isValid()) - return fail("Invalid transaction map"); - - try - { - ledger->txMap().visitNodes(visit); - } - catch (std::exception const& e) - { - return fail( - std::string(". Exception caught in function ") + __func__ + - ". Error: " + e.what()); - } - - if (stop_) - return false; - if (error) - return fail("Invalid transaction map"); - } - - return true; -} - -std::shared_ptr -Shard::verifyFetch(uint256 const& hash) const -{ - std::shared_ptr nodeObject; - auto fail = - [j = j_, index = index_, &hash, &nodeObject](std::string const& msg) { - JLOG(j.error()) << "shard " << index << ". " << msg - << ". Node object hash " << to_string(hash); - nodeObject.reset(); - return nodeObject; - }; - - try - { - std::lock_guard lock(mutex_); - switch (backend_->fetch(hash.data(), &nodeObject)) - { - case ok: - // Verify that the hash of node object matches the payload - if (nodeObject->getHash() != - sha512Half(makeSlice(nodeObject->getData()))) - return fail("Node object hash does not match payload"); - return nodeObject; - case notFound: - return fail("Missing node object"); - case dataCorrupt: - return fail("Corrupt node object"); - default: - return fail("Unknown error"); - } - } - catch (std::exception const& e) - { - return fail( - std::string(". Exception caught in function ") + __func__ + - ". Error: " + e.what()); - } -} - -Shard::Count -Shard::makeBackendCount() -{ - if (stop_ || busy_) - return Shard::Count{nullptr}; - - std::lock_guard lock(mutex_); - if (!backend_) - { - JLOG(j_.error()) << "shard " << index_ << " not initialized"; - return Shard::Count{nullptr}; - } - if (!backend_->isOpen()) - { - if (!open(lock)) - return Shard::Count{nullptr}; - } - else if (state_ == ShardState::finalized) - lastAccess_ = std::chrono::steady_clock::now(); - - return Shard::Count(&backendCount_); -} - -bool -Shard::doCallForSQL( - std::function const& callback, - LockedSociSession&& db) -{ - return callback(*db); -} - -bool -Shard::doCallForSQL( - std::function const& - callback, - LockedSociSession&& db) -{ - return callback(*db, index_); -} - -} // namespace NodeStore -} // namespace ripple diff --git a/src/xrpld/nodestore/detail/Shard.h b/src/xrpld/nodestore/detail/Shard.h deleted file mode 100644 index be11e538c77..00000000000 --- a/src/xrpld/nodestore/detail/Shard.h +++ /dev/null @@ -1,432 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2017 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_NODESTORE_SHARD_H_INCLUDED -#define RIPPLE_NODESTORE_SHARD_H_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -namespace ripple { -namespace NodeStore { - -using PCache = TaggedCache; -using NCache = KeyCache; -class DatabaseShard; - -/* A range of historical ledgers backed by a node store. - Shards are indexed and store `ledgersPerShard`. - Shard `i` stores ledgers starting with sequence: `1 + (i * ledgersPerShard)` - and ending with sequence: `(i + 1) * ledgersPerShard`. - Once a shard has all its ledgers, it is never written to again. - - Public functions can be called concurrently from any thread. -*/ -class Shard final -{ -public: - /// Copy constructor (disallowed) - Shard(Shard const&) = delete; - - /// Move constructor (disallowed) - Shard(Shard&&) = delete; - - // Copy assignment (disallowed) - Shard& - operator=(Shard const&) = delete; - - // Move assignment (disallowed) - Shard& - operator=(Shard&&) = delete; - - Shard( - Application& app, - DatabaseShard const& db, - std::uint32_t index, - boost::filesystem::path const& dir, - beast::Journal j); - - Shard( - Application& app, - DatabaseShard const& db, - std::uint32_t index, - beast::Journal j); - - ~Shard(); - - /** Initialize shard. - - @param scheduler The scheduler to use for performing asynchronous tasks. - @param context The context to use for the backend. - */ - [[nodiscard]] bool - init(Scheduler& scheduler, nudb::context& context); - - /** Returns true if the database are open. - */ - [[nodiscard]] bool - isOpen() const; - - /** Try to close databases if not in use. - - @return true if databases were closed. - */ - bool - tryClose(); - - /** Notify shard to prepare for shutdown. - */ - void - stop() noexcept - { - stop_ = true; - } - - [[nodiscard]] std::optional - prepare(); - - [[nodiscard]] bool - storeNodeObject(std::shared_ptr const& nodeObject); - - [[nodiscard]] std::shared_ptr - fetchNodeObject(uint256 const& hash, FetchReport& fetchReport); - - /** Store a ledger. - - @param srcLedger The ledger to store. - @param next The ledger that immediately follows srcLedger, can be null. - @return StoreLedgerResult containing data about the store. - */ - struct StoreLedgerResult - { - std::uint64_t count{0}; // Number of storage calls - std::uint64_t size{0}; // Number of bytes stored - bool error{false}; - }; - - [[nodiscard]] StoreLedgerResult - storeLedger( - std::shared_ptr const& srcLedger, - std::shared_ptr const& next); - - [[nodiscard]] bool - setLedgerStored(std::shared_ptr const& ledger); - - [[nodiscard]] bool - containsLedger(std::uint32_t ledgerSeq) const; - - [[nodiscard]] std::uint32_t - index() const noexcept - { - return index_; - } - - [[nodiscard]] boost::filesystem::path const& - getDir() const noexcept - { - return dir_; - } - - [[nodiscard]] std::chrono::steady_clock::time_point - getLastUse() const; - - /** Returns a pair where the first item describes the storage space - utilized and the second item is the number of file descriptors required. - */ - [[nodiscard]] std::pair - getFileInfo() const; - - [[nodiscard]] ShardState - getState() const noexcept - { - return state_; - } - - /** Returns a percent signifying how complete - the current state of the shard is. - */ - [[nodiscard]] std::uint32_t - getPercentProgress() const noexcept - { - return calculatePercent(progress_, maxLedgers_); - } - - [[nodiscard]] std::int32_t - getWriteLoad(); - - /** Returns `true` if shard is older, without final key data - */ - [[nodiscard]] bool - isLegacy() const; - - /** Finalize shard by walking its ledgers, verifying each Merkle tree and - creating a deterministic backend. - - @param writeSQLite If true, SQLite entries will be rewritten using - verified backend data. - @param referenceHash If present, this hash must match the hash - of the last ledger in the shard. - */ - [[nodiscard]] bool - finalize(bool writeSQLite, std::optional const& referenceHash); - - /** Enables removal of the shard directory on destruction. - */ - void - removeOnDestroy() noexcept - { - removeOnDestroy_ = true; - } - - std::string - getStoredSeqs() - { - std::lock_guard lock(mutex_); - if (!acquireInfo_) - return ""; - - return to_string(acquireInfo_->storedSeqs); - } - - /** Invoke a callback on the ledger SQLite db - - @param callback Callback function to call. - @return Value returned by callback function. - */ - template - bool - callForLedgerSQL(std::function const& callback) - { - return callForSQL(callback, lgrSQLiteDB_->checkoutDb()); - } - - /** Invoke a callback on the transaction SQLite db - - @param callback Callback function to call. - @return Value returned by callback function. - */ - template - bool - callForTransactionSQL(std::function const& callback) - { - return callForSQL(callback, txSQLiteDB_->checkoutDb()); - } - - // Current shard version - static constexpr std::uint32_t version{2}; - - // The finalKey is a hard coded value of zero. It is used to store - // finalizing shard data to the backend. The data contains a version, - // last ledger's hash, and the first and last ledger sequences. - static uint256 const finalKey; - -private: - class Count final - { - public: - Count(Count const&) = delete; - Count& - operator=(Count const&) = delete; - Count& - operator=(Count&&) = delete; - - Count(Count&& other) noexcept : counter_(other.counter_) - { - other.counter_ = nullptr; - } - - explicit Count(std::atomic* counter) noexcept - : counter_(counter) - { - if (counter_) - ++(*counter_); - } - - ~Count() noexcept - { - if (counter_) - --(*counter_); - } - - explicit operator bool() const noexcept - { - return counter_ != nullptr; - } - - private: - std::atomic* counter_; - }; - - struct AcquireInfo - { - // SQLite database to track information about what has been acquired - std::unique_ptr SQLiteDB; - - // Tracks the sequences of ledgers acquired and stored in the backend - RangeSet storedSeqs; - }; - - Application& app_; - beast::Journal const j_; - mutable std::mutex mutex_; - mutable std::mutex storedMutex_; - - // Shard Index - std::uint32_t const index_; - - // First ledger sequence in the shard - std::uint32_t const firstSeq_; - - // Last ledger sequence in the shard - std::uint32_t const lastSeq_; - - // The maximum number of ledgers the shard can store - // The earliest shard may store fewer ledgers than subsequent shards - std::uint32_t const maxLedgers_; - - // Path to database files - boost::filesystem::path const dir_; - - // Storage space utilized by the shard - GUARDED_BY(mutex_) std::uint64_t fileSz_{0}; - - // Number of file descriptors required by the shard - GUARDED_BY(mutex_) std::uint32_t fdRequired_{0}; - - // NuDB key/value store for node objects - std::unique_ptr backend_ GUARDED_BY(mutex_); - - std::atomic backendCount_{0}; - - // Ledger SQLite database used for indexes - std::unique_ptr lgrSQLiteDB_ GUARDED_BY(mutex_); - - // Transaction SQLite database used for indexes - std::unique_ptr txSQLiteDB_ GUARDED_BY(mutex_); - - // Tracking information used only when acquiring a shard from the network. - // If the shard is finalized, this member will be null. - std::unique_ptr acquireInfo_ GUARDED_BY(mutex_); - ; - - // Older shard without an acquire database or final key - // Eventually there will be no need for this and should be removed - GUARDED_BY(mutex_) bool legacy_{false}; - - // Determines if the shard needs to stop processing for shutdown - std::atomic stop_{false}; - - // Determines if the shard busy with replacing by deterministic one - std::atomic busy_{false}; - - // State of the shard - std::atomic state_{ShardState::acquire}; - - // Number of ledgers processed for the current shard state - std::atomic progress_{0}; - - // Determines if the shard directory should be removed in the destructor - std::atomic removeOnDestroy_{false}; - - // The time of the last access of a shard with a finalized state - std::chrono::steady_clock::time_point lastAccess_ GUARDED_BY(mutex_); - ; - - // Open shard databases - [[nodiscard]] bool - open(std::lock_guard const& lock) REQUIRES(mutex_); - - // Open/Create SQLite databases - // Lock over mutex_ required - [[nodiscard]] bool - initSQLite(std::lock_guard const&) REQUIRES(mutex_); - - // Write SQLite entries for this ledger - [[nodiscard]] bool - storeSQLite(std::shared_ptr const& ledger); - - // Set storage and file descriptor usage stats - // Lock over mutex_ required - void - setFileStats(std::lock_guard const&) REQUIRES(mutex_); - - // Verify this ledger by walking its SHAMaps and verifying its Merkle trees - // Every node object verified will be stored in the deterministic shard - [[nodiscard]] bool - verifyLedger( - std::shared_ptr const& ledger, - std::shared_ptr const& next, - std::shared_ptr const& dShard) const; - - // Fetches from backend and log errors based on status codes - [[nodiscard]] std::shared_ptr - verifyFetch(uint256 const& hash) const; - - // Open databases if they are closed - [[nodiscard]] Shard::Count - makeBackendCount(); - - // Invoke a callback on the supplied session parameter - template - bool - callForSQL( - std::function const& callback, - LockedSociSession&& db) - { - auto const scopedCount{makeBackendCount()}; - if (!scopedCount) - return false; - - return doCallForSQL(callback, std::move(db)); - } - - // Invoke a callback that accepts a SQLite session parameter - bool - doCallForSQL( - std::function const& callback, - LockedSociSession&& db); - - // Invoke a callback that accepts a SQLite session and the - // shard index as parameters - bool - doCallForSQL( - std::function< - bool(soci::session& session, std::uint32_t shardIndex)> const& - callback, - LockedSociSession&& db); -}; - -} // namespace NodeStore -} // namespace ripple - -#endif diff --git a/src/xrpld/nodestore/detail/ShardInfo.cpp b/src/xrpld/nodestore/detail/ShardInfo.cpp deleted file mode 100644 index 43a9d484900..00000000000 --- a/src/xrpld/nodestore/detail/ShardInfo.cpp +++ /dev/null @@ -1,136 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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 -#include -#include -#include -#include - -namespace ripple { -namespace NodeStore { - -std::string -ShardInfo::finalizedToString() const -{ - if (!finalized_.empty()) - return ripple::to_string(finalized_); - return {}; -} - -std::string -ShardInfo::incompleteToString() const -{ - std::string result; - if (!incomplete_.empty()) - { - for (auto const& [shardIndex, incomplete] : incomplete_) - { - result += std::to_string(shardIndex) + ":" + - std::to_string(incomplete.percentProgress()) + ","; - } - result.pop_back(); - } - - return result; -} - -bool -ShardInfo::update( - std::uint32_t shardIndex, - ShardState state, - std::uint32_t percentProgress) -{ - if (state == ShardState::finalized) - { - if (boost::icl::contains(finalized_, shardIndex)) - return false; - - finalized_.insert(shardIndex); - return true; - } - - return incomplete_.emplace(shardIndex, Incomplete(state, percentProgress)) - .second; -} - -protocol::TMPeerShardInfoV2 -ShardInfo::makeMessage(Application& app) -{ - protocol::TMPeerShardInfoV2 message; - Serializer s; - s.add32(HashPrefix::shardInfo); - - // Set the message creation time - msgTimestamp_ = app.timeKeeper().now(); - { - auto const timestamp{msgTimestamp_.time_since_epoch().count()}; - message.set_timestamp(timestamp); - s.add32(timestamp); - } - - if (!incomplete_.empty()) - { - message.mutable_incomplete()->Reserve(incomplete_.size()); - for (auto const& [shardIndex, incomplete] : incomplete_) - { - auto tmIncomplete{message.add_incomplete()}; - - tmIncomplete->set_shardindex(shardIndex); - s.add32(shardIndex); - - static_assert(std::is_same_v< - std::underlying_type_t, - std::uint32_t>); - auto const state{static_cast(incomplete.state())}; - tmIncomplete->set_state(state); - s.add32(state); - - // Set progress if greater than zero - auto const percentProgress{incomplete.percentProgress()}; - if (percentProgress > 0) - { - tmIncomplete->set_progress(percentProgress); - s.add32(percentProgress); - } - } - } - - if (!finalized_.empty()) - { - auto const str{ripple::to_string(finalized_)}; - message.set_finalized(str); - s.addRaw(str.data(), str.size()); - } - - // Set the public key - auto const& publicKey{app.nodeIdentity().first}; - message.set_publickey(publicKey.data(), publicKey.size()); - - // Create a digital signature using the node private key - auto const signature{sign(publicKey, app.nodeIdentity().second, s.slice())}; - - // Set the digital signature - message.set_signature(signature.data(), signature.size()); - - return message; -} - -} // namespace NodeStore -} // namespace ripple diff --git a/src/xrpld/nodestore/detail/TaskQueue.cpp b/src/xrpld/nodestore/detail/TaskQueue.cpp deleted file mode 100644 index 6062138c60f..00000000000 --- a/src/xrpld/nodestore/detail/TaskQueue.cpp +++ /dev/null @@ -1,76 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2019 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 - -#include - -namespace ripple { -namespace NodeStore { - -TaskQueue::TaskQueue() : workers_(*this, nullptr, "Shard store taskQueue", 1) -{ -} - -void -TaskQueue::stop() -{ - workers_.stop(); -} - -void -TaskQueue::addTask(std::function task) -{ - { - std::lock_guard lock{mutex_}; - tasks_.emplace(std::move(task)); - } - workers_.addTask(); -} - -size_t -TaskQueue::size() const -{ - std::lock_guard lock{mutex_}; - return tasks_.size() + processing_; -} - -void -TaskQueue::processTask(int instance) -{ - std::function task; - - { - std::lock_guard lock{mutex_}; - - assert(!tasks_.empty()); - task = std::move(tasks_.front()); - tasks_.pop(); - - ++processing_; - } - - task(); - - std::lock_guard lock{mutex_}; - --processing_; -} - -} // namespace NodeStore -} // namespace ripple diff --git a/src/xrpld/nodestore/detail/TaskQueue.h b/src/xrpld/nodestore/detail/TaskQueue.h deleted file mode 100644 index 8a743ff6016..00000000000 --- a/src/xrpld/nodestore/detail/TaskQueue.h +++ /dev/null @@ -1,64 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2019 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_NODESTORE_TASKQUEUE_H_INCLUDED -#define RIPPLE_NODESTORE_TASKQUEUE_H_INCLUDED - -#include - -#include -#include - -namespace ripple { -namespace NodeStore { - -class TaskQueue : private Workers::Callback -{ -public: - TaskQueue(); - - void - stop(); - - /** Adds a task to the queue - - @param task std::function with signature void() - */ - void - addTask(std::function task); - - /** Return the queue size - */ - [[nodiscard]] size_t - size() const; - -private: - mutable std::mutex mutex_; - Workers workers_; - std::queue> tasks_; - std::uint64_t processing_{0}; - - void - processTask(int instance) override; -}; - -} // namespace NodeStore -} // namespace ripple - -#endif diff --git a/src/xrpld/overlay/Overlay.h b/src/xrpld/overlay/Overlay.h index 1a3362d386f..b9550ba2ef4 100644 --- a/src/xrpld/overlay/Overlay.h +++ b/src/xrpld/overlay/Overlay.h @@ -219,15 +219,6 @@ class Overlay : public beast::PropertyStream::Source virtual std::uint64_t getPeerDisconnectCharges() const = 0; - /** Returns information reported to the crawl shard RPC command. - - @param includePublicKey include peer public keys in the result. - @param hops the maximum jumps the crawler will attempt. - The number of hops achieved is not guaranteed. - */ - virtual Json::Value - crawlShards(bool includePublicKey, std::uint32_t hops) = 0; - /** Returns the ID of the network this server is configured for, if any. The ID is just a numerical identifier, with the IDs 0, 1 and 2 used to diff --git a/src/xrpld/overlay/Peer.h b/src/xrpld/overlay/Peer.h index 81c04f7206c..82ed2c2481a 100644 --- a/src/xrpld/overlay/Peer.h +++ b/src/xrpld/overlay/Peer.h @@ -32,9 +32,6 @@ namespace Resource { class Charge; } -// Maximum hops to relay the peer shard info request -static constexpr std::uint32_t relayLimit = 3; - enum class ProtocolFeature { ValidatorListPropagation, ValidatorList2Propagation, diff --git a/src/xrpld/overlay/detail/Message.cpp b/src/xrpld/overlay/detail/Message.cpp index e19d718c73d..71917db0506 100644 --- a/src/xrpld/overlay/detail/Message.cpp +++ b/src/xrpld/overlay/detail/Message.cpp @@ -94,13 +94,9 @@ Message::compress() case protocol::mtSTATUS_CHANGE: case protocol::mtHAVE_SET: case protocol::mtVALIDATION: - case protocol::mtGET_PEER_SHARD_INFO: - case protocol::mtPEER_SHARD_INFO: case protocol::mtPROOF_PATH_REQ: case protocol::mtPROOF_PATH_RESPONSE: case protocol::mtREPLAY_DELTA_REQ: - case protocol::mtGET_PEER_SHARD_INFO_V2: - case protocol::mtPEER_SHARD_INFO_V2: case protocol::mtHAVE_TRANSACTIONS: break; } diff --git a/src/xrpld/overlay/detail/OverlayImpl.cpp b/src/xrpld/overlay/detail/OverlayImpl.cpp index 1978a2617aa..970873007c2 100644 --- a/src/xrpld/overlay/detail/OverlayImpl.cpp +++ b/src/xrpld/overlay/detail/OverlayImpl.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -679,103 +678,6 @@ OverlayImpl::reportTraffic( m_traffic.addCount(cat, isInbound, number); } -Json::Value -OverlayImpl::crawlShards(bool includePublicKey, std::uint32_t relays) -{ - using namespace std::chrono; - - Json::Value jv(Json::objectValue); - - // Add shard info from this server to json result - if (auto shardStore = app_.getShardStore()) - { - if (includePublicKey) - jv[jss::public_key] = - toBase58(TokenType::NodePublic, app_.nodeIdentity().first); - - auto const shardInfo{shardStore->getShardInfo()}; - if (!shardInfo->finalized().empty()) - jv[jss::complete_shards] = shardInfo->finalizedToString(); - if (!shardInfo->incomplete().empty()) - jv[jss::incomplete_shards] = shardInfo->incompleteToString(); - } - - if (relays == 0 || size() == 0) - return jv; - - { - protocol::TMGetPeerShardInfoV2 tmGPS; - tmGPS.set_relays(relays); - - // Wait if a request is in progress - std::unique_lock csLock{csMutex_}; - if (!csIDs_.empty()) - csCV_.wait(csLock); - - { - std::lock_guard lock{mutex_}; - for (auto const& id : ids_) - csIDs_.emplace(id.first); - } - - // Request peer shard info - foreach(send_always(std::make_shared( - tmGPS, protocol::mtGET_PEER_SHARD_INFO_V2))); - - if (csCV_.wait_for(csLock, seconds(60)) == std::cv_status::timeout) - { - csIDs_.clear(); - csCV_.notify_all(); - } - } - - // Combine shard info from peers - hash_map peerShardInfo; - for_each([&](std::shared_ptr&& peer) { - auto const psi{peer->getPeerShardInfos()}; - for (auto const& [publicKey, shardInfo] : psi) - { - auto const it{peerShardInfo.find(publicKey)}; - if (it == peerShardInfo.end()) - peerShardInfo.emplace(publicKey, shardInfo); - else if (shardInfo.msgTimestamp() > it->second.msgTimestamp()) - it->second = shardInfo; - } - }); - - // Add shard info to json result - if (!peerShardInfo.empty()) - { - auto& av = jv[jss::peers] = Json::Value(Json::arrayValue); - for (auto const& [publicKey, shardInfo] : peerShardInfo) - { - auto& pv{av.append(Json::Value(Json::objectValue))}; - if (includePublicKey) - { - pv[jss::public_key] = - toBase58(TokenType::NodePublic, publicKey); - } - - if (!shardInfo.finalized().empty()) - pv[jss::complete_shards] = shardInfo.finalizedToString(); - if (!shardInfo.incomplete().empty()) - pv[jss::incomplete_shards] = shardInfo.incompleteToString(); - } - } - - return jv; -} - -void -OverlayImpl::endOfPeerChain(std::uint32_t id) -{ - // Notify threads if all peers have received a reply from all peer chains - std::lock_guard csLock{csMutex_}; - csIDs_.erase(id); - if (csIDs_.empty()) - csCV_.notify_all(); -} - /** The number of active peers on the network Active peers are only those peers that have completed the handshake and are running the Ripple protocol. @@ -833,17 +735,6 @@ OverlayImpl::getOverlayInfo() if (minSeq != 0 || maxSeq != 0) pv[jss::complete_ledgers] = std::to_string(minSeq) + "-" + std::to_string(maxSeq); - - auto const peerShardInfos{sp->getPeerShardInfos()}; - auto const it{peerShardInfos.find(sp->getNodePublic())}; - if (it != peerShardInfos.end()) - { - auto const& shardInfo{it->second}; - if (!shardInfo.finalized().empty()) - pv[jss::complete_shards] = shardInfo.finalizedToString(); - if (!shardInfo.incomplete().empty()) - pv[jss::incomplete_shards] = shardInfo.incompleteToString(); - } }); return jv; diff --git a/src/xrpld/overlay/detail/OverlayImpl.h b/src/xrpld/overlay/detail/OverlayImpl.h index 1934a7c94c8..a50dfc5e905 100644 --- a/src/xrpld/overlay/detail/OverlayImpl.h +++ b/src/xrpld/overlay/detail/OverlayImpl.h @@ -119,12 +119,6 @@ class OverlayImpl : public Overlay, public reduce_relay::SquelchHandler std::atomic peerDisconnects_{0}; std::atomic peerDisconnectsCharges_{0}; - // 'cs' = crawl shards - std::mutex csMutex_; - std::condition_variable csCV_; - // Peer IDs expecting to receive a last link notification - std::set csIDs_; - reduce_relay::Slots slots_; // Transaction reduce-relay metrics @@ -392,16 +386,6 @@ class OverlayImpl : public Overlay, public reduce_relay::SquelchHandler return setup_.networkID; } - Json::Value - crawlShards(bool includePublicKey, std::uint32_t relays) override; - - /** Called when the reply from the last peer in a peer chain is received. - - @param id peer id that received the shard info. - */ - void - endOfPeerChain(std::uint32_t id); - /** Updates message count for validator/peer. Sends TMSquelch if the number * of messages for N peers reaches threshold T. A message is counted * if a peer receives the message for the first time and if diff --git a/src/xrpld/overlay/detail/PeerImp.cpp b/src/xrpld/overlay/detail/PeerImp.cpp index 96f793b8d80..86e336f850b 100644 --- a/src/xrpld/overlay/detail/PeerImp.cpp +++ b/src/xrpld/overlay/detail/PeerImp.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -521,17 +520,6 @@ PeerImp::hasLedger(uint256 const& hash, std::uint32_t seq) const recentLedgers_.end()) return true; } - - if (seq >= app_.getNodeStore().earliestLedgerSeq()) - { - std::lock_guard lock{shardInfoMutex_}; - auto const it{shardInfos_.find(publicKey_)}; - if (it != shardInfos_.end()) - { - auto const shardIndex{app_.getNodeStore().seqToShardIndex(seq)}; - return boost::icl::contains(it->second.finalized(), shardIndex); - } - } return false; } @@ -626,13 +614,6 @@ PeerImp::fail(std::string const& name, error_code ec) close(); } -hash_map const -PeerImp::getPeerShardInfos() const -{ - std::lock_guard l{shardInfoMutex_}; - return shardInfos_; -} - void PeerImp::gracefulClose() { @@ -878,11 +859,6 @@ PeerImp::doProtocolStart() if (auto m = overlay_.getManifestsMessage()) send(m); - // Request shard info from peer - protocol::TMGetPeerShardInfoV2 tmGPS; - tmGPS.set_relays(0); - send(std::make_shared(tmGPS, protocol::mtGET_PEER_SHARD_INFO_V2)); - setTimer(); } @@ -1175,294 +1151,6 @@ PeerImp::onMessage(std::shared_ptr const& m) app_.getFeeTrack().setClusterFee(clusterFee); } -void -PeerImp::onMessage(std::shared_ptr const& m) -{ - // DEPRECATED -} - -void -PeerImp::onMessage(std::shared_ptr const& m) -{ - // DEPRECATED -} - -void -PeerImp::onMessage(std::shared_ptr const& m) -{ - auto badData = [&](std::string msg) { - fee_ = Resource::feeBadData; - JLOG(p_journal_.warn()) << msg; - }; - - // Verify relays - if (m->relays() > relayLimit) - return badData("Invalid relays"); - - // Verify peer chain - // The peer chain should not contain this node's public key - // nor the public key of the sending peer - std::set pubKeyChain; - pubKeyChain.insert(app_.nodeIdentity().first); - pubKeyChain.insert(publicKey_); - - auto const peerChainSz{m->peerchain_size()}; - if (peerChainSz > 0) - { - if (peerChainSz > relayLimit) - return badData("Invalid peer chain size"); - - if (peerChainSz + m->relays() > relayLimit) - return badData("Invalid relays and peer chain size"); - - for (int i = 0; i < peerChainSz; ++i) - { - auto const slice{makeSlice(m->peerchain(i).publickey())}; - - // Verify peer public key - if (!publicKeyType(slice)) - return badData("Invalid peer public key"); - - // Verify peer public key is unique in the peer chain - if (!pubKeyChain.emplace(slice).second) - return badData("Invalid peer public key"); - } - } - - // Reply with shard info this node may have - if (auto shardStore = app_.getShardStore()) - { - auto reply{shardStore->getShardInfo()->makeMessage(app_)}; - if (peerChainSz > 0) - *(reply.mutable_peerchain()) = m->peerchain(); - send(std::make_shared(reply, protocol::mtPEER_SHARD_INFO_V2)); - } - - if (m->relays() == 0) - return; - - // Charge originating peer a fee for requesting relays - if (peerChainSz == 0) - fee_ = Resource::feeMediumBurdenPeer; - - // Add peer to the peer chain - m->add_peerchain()->set_publickey(publicKey_.data(), publicKey_.size()); - - // Relay the request to peers, exclude the peer chain - m->set_relays(m->relays() - 1); - overlay_.foreach(send_if_not( - std::make_shared(*m, protocol::mtGET_PEER_SHARD_INFO_V2), - [&](std::shared_ptr const& peer) { - return pubKeyChain.find(peer->getNodePublic()) != pubKeyChain.end(); - })); -} - -void -PeerImp::onMessage(std::shared_ptr const& m) -{ - // Find the earliest and latest shard indexes - auto const& db{app_.getNodeStore()}; - auto const earliestShardIndex{db.earliestShardIndex()}; - auto const latestShardIndex{[&]() -> std::optional { - auto const curLedgerSeq{app_.getLedgerMaster().getCurrentLedgerIndex()}; - if (curLedgerSeq >= db.earliestLedgerSeq()) - return db.seqToShardIndex(curLedgerSeq); - return std::nullopt; - }()}; - - auto badData = [&](std::string msg) { - fee_ = Resource::feeBadData; - JLOG(p_journal_.warn()) << msg; - }; - - // Used to create a digest and verify the message signature - Serializer s; - s.add32(HashPrefix::shardInfo); - - // Verify message creation time - NodeStore::ShardInfo shardInfo; - { - auto const timestamp{ - NetClock::time_point{std::chrono::seconds{m->timestamp()}}}; - auto const now{app_.timeKeeper().now()}; - if (timestamp > (now + 5s)) - return badData("Invalid timestamp"); - - // Check if stale - using namespace std::chrono_literals; - if (timestamp < (now - 5min)) - return badData("Stale timestamp"); - - s.add32(m->timestamp()); - shardInfo.setMsgTimestamp(timestamp); - } - - // Verify incomplete shards - auto const numIncomplete{m->incomplete_size()}; - if (numIncomplete > 0) - { - if (latestShardIndex && numIncomplete > *latestShardIndex) - return badData("Invalid number of incomplete shards"); - - // Verify each incomplete shard - for (int i = 0; i < numIncomplete; ++i) - { - auto const& incomplete{m->incomplete(i)}; - auto const shardIndex{incomplete.shardindex()}; - - // Verify shard index - if (shardIndex < earliestShardIndex || - (latestShardIndex && shardIndex > latestShardIndex)) - { - return badData("Invalid incomplete shard index"); - } - s.add32(shardIndex); - - // Verify state - auto const state{static_cast(incomplete.state())}; - switch (state) - { - // Incomplete states - case ShardState::acquire: - case ShardState::complete: - case ShardState::finalizing: - case ShardState::queued: - break; - - // case ShardState::finalized: - default: - return badData("Invalid incomplete shard state"); - } - s.add32(incomplete.state()); - - // Verify progress - std::uint32_t progress{0}; - if (incomplete.has_progress()) - { - progress = incomplete.progress(); - if (progress < 1 || progress > 100) - return badData("Invalid incomplete shard progress"); - s.add32(progress); - } - - // Verify each incomplete shard is unique - if (!shardInfo.update(shardIndex, state, progress)) - return badData("Invalid duplicate incomplete shards"); - } - } - - // Verify finalized shards - if (m->has_finalized()) - { - auto const& str{m->finalized()}; - if (str.empty()) - return badData("Invalid finalized shards"); - - if (!shardInfo.setFinalizedFromString(str)) - return badData("Invalid finalized shard indexes"); - - auto const& finalized{shardInfo.finalized()}; - auto const numFinalized{boost::icl::length(finalized)}; - if (numFinalized == 0 || - boost::icl::first(finalized) < earliestShardIndex || - (latestShardIndex && - boost::icl::last(finalized) > latestShardIndex)) - { - return badData("Invalid finalized shard indexes"); - } - - if (latestShardIndex && - (numFinalized + numIncomplete) > *latestShardIndex) - { - return badData("Invalid number of finalized and incomplete shards"); - } - - s.addRaw(str.data(), str.size()); - } - - // Verify public key - auto slice{makeSlice(m->publickey())}; - if (!publicKeyType(slice)) - return badData("Invalid public key"); - - // Verify peer public key isn't this nodes's public key - PublicKey const publicKey(slice); - if (publicKey == app_.nodeIdentity().first) - return badData("Invalid public key"); - - // Verify signature - if (!verify(publicKey, s.slice(), makeSlice(m->signature()), false)) - return badData("Invalid signature"); - - // Forward the message if a peer chain exists - auto const peerChainSz{m->peerchain_size()}; - if (peerChainSz > 0) - { - // Verify peer chain - if (peerChainSz > relayLimit) - return badData("Invalid peer chain size"); - - // The peer chain should not contain this node's public key - // nor the public key of the sending peer - std::set pubKeyChain; - pubKeyChain.insert(app_.nodeIdentity().first); - pubKeyChain.insert(publicKey_); - - for (int i = 0; i < peerChainSz; ++i) - { - // Verify peer public key - slice = makeSlice(m->peerchain(i).publickey()); - if (!publicKeyType(slice)) - return badData("Invalid peer public key"); - - // Verify peer public key is unique in the peer chain - if (!pubKeyChain.emplace(slice).second) - return badData("Invalid peer public key"); - } - - // If last peer in the chain is connected, relay the message - PublicKey const peerPubKey( - makeSlice(m->peerchain(peerChainSz - 1).publickey())); - if (auto peer = overlay_.findPeerByPublicKey(peerPubKey)) - { - m->mutable_peerchain()->RemoveLast(); - peer->send( - std::make_shared(*m, protocol::mtPEER_SHARD_INFO_V2)); - JLOG(p_journal_.trace()) - << "Relayed TMPeerShardInfoV2 from peer IP " - << remote_address_.address().to_string() << " to peer IP " - << peer->getRemoteAddress().to_string(); - } - else - { - // Peer is no longer available so the relay ends - JLOG(p_journal_.info()) << "Unable to relay peer shard info"; - } - } - - JLOG(p_journal_.trace()) - << "Consumed TMPeerShardInfoV2 originating from public key " - << toBase58(TokenType::NodePublic, publicKey) << " finalized shards[" - << ripple::to_string(shardInfo.finalized()) << "] incomplete shards[" - << (shardInfo.incomplete().empty() ? "empty" - : shardInfo.incompleteToString()) - << "]"; - - // Consume the message - { - std::lock_guard lock{shardInfoMutex_}; - auto const it{shardInfos_.find(publicKey_)}; - if (it == shardInfos_.end()) - shardInfos_.emplace(publicKey, std::move(shardInfo)); - else if (shardInfo.msgTimestamp() > it->second.msgTimestamp()) - it->second = std::move(shardInfo); - } - - // Notify overlay a reply was received from the last peer in this chain - if (peerChainSz == 0) - overlay_.endOfPeerChain(id_); -} - void PeerImp::onMessage(std::shared_ptr const& m) { @@ -1659,13 +1347,6 @@ PeerImp::onMessage(std::shared_ptr const& m) if (m->has_ledgerseq()) { auto const ledgerSeq{m->ledgerseq()}; - // Verifying the network's earliest ledger only pertains to shards. - if (app_.getShardStore() && - ledgerSeq < app_.getNodeStore().earliestLedgerSeq()) - { - return badData( - "Invalid ledger sequence " + std::to_string(ledgerSeq)); - } // Check if within a reasonable range using namespace std::chrono_literals; @@ -1835,14 +1516,6 @@ PeerImp::onMessage(std::shared_ptr const& m) } else { - // Verifying the network's earliest ledger only pertains to shards. - if (app_.getShardStore() && - ledgerSeq < app_.getNodeStore().earliestLedgerSeq()) - { - return badData( - "Invalid ledger sequence " + std::to_string(ledgerSeq)); - } - // Check if within a reasonable range using namespace std::chrono_literals; if (app_.getLedgerMaster().getValidatedLedgerAge() <= 10s && @@ -2705,14 +2378,6 @@ PeerImp::onMessage(std::shared_ptr const& m) // need to inject the NodeStore interfaces. std::uint32_t seq{obj.has_ledgerseq() ? obj.ledgerseq() : 0}; auto nodeObject{app_.getNodeStore().fetchNodeObject(hash, seq)}; - if (!nodeObject) - { - if (auto shardStore = app_.getShardStore()) - { - if (seq >= shardStore->earliestLedgerSeq()) - nodeObject = shardStore->fetchNodeObject(hash, seq); - } - } if (nodeObject) { protocol::TMIndexedObject& newObj = *reply.add_objects(); @@ -3312,44 +2977,28 @@ PeerImp::getLedger(std::shared_ptr const& m) ledger = app_.getLedgerMaster().getLedgerByHash(ledgerHash); if (!ledger) { - if (m->has_ledgerseq()) + JLOG(p_journal_.trace()) + << "getLedger: Don't have ledger with hash " << ledgerHash; + + if (m->has_querytype() && !m->has_requestcookie()) { - // Attempt to find ledger by sequence in the shard store - if (auto shards = app_.getShardStore()) + // Attempt to relay the request to a peer + if (auto const peer = getPeerWithLedger( + overlay_, + ledgerHash, + m->has_ledgerseq() ? m->ledgerseq() : 0, + this)) { - if (m->ledgerseq() >= shards->earliestLedgerSeq()) - { - ledger = - shards->fetchLedger(ledgerHash, m->ledgerseq()); - } + m->set_requestcookie(id()); + peer->send( + std::make_shared(*m, protocol::mtGET_LEDGER)); + JLOG(p_journal_.debug()) + << "getLedger: Request relayed to peer"; + return ledger; } - } - if (!ledger) - { JLOG(p_journal_.trace()) - << "getLedger: Don't have ledger with hash " << ledgerHash; - - if (m->has_querytype() && !m->has_requestcookie()) - { - // Attempt to relay the request to a peer - if (auto const peer = getPeerWithLedger( - overlay_, - ledgerHash, - m->has_ledgerseq() ? m->ledgerseq() : 0, - this)) - { - m->set_requestcookie(id()); - peer->send(std::make_shared( - *m, protocol::mtGET_LEDGER)); - JLOG(p_journal_.debug()) - << "getLedger: Request relayed to peer"; - return ledger; - } - - JLOG(p_journal_.trace()) - << "getLedger: Failed to find peer to relay request"; - } + << "getLedger: Failed to find peer to relay request"; } } } diff --git a/src/xrpld/overlay/detail/PeerImp.h b/src/xrpld/overlay/detail/PeerImp.h index 1c25d8089b8..9c76ddb4db8 100644 --- a/src/xrpld/overlay/detail/PeerImp.h +++ b/src/xrpld/overlay/detail/PeerImp.h @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -163,10 +162,6 @@ class PeerImp : public Peer, // been sent to or received from this peer. hash_map publisherListSequences_; - // Any known shard info from this peer and its sub peers - hash_map shardInfos_; - std::mutex mutable shardInfoMutex_; - Compressed compressionEnabled_ = Compressed::Off; // Queue of transactions' hashes that have not been @@ -415,10 +410,6 @@ class PeerImp : public Peer, void fail(std::string const& reason); - // Return any known shard info from this peer and its sub peers - [[nodiscard]] hash_map const - getPeerShardInfos() const; - bool compressionEnabled() const override { @@ -541,14 +532,6 @@ class PeerImp : public Peer, void onMessage(std::shared_ptr const& m); void - onMessage(std::shared_ptr const& m); - void - onMessage(std::shared_ptr const& m); - void - onMessage(std::shared_ptr const& m); - void - onMessage(std::shared_ptr const& m); - void onMessage(std::shared_ptr const& m); void onMessage(std::shared_ptr const& m); diff --git a/src/xrpld/overlay/detail/ProtocolMessage.h b/src/xrpld/overlay/detail/ProtocolMessage.h index b8c6a2c1cf2..8a7512afb31 100644 --- a/src/xrpld/overlay/detail/ProtocolMessage.h +++ b/src/xrpld/overlay/detail/ProtocolMessage.h @@ -88,10 +88,6 @@ protocolMessageName(int type) return "validator_list_collection"; case protocol::mtVALIDATION: return "validation"; - case protocol::mtGET_PEER_SHARD_INFO: - return "get_peer_shard_info"; - case protocol::mtPEER_SHARD_INFO: - return "peer_shard_info"; case protocol::mtGET_OBJECTS: return "get_objects"; case protocol::mtHAVE_TRANSACTIONS: @@ -108,10 +104,6 @@ protocolMessageName(int type) return "replay_delta_request"; case protocol::mtREPLAY_DELTA_RESPONSE: return "replay_delta_response"; - case protocol::mtGET_PEER_SHARD_INFO_V2: - return "get_peer_shard_info_v2"; - case protocol::mtPEER_SHARD_INFO_V2: - return "peer_shard_info_v2"; default: break; } @@ -436,14 +428,6 @@ invokeProtocolMessage( success = detail::invoke( *header, buffers, handler); break; - case protocol::mtGET_PEER_SHARD_INFO: - success = detail::invoke( - *header, buffers, handler); - break; - case protocol::mtPEER_SHARD_INFO: - success = detail::invoke( - *header, buffers, handler); - break; case protocol::mtVALIDATORLIST: success = detail::invoke( *header, buffers, handler); @@ -484,14 +468,6 @@ invokeProtocolMessage( success = detail::invoke( *header, buffers, handler); break; - case protocol::mtGET_PEER_SHARD_INFO_V2: - success = detail::invoke( - *header, buffers, handler); - break; - case protocol::mtPEER_SHARD_INFO_V2: - success = detail::invoke( - *header, buffers, handler); - break; default: handler.onMessageUnknown(header->message_type); success = true; diff --git a/src/xrpld/overlay/detail/TrafficCount.cpp b/src/xrpld/overlay/detail/TrafficCount.cpp index f3e9c137fba..c64a033e3e3 100644 --- a/src/xrpld/overlay/detail/TrafficCount.cpp +++ b/src/xrpld/overlay/detail/TrafficCount.cpp @@ -39,12 +39,6 @@ TrafficCount::categorize( if (type == protocol::mtENDPOINTS) return TrafficCount::category::overlay; - if ((type == protocol::mtGET_PEER_SHARD_INFO) || - (type == protocol::mtPEER_SHARD_INFO) || - (type == protocol::mtGET_PEER_SHARD_INFO_V2) || - (type == protocol::mtPEER_SHARD_INFO_V2)) - return TrafficCount::category::shards; - if (type == protocol::mtTRANSACTION) return TrafficCount::category::transaction; diff --git a/src/xrpld/overlay/detail/TrafficCount.h b/src/xrpld/overlay/detail/TrafficCount.h index acd96695257..7dd5cbba901 100644 --- a/src/xrpld/overlay/detail/TrafficCount.h +++ b/src/xrpld/overlay/detail/TrafficCount.h @@ -74,7 +74,6 @@ class TrafficCount proposal, validation, validatorlist, - shards, // shard-related traffic // TMHaveSet message: get_set, // transaction sets we try to get @@ -208,7 +207,6 @@ class TrafficCount {"proposals"}, // category::proposal {"validations"}, // category::validation {"validator_lists"}, // category::validatorlist - {"shards"}, // category::shards {"set_get"}, // category::get_set {"set_share"}, // category::share_set {"ledger_data_Transaction_Set_candidate_get"}, // category::ld_tsc_get diff --git a/src/xrpld/perflog/detail/PerfLogImp.cpp b/src/xrpld/perflog/detail/PerfLogImp.cpp index b9691e05c23..a4773b33e10 100644 --- a/src/xrpld/perflog/detail/PerfLogImp.cpp +++ b/src/xrpld/perflog/detail/PerfLogImp.cpp @@ -20,7 +20,6 @@ #include #include -#include #include #include #include @@ -299,10 +298,7 @@ PerfLogImp::report() report[jss::hostid] = hostname_; report[jss::counters] = counters_.countersJson(); report[jss::nodestore] = Json::objectValue; - if (app_.getShardStore()) - app_.getShardStore()->getCountsJson(report[jss::nodestore]); - else - app_.getNodeStore().getCountsJson(report[jss::nodestore]); + app_.getNodeStore().getCountsJson(report[jss::nodestore]); report[jss::current_activities] = counters_.currentJson(); app_.getOPs().stateAccounting(report); diff --git a/src/xrpld/rpc/ShardArchiveHandler.h b/src/xrpld/rpc/ShardArchiveHandler.h deleted file mode 100644 index 3a407b37976..00000000000 --- a/src/xrpld/rpc/ShardArchiveHandler.h +++ /dev/null @@ -1,176 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 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_RPC_SHARDARCHIVEHANDLER_H_INCLUDED -#define RIPPLE_RPC_SHARDARCHIVEHANDLER_H_INCLUDED - -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace ripple { -#ifdef ENABLE_TESTS -namespace test { -class ShardArchiveHandler_test; -} -#endif // ENABLE_TESTS -namespace RPC { - -/** Handles the download and import of one or more shard archives. */ -class ShardArchiveHandler -{ -public: - using TimerOpCounter = - ClosureCounter; -#ifdef ENABLE_TESTS - friend class test::ShardArchiveHandler_test; -#endif // ENABLE_TESTS - - static boost::filesystem::path - getDownloadDirectory(Config const& config); - - static std::unique_ptr - makeShardArchiveHandler(Application& app); - - // Create a ShardArchiveHandler only if - // the state database is present, indicating - // that recovery is needed. - static std::unique_ptr - tryMakeRecoveryHandler(Application& app); - - explicit ShardArchiveHandler(Application& app); - - virtual ~ShardArchiveHandler() = default; - - [[nodiscard]] bool - init(); - - bool - add(std::uint32_t shardIndex, std::pair&& url); - - /** Starts downloading and importing archives. */ - bool - start(); - - void - stop(); - - void - release(); - -private: - ShardArchiveHandler() = delete; - ShardArchiveHandler(ShardArchiveHandler const&) = delete; - ShardArchiveHandler& - operator=(ShardArchiveHandler&&) = delete; - ShardArchiveHandler& - operator=(ShardArchiveHandler const&) = delete; - - [[nodiscard]] bool - initFromDB(std::lock_guard const&); - - /** Add an archive to be downloaded and imported. - @param shardIndex the index of the shard to be imported. - @param url the location of the archive. - @return `true` if successfully added. - @note Returns false if called while downloading. - */ - bool - add(std::uint32_t shardIndex, - parsedURL&& url, - std::lock_guard const&); - - // Begins the download and import of the next archive. - bool - next(std::lock_guard const& l); - - // Callback used by the downloader to notify completion of a download. - void - complete(boost::filesystem::path dstPath); - - // Extract a downloaded archive and import it into the shard store. - void - process(boost::filesystem::path const& dstPath); - - // Remove the archive being processed. - void - remove(std::lock_guard const&); - - void - doRelease(std::lock_guard const&); - - bool - onClosureFailed( - std::string const& errorMsg, - std::lock_guard const& lock); - - bool - removeAndProceed(std::lock_guard const& lock); - - ///////////////////////////////////////////////// - // m_ is used to protect access to downloader_, - // archives_, process_ and to protect setting and - // destroying sqlDB_. - ///////////////////////////////////////////////// - std::mutex mutable m_; - std::atomic_bool stopping_{false}; - std::shared_ptr downloader_; - std::map archives_; - bool process_; - std::unique_ptr sqlDB_; - ///////////////////////////////////////////////// - - Application& app_; - beast::Journal const j_; - boost::filesystem::path const downloadDir_; - boost::asio::basic_waitable_timer timer_; - JobCounter jobCounter_; - TimerOpCounter timerCounter_; - ShardVerificationScheduler verificationScheduler_; -}; - -//////////////////////////////////////////////////////////////////// -// The RecoveryHandler is an empty class that is constructed by -// the application when the ShardArchiveHandler's state database -// is present at application start, indicating that the handler -// needs to perform recovery. However, if recovery isn't needed -// at application start, and the user subsequently submits a request -// to download shards, we construct a ShardArchiveHandler rather -// than a RecoveryHandler to process the request. With this approach, -// type verification can be employed to determine whether the -// ShardArchiveHandler was constructed in recovery mode by the -// application, or as a response to a user submitting a request to -// download shards. -//////////////////////////////////////////////////////////////////// -class RecoveryHandler : public ShardArchiveHandler -{ -public: - explicit RecoveryHandler(Application& app); -}; - -} // namespace RPC -} // namespace ripple - -#endif diff --git a/src/xrpld/rpc/ShardVerificationScheduler.h b/src/xrpld/rpc/ShardVerificationScheduler.h deleted file mode 100644 index bc561381b3e..00000000000 --- a/src/xrpld/rpc/ShardVerificationScheduler.h +++ /dev/null @@ -1,84 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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_RPC_SHARDVERIFICATIONSCHEDULER_H_INCLUDED -#define RIPPLE_RPC_SHARDVERIFICATIONSCHEDULER_H_INCLUDED - -#include -#include - -namespace ripple { -namespace RPC { - -class ShardVerificationScheduler -{ -public: - // This is the signature of the function that the client - // wants to have invoked upon timer expiration. The function - // should check the error code 'ec' and abort the function - // if the timer was cancelled: - // (ec == boost::asio::error::operation_aborted). - // In the body of the function, the client should perform - // the necessary verification. - using retryFunction = - std::function; - - ShardVerificationScheduler() = default; - - ShardVerificationScheduler( - std::chrono::seconds retryInterval, - std::uint32_t maxAttempts); - - bool - retry(Application& app, bool shouldHaveHash, retryFunction f); - - void - reset(); - -private: - using waitable_timer = - boost::asio::basic_waitable_timer; - - ///////////////////////////////////////////////////// - // NOTE: retryInterval_ and maxAttempts_ were chosen - // semi-arbitrarily and experimenting with other - // values might prove useful. - ///////////////////////////////////////////////////// - - static constexpr std::chrono::seconds defaultRetryInterval_{60}; - - static constexpr std::uint32_t defaultmaxAttempts_{5}; - - // The number of seconds to wait before retrying - // retrieval of a shard's last ledger hash - const std::chrono::seconds retryInterval_{defaultRetryInterval_}; - - // Maximum attempts to retrieve a shard's last ledger hash - const std::uint32_t maxAttempts_{defaultmaxAttempts_}; - - std::unique_ptr timer_; - - // Number of attempts to retrieve a shard's last ledger hash - std::uint32_t numAttempts_{0}; -}; - -} // namespace RPC -} // namespace ripple - -#endif // RIPPLE_RPC_SHARDVERIFICATIONSCHEDULER_H_INCLUDED diff --git a/src/xrpld/rpc/detail/Handler.cpp b/src/xrpld/rpc/detail/Handler.cpp index 4bac4610229..d4a3fda380f 100644 --- a/src/xrpld/rpc/detail/Handler.cpp +++ b/src/xrpld/rpc/detail/Handler.cpp @@ -99,12 +99,10 @@ Handler const handlerArray[]{ {"channel_verify", byRef(&doChannelVerify), Role::USER, NO_CONDITION}, {"connect", byRef(&doConnect), Role::ADMIN, NO_CONDITION}, {"consensus_info", byRef(&doConsensusInfo), Role::ADMIN, NO_CONDITION}, - {"crawl_shards", byRef(&doCrawlShards), Role::ADMIN, NO_CONDITION}, {"deposit_authorized", byRef(&doDepositAuthorized), Role::USER, NO_CONDITION}, - {"download_shard", byRef(&doDownloadShard), Role::ADMIN, NO_CONDITION}, {"feature", byRef(&doFeature), Role::USER, NO_CONDITION}, {"fee", byRef(&doFee), Role::USER, NEEDS_CURRENT_LEDGER}, {"fetch_info", byRef(&doFetchInfo), Role::ADMIN, NO_CONDITION}, @@ -140,7 +138,6 @@ Handler const handlerArray[]{ {"manifest", byRef(&doManifest), Role::USER, NO_CONDITION}, {"nft_buy_offers", byRef(&doNFTBuyOffers), Role::USER, NO_CONDITION}, {"nft_sell_offers", byRef(&doNFTSellOffers), Role::USER, NO_CONDITION}, - {"node_to_shard", byRef(&doNodeToShard), Role::ADMIN, NO_CONDITION}, {"noripple_check", byRef(&doNoRippleCheck), Role::USER, NO_CONDITION}, {"owner_info", byRef(&doOwnerInfo), Role::USER, NEEDS_CURRENT_LEDGER}, {"peers", byRef(&doPeers), Role::ADMIN, NO_CONDITION}, diff --git a/src/xrpld/rpc/detail/ShardArchiveHandler.cpp b/src/xrpld/rpc/detail/ShardArchiveHandler.cpp deleted file mode 100644 index 1ab8f7767b5..00000000000 --- a/src/xrpld/rpc/detail/ShardArchiveHandler.cpp +++ /dev/null @@ -1,585 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2014 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 -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace ripple { -namespace RPC { - -using namespace boost::filesystem; -using namespace std::chrono_literals; - -boost::filesystem::path -ShardArchiveHandler::getDownloadDirectory(Config const& config) -{ - return boost::filesystem::path{ - get(config.section(ConfigSection::shardDatabase()), - "download_path", - get(config.section(ConfigSection::shardDatabase()), - "path", - ""))} / - "download"; -} - -std::unique_ptr -ShardArchiveHandler::makeShardArchiveHandler(Application& app) -{ - return std::make_unique(app); -} - -std::unique_ptr -ShardArchiveHandler::tryMakeRecoveryHandler(Application& app) -{ - auto const downloadDir(getDownloadDirectory(app.config())); - - // Create the handler iff the database - // is present. - if (exists(downloadDir / stateDBName) && - is_regular_file(downloadDir / stateDBName)) - { - return std::make_unique(app); - } - - return nullptr; -} - -ShardArchiveHandler::ShardArchiveHandler(Application& app) - : process_(false) - , app_(app) - , j_(app.journal("ShardArchiveHandler")) - , downloadDir_(getDownloadDirectory(app.config())) - , timer_(app_.getIOService()) - , verificationScheduler_( - std::chrono::seconds(get( - app.config().section(ConfigSection::shardDatabase()), - "shard_verification_retry_interval")), - - get( - app.config().section(ConfigSection::shardDatabase()), - "shard_verification_max_attempts")) -{ - assert(app_.getShardStore()); -} - -bool -ShardArchiveHandler::init() -{ - std::lock_guard lock(m_); - - if (process_ || downloader_ != nullptr || sqlDB_ != nullptr) - { - JLOG(j_.warn()) << "Archives already being processed"; - return false; - } - - // Initialize from pre-existing database - if (exists(downloadDir_ / stateDBName) && - is_regular_file(downloadDir_ / stateDBName)) - { - downloader_ = - make_DatabaseDownloader(app_.getIOService(), app_.config(), j_); - - return initFromDB(lock); - } - - // Fresh initialization - else - { - try - { - create_directories(downloadDir_); - - sqlDB_ = makeArchiveDB(downloadDir_, stateDBName); - } - catch (std::exception const& e) - { - JLOG(j_.error()) - << "exception: " << e.what() << " in function: " << __func__; - - return false; - } - } - - return true; -} - -bool -ShardArchiveHandler::initFromDB(std::lock_guard const& lock) -{ - try - { - using namespace boost::filesystem; - - assert( - exists(downloadDir_ / stateDBName) && - is_regular_file(downloadDir_ / stateDBName)); - - sqlDB_ = makeArchiveDB(downloadDir_, stateDBName); - - readArchiveDB(*sqlDB_, [&](std::string const& url_, int state) { - parsedURL url; - - if (!parseUrl(url, url_)) - { - JLOG(j_.error()) << "Failed to parse url: " << url_; - - return; - } - - add(state, std::move(url), lock); - }); - - // Failed to load anything - // from the state database. - if (archives_.empty()) - { - release(); - return false; - } - } - catch (std::exception const& e) - { - JLOG(j_.error()) << "exception: " << e.what() - << " in function: " << __func__; - - return false; - } - - return true; -} - -void -ShardArchiveHandler::stop() -{ - stopping_ = true; - { - std::lock_guard lock(m_); - - if (downloader_) - { - downloader_->stop(); - downloader_.reset(); - } - - timer_.cancel(); - } - - jobCounter_.join( - "ShardArchiveHandler", std::chrono::milliseconds(2000), j_); - - timerCounter_.join( - "ShardArchiveHandler", std::chrono::milliseconds(2000), j_); -} - -bool -ShardArchiveHandler::add( - std::uint32_t shardIndex, - std::pair&& url) -{ - std::lock_guard lock(m_); - - if (!add(shardIndex, std::forward(url.first), lock)) - return false; - - insertArchiveDB(*sqlDB_, shardIndex, url.second); - - return true; -} - -bool -ShardArchiveHandler::add( - std::uint32_t shardIndex, - parsedURL&& url, - std::lock_guard const&) -{ - if (process_) - { - JLOG(j_.error()) << "Download and import already in progress"; - return false; - } - - auto const it{archives_.find(shardIndex)}; - if (it != archives_.end()) - return url == it->second; - - archives_.emplace(shardIndex, std::move(url)); - - return true; -} - -bool -ShardArchiveHandler::start() -{ - std::lock_guard lock(m_); - if (!app_.getShardStore()) - { - JLOG(j_.error()) << "No shard store available"; - return false; - } - if (process_) - { - JLOG(j_.warn()) << "Archives already being processed"; - return false; - } - if (archives_.empty()) - { - JLOG(j_.warn()) << "No archives to process"; - return false; - } - - std::vector shardIndexes(archives_.size()); - std::transform( - archives_.begin(), - archives_.end(), - shardIndexes.begin(), - [](auto const& entry) { return entry.first; }); - - if (!app_.getShardStore()->prepareShards(shardIndexes)) - return false; - - try - { - // Create temp root download directory - create_directories(downloadDir_); - - if (!downloader_) - { - // will throw if can't initialize ssl context - downloader_ = - make_DatabaseDownloader(app_.getIOService(), app_.config(), j_); - } - } - catch (std::exception const& e) - { - JLOG(j_.error()) << "exception: " << e.what(); - return false; - } - - process_ = true; - return next(lock); -} - -void -ShardArchiveHandler::release() -{ - std::lock_guard lock(m_); - doRelease(lock); -} - -bool -ShardArchiveHandler::next(std::lock_guard const& l) -{ - if (stopping_) - return false; - - if (archives_.empty()) - { - doRelease(l); - return false; - } - - auto const shardIndex{archives_.begin()->first}; - - // We use the sequence of the last validated ledger - // to determine whether or not we have stored a ledger - // that comes after the last ledger in this shard. A - // later ledger must be present in order to reliably - // retrieve the hash of the shard's last ledger. - std::optional expectedHash; - bool shouldHaveHash = false; - if (auto const seq = app_.getShardStore()->lastLedgerSeq(shardIndex); - (shouldHaveHash = app_.getLedgerMaster().getValidLedgerIndex() > seq)) - { - expectedHash = app_.getLedgerMaster().walkHashBySeq( - seq, InboundLedger::Reason::GENERIC); - } - - if (!expectedHash) - { - auto wrapper = - timerCounter_.wrap([this](boost::system::error_code const& ec) { - if (ec != boost::asio::error::operation_aborted) - { - std::lock_guard lock(m_); - this->next(lock); - } - }); - - if (!wrapper) - return onClosureFailed( - "failed to wrap closure for last ledger confirmation timer", l); - - if (!verificationScheduler_.retry(app_, shouldHaveHash, *wrapper)) - { - JLOG(j_.error()) << "failed to find last ledger hash for shard " - << shardIndex << ", maximum attempts reached"; - - return removeAndProceed(l); - } - - return true; - } - - // Create a temp archive directory at the root - auto const dstDir{downloadDir_ / std::to_string(shardIndex)}; - try - { - create_directory(dstDir); - } - catch (std::exception const& e) - { - JLOG(j_.error()) << "exception: " << e.what(); - return removeAndProceed(l); - } - - // Download the archive. Process in another thread - // to prevent holding up the lock if the downloader - // sleeps. - auto const& url{archives_.begin()->second}; - auto wrapper = jobCounter_.wrap([this, url, dstDir]() { - auto const ssl = (url.scheme == "https"); - auto const defaultPort = ssl ? 443 : 80; - - if (!downloader_->download( - url.domain, - std::to_string(url.port.value_or(defaultPort)), - url.path, - 11, - dstDir / "archive.tar.lz4", - [this](path dstPath) { complete(dstPath); }, - ssl)) - { - std::lock_guard l(m_); - removeAndProceed(l); - } - }); - - if (!wrapper) - return onClosureFailed( - "failed to wrap closure for starting download", l); - - app_.getJobQueue().addJob(jtCLIENT_SHARD, "ShardArchiveHandler", *wrapper); - - return true; -} - -void -ShardArchiveHandler::complete(path dstPath) -{ - if (stopping_) - return; - - { - std::lock_guard lock(m_); - try - { - if (!is_regular_file(dstPath)) - { - auto ar{archives_.begin()}; - JLOG(j_.error()) - << "Downloading shard id " << ar->first << " from URL " - << ar->second.domain << ar->second.path; - removeAndProceed(lock); - return; - } - } - catch (std::exception const& e) - { - JLOG(j_.error()) << "exception: " << e.what(); - removeAndProceed(lock); - return; - } - } - - // Make lambdas mutable captured vars can be moved from - auto wrapper = - jobCounter_.wrap([=, this, dstPath = std::move(dstPath)]() mutable { - if (stopping_) - return; - - // If not synced then defer and retry - auto const mode{app_.getOPs().getOperatingMode()}; - if (mode != OperatingMode::FULL) - { - std::lock_guard lock(m_); - timer_.expires_from_now(static_cast( - (static_cast(OperatingMode::FULL) - - static_cast(mode)) * - 10)); - - auto wrapper = timerCounter_.wrap( - [=, this, dstPath = std::move(dstPath)]( - boost::system::error_code const& ec) mutable { - if (ec != boost::asio::error::operation_aborted) - complete(std::move(dstPath)); - }); - - if (!wrapper) - onClosureFailed( - "failed to wrap closure for operating mode timer", - lock); - else - timer_.async_wait(*wrapper); - } - else - { - process(dstPath); - std::lock_guard lock(m_); - removeAndProceed(lock); - } - }); - - if (!wrapper) - { - if (stopping_) - return; - - JLOG(j_.error()) << "failed to wrap closure for process()"; - - std::lock_guard lock(m_); - removeAndProceed(lock); - } - - // Process in another thread to not hold up the IO service - app_.getJobQueue().addJob(jtCLIENT_SHARD, "ShardArchiveHandler", *wrapper); -} - -void -ShardArchiveHandler::process(path const& dstPath) -{ - std::uint32_t shardIndex; - { - std::lock_guard lock(m_); - shardIndex = archives_.begin()->first; - } - - auto const shardDir{dstPath.parent_path() / std::to_string(shardIndex)}; - try - { - // Extract the downloaded archive - extractTarLz4(dstPath, dstPath.parent_path()); - - // The extracted root directory name must match the shard index - if (!is_directory(shardDir)) - { - JLOG(j_.error()) << "Shard " << shardIndex - << " mismatches archive shard directory"; - return; - } - } - catch (std::exception const& e) - { - JLOG(j_.error()) << "exception: " << e.what(); - return; - } - - // Import the shard into the shard store - if (!app_.getShardStore()->importShard(shardIndex, shardDir)) - { - JLOG(j_.error()) << "Importing shard " << shardIndex; - return; - } - - JLOG(j_.debug()) << "Shard " << shardIndex << " downloaded and imported"; -} - -void -ShardArchiveHandler::remove(std::lock_guard const&) -{ - verificationScheduler_.reset(); - - auto const shardIndex{archives_.begin()->first}; - app_.getShardStore()->removePreShard(shardIndex); - archives_.erase(shardIndex); - - deleteFromArchiveDB(*sqlDB_, shardIndex); - - auto const dstDir{downloadDir_ / std::to_string(shardIndex)}; - try - { - remove_all(dstDir); - } - catch (std::exception const& e) - { - JLOG(j_.error()) << "exception: " << e.what(); - } -} - -void -ShardArchiveHandler::doRelease(std::lock_guard const&) -{ - timer_.cancel(); - for (auto const& ar : archives_) - app_.getShardStore()->removePreShard(ar.first); - archives_.clear(); - - dropArchiveDB(*sqlDB_); - - sqlDB_.reset(); - - // Remove temp root download directory - try - { - remove_all(downloadDir_); - } - catch (std::exception const& e) - { - JLOG(j_.error()) << "exception: " << e.what() - << " in function: " << __func__; - } - - downloader_.reset(); - process_ = false; -} - -bool -ShardArchiveHandler::onClosureFailed( - std::string const& errorMsg, - std::lock_guard const& lock) -{ - if (stopping_) - return false; - - JLOG(j_.error()) << errorMsg; - - return removeAndProceed(lock); -} - -bool -ShardArchiveHandler::removeAndProceed(std::lock_guard const& lock) -{ - remove(lock); - return next(lock); -} - -RecoveryHandler::RecoveryHandler(Application& app) : ShardArchiveHandler(app) -{ -} - -} // namespace RPC -} // namespace ripple diff --git a/src/xrpld/rpc/detail/ShardVerificationScheduler.cpp b/src/xrpld/rpc/detail/ShardVerificationScheduler.cpp deleted file mode 100644 index f571e8b29cd..00000000000 --- a/src/xrpld/rpc/detail/ShardVerificationScheduler.cpp +++ /dev/null @@ -1,68 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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 -#include - -namespace ripple { -namespace RPC { - -ShardVerificationScheduler::ShardVerificationScheduler( - std::chrono::seconds retryInterval, - std::uint32_t maxAttempts) - : retryInterval_( - (retryInterval == std::chrono::seconds(0) ? defaultRetryInterval_ - : retryInterval)) - , maxAttempts_(maxAttempts == 0 ? defaultmaxAttempts_ : maxAttempts) -{ -} - -bool -ShardVerificationScheduler::retry( - Application& app, - bool shouldHaveHash, - retryFunction f) -{ - if (numAttempts_ >= maxAttempts_) - return false; - - // Retry attempts only count when we - // have a validated ledger with a - // sequence later than the shard's - // last ledger. - if (shouldHaveHash) - ++numAttempts_; - - if (!timer_) - timer_ = std::make_unique(app.getIOService()); - - timer_->expires_from_now(retryInterval_); - timer_->async_wait(f); - - return true; -} - -void -ShardVerificationScheduler::reset() -{ - numAttempts_ = 0; -} - -} // namespace RPC -} // namespace ripple diff --git a/src/xrpld/rpc/handlers/CrawlShards.cpp b/src/xrpld/rpc/handlers/CrawlShards.cpp deleted file mode 100644 index f586d750439..00000000000 --- a/src/xrpld/rpc/handlers/CrawlShards.cpp +++ /dev/null @@ -1,73 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2018 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 -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { - -/** RPC command that reports stored shards by nodes. - { - // Determines if the result includes node public key. - // optional, default is false - public_key: - - // The maximum number of peer hops to attempt. - // optional, default is zero, maximum is 3 - limit: - } -*/ -Json::Value -doCrawlShards(RPC::JsonContext& context) -{ - if (context.app.config().reporting()) - return rpcError(rpcREPORTING_UNSUPPORTED); - - if (context.role != Role::ADMIN) - return rpcError(rpcNO_PERMISSION); - - std::uint32_t relays{0}; - if (auto const& jv = context.params[jss::limit]) - { - if (!(jv.isUInt() || (jv.isInt() && jv.asInt() >= 0))) - return RPC::expected_field_error(jss::limit, "unsigned integer"); - relays = std::min(jv.asUInt(), relayLimit); - context.loadType = Resource::feeHighBurdenRPC; - } - else - context.loadType = Resource::feeMediumBurdenRPC; - - // Collect shard info from server and peers - bool const includePublicKey{ - context.params.isMember(jss::public_key) && - context.params[jss::public_key].asBool()}; - Json::Value jvResult{ - context.app.overlay().crawlShards(includePublicKey, relays)}; - - return jvResult; -} - -} // namespace ripple diff --git a/src/xrpld/rpc/handlers/DownloadShard.cpp b/src/xrpld/rpc/handlers/DownloadShard.cpp deleted file mode 100644 index 1ec12e0fa66..00000000000 --- a/src/xrpld/rpc/handlers/DownloadShard.cpp +++ /dev/null @@ -1,176 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012-2014 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace ripple { - -/** RPC command that downloads and import shard archives. - { - shards: [{index: , url: }] - } - - example: - { - "command": "download_shard", - "shards": [ - {"index": 1, "url": "https://domain.com/1.tar.lz4"}, - {"index": 5, "url": "https://domain.com/5.tar.lz4"} - ] - } -*/ -Json::Value -doDownloadShard(RPC::JsonContext& context) -{ - if (context.app.config().reporting()) - return rpcError(rpcREPORTING_UNSUPPORTED); - - if (context.role != Role::ADMIN) - return rpcError(rpcNO_PERMISSION); - - // The shard store must be configured - auto shardStore{context.app.getShardStore()}; - if (!shardStore) - return rpcError(rpcNOT_ENABLED); - - // Return status update if already downloading - auto preShards{shardStore->getPreShards()}; - if (!preShards.empty()) - { - std::string s{"Download already in progress. Shard"}; - if (!std::all_of(preShards.begin(), preShards.end(), ::isdigit)) - s += "s"; - return RPC::makeObjectValue(s + " " + preShards); - } - - if (!context.params.isMember(jss::shards)) - return RPC::missing_field_error(jss::shards); - if (!context.params[jss::shards].isArray() || - context.params[jss::shards].size() == 0) - { - return RPC::expected_field_error(std::string(jss::shards), "an array"); - } - - // Validate shards - static const std::string ext{".tar.lz4"}; - std::map> archives; - for (auto& it : context.params[jss::shards]) - { - // Validate the index - if (!it.isMember(jss::index)) - return RPC::missing_field_error(jss::index); - auto& jv{it[jss::index]}; - if (!(jv.isUInt() || (jv.isInt() && jv.asInt() >= 0))) - { - return RPC::expected_field_error( - std::string(jss::index), "an unsigned integer"); - } - - // Validate the URL - if (!it.isMember(jss::url)) - return RPC::missing_field_error(jss::url); - parsedURL url; - auto unparsedURL = it[jss::url].asString(); - if (!parseUrl(url, unparsedURL) || url.domain.empty() || - url.path.empty()) - { - return RPC::invalid_field_error(jss::url); - } - if (url.scheme != "https" && url.scheme != "http") - return RPC::expected_field_error( - std::string(jss::url), "HTTPS or HTTP"); - - // URL must point to an lz4 compressed tar archive '.tar.lz4' - auto archiveName{url.path.substr(url.path.find_last_of("/\\") + 1)}; - if (archiveName.empty() || archiveName.size() <= ext.size()) - { - return RPC::make_param_error( - "Invalid field '" + std::string(jss::url) + - "', invalid archive name"); - } - if (!boost::iends_with(archiveName, ext)) - { - return RPC::make_param_error( - "Invalid field '" + std::string(jss::url) + - "', invalid archive extension"); - } - - // Check for duplicate indexes - if (!archives - .emplace( - jv.asUInt(), std::make_pair(std::move(url), unparsedURL)) - .second) - { - return RPC::make_param_error( - "Invalid field '" + std::string(jss::index) + - "', duplicate shard ids."); - } - } - - RPC::ShardArchiveHandler* handler = nullptr; - - try - { - handler = context.app.getShardArchiveHandler(); - - if (!handler) - return RPC::make_error( - rpcINTERNAL, "Failed to create ShardArchiveHandler."); - } - catch (std::exception const& e) - { - return RPC::make_error( - rpcINTERNAL, std::string("Failed to start download: ") + e.what()); - } - - for (auto& [index, url] : archives) - { - if (!handler->add(index, std::move(url))) - { - return RPC::make_param_error( - "Invalid field '" + std::string(jss::index) + "', shard id " + - std::to_string(index) + " exists or being acquired"); - } - } - - // Begin downloading. - if (!handler->start()) - { - handler->release(); - return rpcError(rpcINTERNAL); - } - - std::string s{"Downloading shard"}; - preShards = shardStore->getPreShards(); - if (!std::all_of(preShards.begin(), preShards.end(), ::isdigit)) - s += "s"; - return RPC::makeObjectValue(s + " " + preShards); -} - -} // namespace ripple diff --git a/src/xrpld/rpc/handlers/GetCounts.cpp b/src/xrpld/rpc/handlers/GetCounts.cpp index 0a2327e117a..035d698a5d4 100644 --- a/src/xrpld/rpc/handlers/GetCounts.cpp +++ b/src/xrpld/rpc/handlers/GetCounts.cpp @@ -25,9 +25,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -113,11 +111,11 @@ getCountsJson(Application& app, int minObjectCount) ret[jss::AL_hit_rate] = app.getAcceptedLedgerCache().getHitRate(); ret[jss::fullbelow_size] = - static_cast(app.getNodeFamily().getFullBelowCache(0)->size()); + static_cast(app.getNodeFamily().getFullBelowCache()->size()); ret[jss::treenode_cache_size] = - app.getNodeFamily().getTreeNodeCache(0)->getCacheSize(); + app.getNodeFamily().getTreeNodeCache()->getCacheSize(); ret[jss::treenode_track_size] = - app.getNodeFamily().getTreeNodeCache(0)->getTrackSize(); + app.getNodeFamily().getTreeNodeCache()->getTrackSize(); std::string uptime; auto s = UptimeClock::now(); @@ -129,27 +127,7 @@ getCountsJson(Application& app, int minObjectCount) textTime(uptime, s, "second", 1s); ret[jss::uptime] = uptime; - if (auto shardStore = app.getShardStore()) - { - auto shardFamily{dynamic_cast(app.getShardFamily())}; - auto const [cacheSz, trackSz] = shardFamily->getTreeNodeCacheSize(); - Json::Value& jv = (ret[jss::shards] = Json::objectValue); - - jv[jss::fullbelow_size] = shardFamily->getFullBelowCacheSize(); - jv[jss::treenode_cache_size] = cacheSz; - jv[jss::treenode_track_size] = trackSz; - ret[jss::write_load] = shardStore->getWriteLoad(); - jv[jss::node_writes] = std::to_string(shardStore->getStoreCount()); - jv[jss::node_reads_total] = shardStore->getFetchTotalCount(); - jv[jss::node_reads_hit] = shardStore->getFetchHitCount(); - jv[jss::node_written_bytes] = - std::to_string(shardStore->getStoreSize()); - jv[jss::node_read_bytes] = shardStore->getFetchSize(); - } - else - { - app.getNodeStore().getCountsJson(ret); - } + app.getNodeStore().getCountsJson(ret); return ret; } diff --git a/src/xrpld/rpc/handlers/Handlers.h b/src/xrpld/rpc/handlers/Handlers.h index 917ad38a741..0085f51465a 100644 --- a/src/xrpld/rpc/handlers/Handlers.h +++ b/src/xrpld/rpc/handlers/Handlers.h @@ -61,8 +61,6 @@ doConsensusInfo(RPC::JsonContext&); Json::Value doDepositAuthorized(RPC::JsonContext&); Json::Value -doDownloadShard(RPC::JsonContext&); -Json::Value doFeature(RPC::JsonContext&); Json::Value doFee(RPC::JsonContext&); @@ -101,8 +99,6 @@ doNFTBuyOffers(RPC::JsonContext&); Json::Value doNFTSellOffers(RPC::JsonContext&); Json::Value -doNodeToShard(RPC::JsonContext&); -Json::Value doNoRippleCheck(RPC::JsonContext&); Json::Value doOwnerInfo(RPC::JsonContext&); @@ -139,8 +135,6 @@ doSign(RPC::JsonContext&); Json::Value doSignFor(RPC::JsonContext&); Json::Value -doCrawlShards(RPC::JsonContext&); -Json::Value doStop(RPC::JsonContext&); Json::Value doSubmit(RPC::JsonContext&); diff --git a/src/xrpld/rpc/handlers/NodeToShard.cpp b/src/xrpld/rpc/handlers/NodeToShard.cpp deleted file mode 100644 index 917086ab0f4..00000000000 --- a/src/xrpld/rpc/handlers/NodeToShard.cpp +++ /dev/null @@ -1,86 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 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 -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { - -// node_to_shard [status|start|stop] -Json::Value -doNodeToShard(RPC::JsonContext& context) -{ - if (context.app.config().reporting()) - return rpcError(rpcREPORTING_UNSUPPORTED); - - // Shard store must be enabled - auto const shardStore = context.app.getShardStore(); - if (!shardStore) - return RPC::make_error(rpcNOT_ENABLED); - - if (!context.params.isMember(jss::action)) - return RPC::missing_field_error(jss::action); - - // Obtain and normalize the action to perform - auto const action = [&context] { - auto value = context.params[jss::action].asString(); - boost::to_lower(value); - - return value; - }(); - - // Vector of allowed actions - std::vector const allowedActions = {"status", "start", "stop"}; - - // Validate the action - if (std::find(allowedActions.begin(), allowedActions.end(), action) == - allowedActions.end()) - return RPC::invalid_field_error(jss::action); - - // Perform the action - if (action == "status") - { - // Get the status of the database import - return shardStore->getDatabaseImportStatus(); - } - else if (action == "start") - { - // Kick off an import - return shardStore->startNodeToShard(); - } - else if (action == "stop") - { - // Halt an import - return shardStore->stopNodeToShard(); - } - else - { - // Shouldn't happen - assert(false); - return rpcError(rpcINTERNAL); - } -} - -} // namespace ripple diff --git a/src/xrpld/rpc/handlers/Tx.cpp b/src/xrpld/rpc/handlers/Tx.cpp index de95044b71f..e32d926e566 100644 --- a/src/xrpld/rpc/handlers/Tx.cpp +++ b/src/xrpld/rpc/handlers/Tx.cpp @@ -100,7 +100,6 @@ doTxPostgres(RPC::Context& context, TxArgs const& args) if (locator.isFound()) { auto start = std::chrono::system_clock::now(); - // The second argument of fetch is ignored when not using shards if (auto obj = context.app.getNodeFamily().db().fetchNodeObject( locator.getNodestoreHash(), locator.getLedgerSequence())) { diff --git a/src/xrpld/shamap/Family.h b/src/xrpld/shamap/Family.h index 730f83483a6..6559ce5059b 100644 --- a/src/xrpld/shamap/Family.h +++ b/src/xrpld/shamap/Family.h @@ -53,28 +53,17 @@ class Family virtual beast::Journal const& journal() = 0; - /** Return a pointer to the Family Full Below Cache - - @param ledgerSeq ledger sequence determines a corresponding shard cache - @note ledgerSeq is used by ShardFamily and ignored by NodeFamily - */ + /** Return a pointer to the Family Full Below Cache */ virtual std::shared_ptr - getFullBelowCache(std::uint32_t ledgerSeq) = 0; - - /** Return a pointer to the Family Tree Node Cache + getFullBelowCache() = 0; - @param ledgerSeq ledger sequence determines a corresponding shard cache - @note ledgerSeq is used by ShardFamily and ignored by NodeFamily - */ + /** Return a pointer to the Family Tree Node Cache */ virtual std::shared_ptr - getTreeNodeCache(std::uint32_t ledgerSeq) = 0; + getTreeNodeCache() = 0; virtual void sweep() = 0; - virtual bool - isShardBacked() const = 0; - /** Acquire ledger that has a missing node by ledger sequence * * Throw if in reporting mode. diff --git a/src/xrpld/shamap/NodeFamily.h b/src/xrpld/shamap/NodeFamily.h index c540172c374..4062ea23897 100644 --- a/src/xrpld/shamap/NodeFamily.h +++ b/src/xrpld/shamap/NodeFamily.h @@ -60,18 +60,14 @@ class NodeFamily : public Family return j_; } - bool - isShardBacked() const override - { - return false; - } - - std::shared_ptr getFullBelowCache(std::uint32_t) override + std::shared_ptr + getFullBelowCache() override { return fbCache_; } - std::shared_ptr getTreeNodeCache(std::uint32_t) override + std::shared_ptr + getTreeNodeCache() override { return tnCache_; } diff --git a/src/xrpld/shamap/ShardFamily.h b/src/xrpld/shamap/ShardFamily.h deleted file mode 100644 index 2e8bece6dcf..00000000000 --- a/src/xrpld/shamap/ShardFamily.h +++ /dev/null @@ -1,125 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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_SHAMAP_SHARDFAMILY_H_INCLUDED -#define RIPPLE_SHAMAP_SHARDFAMILY_H_INCLUDED - -#include -#include - -namespace ripple { - -class Application; - -class ShardFamily : public Family -{ -public: - ShardFamily() = delete; - ShardFamily(ShardFamily const&) = delete; - ShardFamily(ShardFamily&&) = delete; - - ShardFamily& - operator=(ShardFamily const&) = delete; - - ShardFamily& - operator=(ShardFamily&&) = delete; - - ShardFamily(Application& app, CollectorManager& cm); - - NodeStore::Database& - db() override - { - return db_; - } - - NodeStore::Database const& - db() const override - { - return db_; - } - - beast::Journal const& - journal() override - { - return j_; - } - - bool - isShardBacked() const override - { - return true; - } - - std::shared_ptr - getFullBelowCache(std::uint32_t ledgerSeq) override; - - /** Return the number of entries in the cache */ - int - getFullBelowCacheSize(); - - std::shared_ptr - getTreeNodeCache(std::uint32_t ledgerSeq) override; - - /** Return a pair where the first item is the number of items cached - and the second item is the number of entries in the cached - */ - std::pair - getTreeNodeCacheSize(); - - void - sweep() override; - - void - reset() override; - - void - missingNodeAcquireBySeq(std::uint32_t seq, uint256 const& nodeHash) - override; - - void - missingNodeAcquireByHash(uint256 const& hash, std::uint32_t seq) override - { - acquire(hash, seq); - } - -private: - Application& app_; - NodeStore::Database& db_; - CollectorManager& cm_; - beast::Journal const j_; - - std::unordered_map> fbCache_; - std::mutex fbCacheMutex_; - - std::unordered_map> tnCache_; - std::mutex tnCacheMutex_; - int const tnTargetSize_; - std::chrono::seconds const tnTargetAge_; - - // Missing node handler - LedgerIndex maxSeq_{0}; - std::mutex maxSeqMutex_; - - void - acquire(uint256 const& hash, std::uint32_t seq); -}; - -} // namespace ripple - -#endif diff --git a/src/xrpld/shamap/detail/SHAMap.cpp b/src/xrpld/shamap/detail/SHAMap.cpp index e17f9346b85..d06ba2a153a 100644 --- a/src/xrpld/shamap/detail/SHAMap.cpp +++ b/src/xrpld/shamap/detail/SHAMap.cpp @@ -1166,7 +1166,7 @@ SHAMap::dump(bool hash) const std::shared_ptr SHAMap::cacheLookup(SHAMapHash const& hash) const { - auto ret = f_.getTreeNodeCache(ledgerSeq_)->fetch(hash.as_uint256()); + auto ret = f_.getTreeNodeCache()->fetch(hash.as_uint256()); assert(!ret || !ret->cowid()); return ret; } @@ -1180,8 +1180,7 @@ SHAMap::canonicalize( assert(node->cowid() == 0); assert(node->getHash() == hash); - f_.getTreeNodeCache(ledgerSeq_) - ->canonicalize_replace_client(hash.as_uint256(), node); + f_.getTreeNodeCache()->canonicalize_replace_client(hash.as_uint256(), node); } void diff --git a/src/xrpld/shamap/detail/SHAMapSync.cpp b/src/xrpld/shamap/detail/SHAMapSync.cpp index 02d548be24e..7235e526560 100644 --- a/src/xrpld/shamap/detail/SHAMapSync.cpp +++ b/src/xrpld/shamap/detail/SHAMapSync.cpp @@ -192,8 +192,7 @@ SHAMap::gmn_ProcessNodes(MissingNodes& mn, MissingNodes::StackEntry& se) } else if ( !backed_ || - !f_.getFullBelowCache(ledgerSeq_) - ->touch_if_exists(childHash.as_uint256())) + !f_.getFullBelowCache()->touch_if_exists(childHash.as_uint256())) { bool pending = false; auto d = descendAsync( @@ -251,8 +250,7 @@ SHAMap::gmn_ProcessNodes(MissingNodes& mn, MissingNodes::StackEntry& se) node->setFullBelowGen(mn.generation_); if (backed_) { - f_.getFullBelowCache(ledgerSeq_) - ->insert(node->getHash().as_uint256()); + f_.getFullBelowCache()->insert(node->getHash().as_uint256()); } } @@ -323,7 +321,7 @@ SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter) max, filter, 512, // number of async reads per pass - f_.getFullBelowCache(ledgerSeq_)->getGeneration()); + f_.getFullBelowCache()->getGeneration()); if (!root_->isInner() || std::static_pointer_cast(root_)->isFullBelow( @@ -580,7 +578,7 @@ SHAMap::addKnownNode( return SHAMapAddNode::duplicate(); } - auto const generation = f_.getFullBelowCache(ledgerSeq_)->getGeneration(); + auto const generation = f_.getFullBelowCache()->getGeneration(); SHAMapNodeID iNodeID; auto iNode = root_.get(); @@ -598,8 +596,7 @@ SHAMap::addKnownNode( } auto childHash = inner->getChildHash(branch); - if (f_.getFullBelowCache(ledgerSeq_) - ->touch_if_exists(childHash.as_uint256())) + if (f_.getFullBelowCache()->touch_if_exists(childHash.as_uint256())) { return SHAMapAddNode::duplicate(); } diff --git a/src/xrpld/shamap/detail/ShardFamily.cpp b/src/xrpld/shamap/detail/ShardFamily.cpp deleted file mode 100644 index aef4c6cde0a..00000000000 --- a/src/xrpld/shamap/detail/ShardFamily.cpp +++ /dev/null @@ -1,198 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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 -#include -#include -#include -#include -#include - -namespace ripple { - -static NodeStore::Database& -getShardStore(Application& app) -{ - auto const dbPtr = app.getShardStore(); - assert(dbPtr); - return *dbPtr; -} - -ShardFamily::ShardFamily(Application& app, CollectorManager& cm) - : app_(app) - , db_(getShardStore(app)) - , cm_(cm) - , j_(app.journal("ShardFamily")) - , tnTargetSize_(app.config().getValueFor(SizedItem::treeCacheSize, 0)) - , tnTargetAge_(app.config().getValueFor(SizedItem::treeCacheAge, 0)) -{ -} - -std::shared_ptr -ShardFamily::getFullBelowCache(std::uint32_t ledgerSeq) -{ - auto const shardIndex{app_.getShardStore()->seqToShardIndex(ledgerSeq)}; - std::lock_guard lock(fbCacheMutex_); - if (auto const it{fbCache_.find(shardIndex)}; it != fbCache_.end()) - return it->second; - - // Create a cache for the corresponding shard - auto fbCache{std::make_shared( - "Shard family full below cache shard " + std::to_string(shardIndex), - stopwatch(), - j_, - cm_.collector(), - fullBelowTargetSize, - fullBelowExpiration)}; - return fbCache_.emplace(shardIndex, std::move(fbCache)).first->second; -} - -int -ShardFamily::getFullBelowCacheSize() -{ - size_t sz{0}; - std::lock_guard lock(fbCacheMutex_); - for (auto const& e : fbCache_) - sz += e.second->size(); - return sz; -} - -std::shared_ptr -ShardFamily::getTreeNodeCache(std::uint32_t ledgerSeq) -{ - auto const shardIndex{app_.getShardStore()->seqToShardIndex(ledgerSeq)}; - std::lock_guard lock(tnCacheMutex_); - if (auto const it{tnCache_.find(shardIndex)}; it != tnCache_.end()) - return it->second; - - // Create a cache for the corresponding shard - auto tnCache{std::make_shared( - "Shard family tree node cache shard " + std::to_string(shardIndex), - tnTargetSize_, - tnTargetAge_, - stopwatch(), - j_)}; - return tnCache_.emplace(shardIndex, std::move(tnCache)).first->second; -} - -std::pair -ShardFamily::getTreeNodeCacheSize() -{ - int cacheSz{0}; - int trackSz{0}; - std::lock_guard lock(tnCacheMutex_); - for (auto const& e : tnCache_) - { - cacheSz += e.second->getCacheSize(); - trackSz += e.second->getTrackSize(); - } - return {cacheSz, trackSz}; -} - -void -ShardFamily::sweep() -{ - { - std::lock_guard lock(fbCacheMutex_); - for (auto it = fbCache_.cbegin(); it != fbCache_.cend();) - { - it->second->sweep(); - - // Remove cache if empty - if (it->second->size() == 0) - it = fbCache_.erase(it); - else - ++it; - } - } - - std::lock_guard lock(tnCacheMutex_); - for (auto it = tnCache_.cbegin(); it != tnCache_.cend();) - { - it->second->sweep(); - - // Remove cache if empty - if (it->second->getTrackSize() == 0) - it = tnCache_.erase(it); - else - ++it; - } -} - -void -ShardFamily::reset() -{ - { - std::lock_guard lock(maxSeqMutex_); - maxSeq_ = 0; - } - - { - std::lock_guard lock(fbCacheMutex_); - fbCache_.clear(); - } - - std::lock_guard lock(tnCacheMutex_); - tnCache_.clear(); -} - -void -ShardFamily::missingNodeAcquireBySeq(std::uint32_t seq, uint256 const& nodeHash) -{ - std::ignore = nodeHash; - JLOG(j_.error()) << "Missing node in ledger sequence " << seq; - - std::unique_lock lock(maxSeqMutex_); - if (maxSeq_ == 0) - { - maxSeq_ = seq; - - do - { - // Try to acquire the most recent missing ledger - seq = maxSeq_; - - lock.unlock(); - - // This can invoke the missing node handler - acquire(app_.getLedgerMaster().getHashBySeq(seq), seq); - - lock.lock(); - } while (maxSeq_ != seq); - } - else if (maxSeq_ < seq) - { - // We found a more recent ledger with a missing node - maxSeq_ = seq; - } -} - -void -ShardFamily::acquire(uint256 const& hash, std::uint32_t seq) -{ - if (hash.isNonZero()) - { - JLOG(j_.error()) << "Missing node in " << to_string(hash); - - app_.getInboundLedgers().acquire( - hash, seq, InboundLedger::Reason::SHARD); - } -} - -} // namespace ripple From 0a331ea72e6239b6990cbea419d81af74c6c4895 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Mon, 5 Aug 2024 17:05:12 +0100 Subject: [PATCH 41/82] Factor out Transactor::trapTransaction (#5087) --- src/xrpld/app/tx/detail/Transactor.cpp | 10 +++++++++- src/xrpld/app/tx/detail/Transactor.h | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/xrpld/app/tx/detail/Transactor.cpp b/src/xrpld/app/tx/detail/Transactor.cpp index 42e9f0677ab..6ae8be8a67f 100644 --- a/src/xrpld/app/tx/detail/Transactor.cpp +++ b/src/xrpld/app/tx/detail/Transactor.cpp @@ -825,6 +825,14 @@ Transactor::reset(XRPAmount fee) return {ter, fee}; } +// The sole purpose of this function is to provide a convenient, named +// location to set a breakpoint, to be used when replaying transactions. +void +Transactor::trapTransaction(uint256 txHash) const +{ + JLOG(j_.debug()) << "Transaction trapped: " << txHash; +} + //------------------------------------------------------------------------------ std::pair Transactor::operator()() @@ -857,7 +865,7 @@ Transactor::operator()() if (auto const& trap = ctx_.app.trapTxID(); trap && *trap == ctx_.tx.getTransactionID()) { - JLOG(j_.debug()) << "Transaction trapped: " << *trap; + trapTransaction(*trap); } auto result = ctx_.preclaimResult; diff --git a/src/xrpld/app/tx/detail/Transactor.h b/src/xrpld/app/tx/detail/Transactor.h index 27f22a0eb2e..c587e5e1994 100644 --- a/src/xrpld/app/tx/detail/Transactor.h +++ b/src/xrpld/app/tx/detail/Transactor.h @@ -198,6 +198,8 @@ class Transactor checkSingleSign(PreclaimContext const& ctx); static NotTEC checkMultiSign(PreclaimContext const& ctx); + + void trapTransaction(uint256) const; }; /** Performs early sanity checks on the txid */ From c19a88fee9cd5b034a2fbcc013416afc10464e35 Mon Sep 17 00:00:00 2001 From: Scott Schurr Date: Wed, 7 Aug 2024 15:14:19 -0700 Subject: [PATCH 42/82] Address rare corruption of NFTokenPage linked list (#4945) * Add fixNFTokenPageLinks amendment: It was discovered that under rare circumstances the links between NFTokenPages could be removed. If this happens, then the account_objects and account_nfts RPC commands under-report the NFTokens owned by an account. The fixNFTokenPageLinks amendment does the following to address the problem: - It fixes the underlying problem so no further broken links should be created. - It adds Invariants so, if such damage were introduced in the future, an invariant would stop it. - It adds a new FixLedgerState transaction that repairs directories that were damaged in this fashion. - It adds unit tests for all of it. --- include/xrpl/protocol/Feature.h | 3 +- include/xrpl/protocol/SField.h | 1 + include/xrpl/protocol/TER.h | 1 + include/xrpl/protocol/TxFormats.h | 5 +- include/xrpl/protocol/jss.h | 1 + src/libxrpl/protocol/Feature.cpp | 1 + src/libxrpl/protocol/SField.cpp | 1 + src/libxrpl/protocol/TER.cpp | 1 + src/libxrpl/protocol/TxFormats.cpp | 8 + src/test/app/FixNFTokenPageLinks_test.cpp | 676 ++++++++++++++++ src/test/app/NFTokenBurn_test.cpp | 859 ++++++++++++++++++--- src/test/jtx.h | 1 + src/test/jtx/impl/ledgerStateFix.cpp | 49 ++ src/test/jtx/ledgerStateFix.h | 44 ++ src/test/ledger/Invariants_test.cpp | 157 +++- src/xrpld/app/tx/detail/InvariantCheck.cpp | 49 +- src/xrpld/app/tx/detail/InvariantCheck.h | 2 + src/xrpld/app/tx/detail/LedgerStateFix.cpp | 99 +++ src/xrpld/app/tx/detail/LedgerStateFix.h | 57 ++ src/xrpld/app/tx/detail/NFTokenUtils.cpp | 160 +++- src/xrpld/app/tx/detail/NFTokenUtils.h | 7 + src/xrpld/app/tx/detail/applySteps.cpp | 3 + 22 files changed, 2054 insertions(+), 131 deletions(-) create mode 100644 src/test/app/FixNFTokenPageLinks_test.cpp create mode 100644 src/test/jtx/impl/ledgerStateFix.cpp create mode 100644 src/test/jtx/ledgerStateFix.h create mode 100644 src/xrpld/app/tx/detail/LedgerStateFix.cpp create mode 100644 src/xrpld/app/tx/detail/LedgerStateFix.h diff --git a/include/xrpl/protocol/Feature.h b/include/xrpl/protocol/Feature.h index 7eec46e89eb..a00d6b85c1b 100644 --- a/include/xrpl/protocol/Feature.h +++ b/include/xrpl/protocol/Feature.h @@ -80,7 +80,7 @@ namespace detail { // Feature.cpp. Because it's only used to reserve storage, and determine how // large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than // the actual number of amendments. A LogicError on startup will verify this. -static constexpr std::size_t numFeatures = 78; +static constexpr std::size_t numFeatures = 79; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated @@ -371,6 +371,7 @@ extern uint256 const fixReducedOffersV2; extern uint256 const fixEnforceNFTokenTrustline; extern uint256 const fixInnerObjTemplate2; extern uint256 const featureInvariantsV1_1; +extern uint256 const fixNFTokenPageLinks; } // namespace ripple diff --git a/include/xrpl/protocol/SField.h b/include/xrpl/protocol/SField.h index 15aa2272d75..7f54201a4b8 100644 --- a/include/xrpl/protocol/SField.h +++ b/include/xrpl/protocol/SField.h @@ -388,6 +388,7 @@ extern SF_UINT16 const sfHookEmitCount; extern SF_UINT16 const sfHookExecutionIndex; extern SF_UINT16 const sfHookApiVersion; extern SF_UINT16 const sfDiscountedFee; +extern SF_UINT16 const sfLedgerFixType; // 32-bit integers (common) extern SF_UINT32 const sfNetworkID; diff --git a/include/xrpl/protocol/TER.h b/include/xrpl/protocol/TER.h index 335ef8de39a..aae3c7107bd 100644 --- a/include/xrpl/protocol/TER.h +++ b/include/xrpl/protocol/TER.h @@ -182,6 +182,7 @@ enum TEFcodes : TERUnderlyingType { tefTOO_BIG, tefNO_TICKET, tefNFTOKEN_IS_NOT_TRANSFERABLE, + tefINVALID_LEDGER_FIX_TYPE, }; //------------------------------------------------------------------------------ diff --git a/include/xrpl/protocol/TxFormats.h b/include/xrpl/protocol/TxFormats.h index bd5dffd94e9..a3f5cca108c 100644 --- a/include/xrpl/protocol/TxFormats.h +++ b/include/xrpl/protocol/TxFormats.h @@ -190,13 +190,16 @@ enum TxType : std::uint16_t /** This transaction type deletes a DID */ ttDID_DELETE = 50, - /** This transaction type creates an Oracle instance */ ttORACLE_SET = 51, /** This transaction type deletes an Oracle instance */ ttORACLE_DELETE = 52, + /** This transaction type fixes a problem in the ledger state */ + ttLEDGER_STATE_FIX = 53, + + /** This system-generated transaction type is used to update the status of the various amendments. For details, see: https://xrpl.org/amendments.html diff --git a/include/xrpl/protocol/jss.h b/include/xrpl/protocol/jss.h index 84628da286f..e3eda80b44f 100644 --- a/include/xrpl/protocol/jss.h +++ b/include/xrpl/protocol/jss.h @@ -104,6 +104,7 @@ JSS(NFTokenAcceptOffer); // transaction type. JSS(NFTokenCancelOffer); // transaction type. JSS(NFTokenCreateOffer); // transaction type. JSS(NFTokenPage); // ledger type. +JSS(LedgerStateFix); // transaction type. JSS(LPTokenOut); // in: AMM Liquidity Provider deposit tokens JSS(LPTokenIn); // in: AMM Liquidity Provider withdraw tokens JSS(LPToken); // out: AMM Liquidity Provider tokens info diff --git a/src/libxrpl/protocol/Feature.cpp b/src/libxrpl/protocol/Feature.cpp index 87395b7e189..078369bf20c 100644 --- a/src/libxrpl/protocol/Feature.cpp +++ b/src/libxrpl/protocol/Feature.cpp @@ -497,6 +497,7 @@ REGISTER_FEATURE(NFTokenMintOffer, Supported::yes, VoteBehavior::De REGISTER_FIX (fixReducedOffersV2, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixEnforceNFTokenTrustline, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixInnerObjTemplate2, Supported::yes, VoteBehavior::DefaultNo); +REGISTER_FIX (fixNFTokenPageLinks, Supported::yes, VoteBehavior::DefaultNo); // InvariantsV1_1 will be changes to Supported::yes when all the // invariants expected to be included under it are complete. REGISTER_FEATURE(InvariantsV1_1, Supported::no, VoteBehavior::DefaultNo); diff --git a/src/libxrpl/protocol/SField.cpp b/src/libxrpl/protocol/SField.cpp index d56f3983352..f8eb2d6f877 100644 --- a/src/libxrpl/protocol/SField.cpp +++ b/src/libxrpl/protocol/SField.cpp @@ -113,6 +113,7 @@ CONSTRUCT_TYPED_SFIELD(sfHookStateChangeCount, "HookStateChangeCount", UINT16, CONSTRUCT_TYPED_SFIELD(sfHookEmitCount, "HookEmitCount", UINT16, 18); CONSTRUCT_TYPED_SFIELD(sfHookExecutionIndex, "HookExecutionIndex", UINT16, 19); CONSTRUCT_TYPED_SFIELD(sfHookApiVersion, "HookApiVersion", UINT16, 20); +CONSTRUCT_TYPED_SFIELD(sfLedgerFixType, "LedgerFixType", UINT16, 21); // 32-bit integers (common) CONSTRUCT_TYPED_SFIELD(sfNetworkID, "NetworkID", UINT32, 1); diff --git a/src/libxrpl/protocol/TER.cpp b/src/libxrpl/protocol/TER.cpp index f452b05464e..917bbf26a9f 100644 --- a/src/libxrpl/protocol/TER.cpp +++ b/src/libxrpl/protocol/TER.cpp @@ -137,6 +137,7 @@ transResults() MAKE_ERROR(tefTOO_BIG, "Transaction affects too many items."), MAKE_ERROR(tefNO_TICKET, "Ticket is not in ledger."), MAKE_ERROR(tefNFTOKEN_IS_NOT_TRANSFERABLE, "The specified NFToken is not transferable."), + MAKE_ERROR(tefINVALID_LEDGER_FIX_TYPE, "The LedgerFixType field has an invalid value."), MAKE_ERROR(telLOCAL_ERROR, "Local failure."), MAKE_ERROR(telBAD_DOMAIN, "Domain too long."), diff --git a/src/libxrpl/protocol/TxFormats.cpp b/src/libxrpl/protocol/TxFormats.cpp index 71c333dc497..8a93232604e 100644 --- a/src/libxrpl/protocol/TxFormats.cpp +++ b/src/libxrpl/protocol/TxFormats.cpp @@ -505,6 +505,14 @@ TxFormats::TxFormats() {sfOracleDocumentID, soeREQUIRED}, }, commonFields); + + add(jss::LedgerStateFix, + ttLEDGER_STATE_FIX, + { + {sfLedgerFixType, soeREQUIRED}, + {sfOwner, soeOPTIONAL}, + }, + commonFields); } TxFormats const& diff --git a/src/test/app/FixNFTokenPageLinks_test.cpp b/src/test/app/FixNFTokenPageLinks_test.cpp new file mode 100644 index 00000000000..dea6d4569e0 --- /dev/null +++ b/src/test/app/FixNFTokenPageLinks_test.cpp @@ -0,0 +1,676 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 +#include +#include +#include +#include + +namespace ripple { + +class FixNFTokenPageLinks_test : public beast::unit_test::suite +{ + // Helper function that returns the owner count of an account root. + static std::uint32_t + ownerCount(test::jtx::Env const& env, test::jtx::Account const& acct) + { + std::uint32_t ret{0}; + if (auto const sleAcct = env.le(acct)) + ret = sleAcct->at(sfOwnerCount); + return ret; + } + + // Helper function that returns the number of nfts owned by an account. + static std::uint32_t + nftCount(test::jtx::Env& env, test::jtx::Account const& acct) + { + Json::Value params; + params[jss::account] = acct.human(); + params[jss::type] = "state"; + Json::Value nfts = env.rpc("json", "account_nfts", to_string(params)); + return nfts[jss::result][jss::account_nfts].size(); + }; + + // A helper function that generates 96 nfts packed into three pages + // of 32 each. Returns a sorted vector of the NFTokenIDs packed into + // the pages. + std::vector + genPackedTokens(test::jtx::Env& env, test::jtx::Account const& owner) + { + using namespace test::jtx; + + std::vector nfts; + nfts.reserve(96); + + // We want to create fully packed NFT pages. This is a little + // tricky since the system currently in place is inclined to + // assign consecutive tokens to only 16 entries per page. + // + // By manipulating the internal form of the taxon we can force + // creation of NFT pages that are completely full. This lambda + // tells us the taxon value we should pass in in order for the + // internal representation to match the passed in value. + auto internalTaxon = [this, &env]( + Account const& acct, + std::uint32_t taxon) -> std::uint32_t { + std::uint32_t tokenSeq = [this, &env, &acct]() { + auto const le = env.le(acct); + if (BEAST_EXPECT(le)) + return le->at(~sfMintedNFTokens).value_or(0u); + return 0u; + }(); + + // If fixNFTokenRemint amendment is on, we must + // add FirstNFTokenSequence. + if (env.current()->rules().enabled(fixNFTokenRemint)) + tokenSeq += env.le(acct) + ->at(~sfFirstNFTokenSequence) + .value_or(env.seq(acct)); + + return toUInt32(nft::cipheredTaxon(tokenSeq, nft::toTaxon(taxon))); + }; + + for (std::uint32_t i = 0; i < 96; ++i) + { + // In order to fill the pages we use the taxon to break them + // into groups of 16 entries. By having the internal + // representation of the taxon go... + // 0, 3, 2, 5, 4, 7... + // in sets of 16 NFTs we can get each page to be fully + // populated. + std::uint32_t const intTaxon = (i / 16) + (i & 0b10000 ? 2 : 0); + uint32_t const extTaxon = internalTaxon(owner, intTaxon); + nfts.push_back( + token::getNextID(env, owner, extTaxon, tfTransferable)); + env(token::mint(owner, extTaxon), txflags(tfTransferable)); + env.close(); + } + + // Sort the NFTs so they are listed in storage order, not + // creation order. + std::sort(nfts.begin(), nfts.end()); + + // Verify that the owner does indeed have exactly three pages + // of NFTs with 32 entries in each page. + { + Json::Value params; + params[jss::account] = owner.human(); + auto resp = env.rpc("json", "account_objects", to_string(params)); + + Json::Value const& acctObjs = + resp[jss::result][jss::account_objects]; + + int pageCount = 0; + for (Json::UInt i = 0; i < acctObjs.size(); ++i) + { + if (BEAST_EXPECT( + acctObjs[i].isMember(sfNFTokens.jsonName) && + acctObjs[i][sfNFTokens.jsonName].isArray())) + { + BEAST_EXPECT(acctObjs[i][sfNFTokens.jsonName].size() == 32); + ++pageCount; + } + } + // If this check fails then the internal NFT directory logic + // has changed. + BEAST_EXPECT(pageCount == 3); + } + return nfts; + }; + + void + testLedgerStateFixErrors() + { + testcase("LedgerStateFix error cases"); + + using namespace test::jtx; + + Account const alice("alice"); + + { + // Verify that the LedgerStateFix transaction is disabled + // without the fixNFTokenPageLinks amendment. + Env env{*this, supported_amendments() - fixNFTokenPageLinks}; + env.fund(XRP(1000), alice); + + auto const linkFixFee = drops(env.current()->fees().increment); + env(ledgerStateFix::nftPageLinks(alice, alice), + fee(linkFixFee), + ter(temDISABLED)); + } + + Env env{*this, supported_amendments()}; + env.fund(XRP(1000), alice); + std::uint32_t const ticketSeq = env.seq(alice); + env(ticket::create(alice, 1)); + + // Preflight + + { + // Fail preflight1. Can't combine AcccountTxnID and ticket. + Json::Value tx = ledgerStateFix::nftPageLinks(alice, alice); + tx[sfAccountTxnID.jsonName] = + "00000000000000000000000000000000" + "00000000000000000000000000000000"; + env(tx, ticket::use(ticketSeq), ter(temINVALID)); + } + // Fee too low. + env(ledgerStateFix::nftPageLinks(alice, alice), ter(telINSUF_FEE_P)); + + // Invalid flags. + auto const linkFixFee = drops(env.current()->fees().increment); + env(ledgerStateFix::nftPageLinks(alice, alice), + fee(linkFixFee), + txflags(tfPassive), + ter(temINVALID_FLAG)); + + { + // ledgerStateFix::nftPageLinks requires an Owner field. + Json::Value tx = ledgerStateFix::nftPageLinks(alice, alice); + tx.removeMember(sfOwner.jsonName); + env(tx, fee(linkFixFee), ter(temINVALID)); + } + { + // Invalid LedgerFixType codes. + Json::Value tx = ledgerStateFix::nftPageLinks(alice, alice); + tx[sfLedgerFixType.jsonName] = 0; + env(tx, fee(linkFixFee), ter(tefINVALID_LEDGER_FIX_TYPE)); + + tx[sfLedgerFixType.jsonName] = 200; + env(tx, fee(linkFixFee), ter(tefINVALID_LEDGER_FIX_TYPE)); + } + + // Preclaim + Account const carol("carol"); + env.memoize(carol); + env(ledgerStateFix::nftPageLinks(alice, carol), + fee(linkFixFee), + ter(tecOBJECT_NOT_FOUND)); + } + + void + testTokenPageLinkErrors() + { + testcase("NFTokenPageLinkFix error cases"); + + using namespace test::jtx; + + Account const alice("alice"); + + Env env{*this, supported_amendments()}; + env.fund(XRP(1000), alice); + + // These cases all return the same TER code, but they exercise + // different cases where there is nothing to fix in an owner's + // NFToken pages. So they increase test coverage. + + // Owner has no pages to fix. + auto const linkFixFee = drops(env.current()->fees().increment); + env(ledgerStateFix::nftPageLinks(alice, alice), + fee(linkFixFee), + ter(tecFAILED_PROCESSING)); + + // Alice has only one page. + env(token::mint(alice), txflags(tfTransferable)); + env.close(); + + env(ledgerStateFix::nftPageLinks(alice, alice), + fee(linkFixFee), + ter(tecFAILED_PROCESSING)); + + // Alice has at least three pages. + for (std::uint32_t i = 0; i < 64; ++i) + { + env(token::mint(alice), txflags(tfTransferable)); + env.close(); + } + + env(ledgerStateFix::nftPageLinks(alice, alice), + fee(linkFixFee), + ter(tecFAILED_PROCESSING)); + } + + void + testFixNFTokenPageLinks() + { + // Steps: + // 1. Before the fixNFTokenPageLinks amendment is enabled, build the + // three kinds of damaged NFToken directories we know about: + // A. One where there is only one page, but without the final index. + // B. One with multiple pages and a missing final page. + // C. One with links missing in the middle of the chain. + // 2. Enable the fixNFTokenPageLinks amendment. + // 3. Invoke the LedgerStateFix transactor and repair the directories. + testcase("Fix links"); + + using namespace test::jtx; + + Account const alice("alice"); + Account const bob("bob"); + Account const carol("carol"); + Account const daria("daria"); + + Env env{*this, supported_amendments() - fixNFTokenPageLinks}; + env.fund(XRP(1000), alice, bob, carol, daria); + + //********************************************************************** + // Step 1A: Create damaged NFToken directories: + // o One where there is only one page, but without the final index. + //********************************************************************** + + // alice generates three packed pages. + std::vector aliceNFTs = genPackedTokens(env, alice); + BEAST_EXPECT(nftCount(env, alice) == 96); + BEAST_EXPECT(ownerCount(env, alice) == 3); + + // Get the index of the middle page. + uint256 const aliceMiddleNFTokenPageIndex = [&env, &alice]() { + auto lastNFTokenPage = env.le(keylet::nftpage_max(alice)); + return lastNFTokenPage->at(sfPreviousPageMin); + }(); + + // alice burns all the tokens in the first and last pages. + for (int i = 0; i < 32; ++i) + { + env(token::burn(alice, {aliceNFTs[i]})); + env.close(); + } + aliceNFTs.erase(aliceNFTs.begin(), aliceNFTs.begin() + 32); + for (int i = 0; i < 32; ++i) + { + env(token::burn(alice, {aliceNFTs.back()})); + aliceNFTs.pop_back(); + env.close(); + } + BEAST_EXPECT(ownerCount(env, alice) == 1); + BEAST_EXPECT(nftCount(env, alice) == 32); + + // Removing the last token from the last page deletes the last + // page. This is a bug. The contents of the next-to-last page + // should have been moved into the last page. + BEAST_EXPECT(!env.le(keylet::nftpage_max(alice))); + + // alice's "middle" page is still present, but has no links. + { + auto aliceMiddleNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), aliceMiddleNFTokenPageIndex)); + if (!BEAST_EXPECT(aliceMiddleNFTokenPage)) + return; + + BEAST_EXPECT( + !aliceMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT( + !aliceMiddleNFTokenPage->isFieldPresent(sfNextPageMin)); + } + + //********************************************************************** + // Step 1B: Create damaged NFToken directories: + // o One with multiple pages and a missing final page. + //********************************************************************** + + // bob generates three packed pages. + std::vector bobNFTs = genPackedTokens(env, bob); + BEAST_EXPECT(nftCount(env, bob) == 96); + BEAST_EXPECT(ownerCount(env, bob) == 3); + + // Get the index of the middle page. + uint256 const bobMiddleNFTokenPageIndex = [&env, &bob]() { + auto lastNFTokenPage = env.le(keylet::nftpage_max(bob)); + return lastNFTokenPage->at(sfPreviousPageMin); + }(); + + // bob burns all the tokens in the very last page. + for (int i = 0; i < 32; ++i) + { + env(token::burn(bob, {bobNFTs.back()})); + bobNFTs.pop_back(); + env.close(); + } + BEAST_EXPECT(nftCount(env, bob) == 64); + BEAST_EXPECT(ownerCount(env, bob) == 2); + + // Removing the last token from the last page deletes the last + // page. This is a bug. The contents of the next-to-last page + // should have been moved into the last page. + BEAST_EXPECT(!env.le(keylet::nftpage_max(bob))); + + // bob's "middle" page is still present, but has lost the + // NextPageMin field. + { + auto bobMiddleNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(bob), bobMiddleNFTokenPageIndex)); + if (!BEAST_EXPECT(bobMiddleNFTokenPage)) + return; + + BEAST_EXPECT( + bobMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!bobMiddleNFTokenPage->isFieldPresent(sfNextPageMin)); + } + + //********************************************************************** + // Step 1C: Create damaged NFToken directories: + // o One with links missing in the middle of the chain. + //********************************************************************** + + // carol generates three packed pages. + std::vector carolNFTs = genPackedTokens(env, carol); + BEAST_EXPECT(nftCount(env, carol) == 96); + BEAST_EXPECT(ownerCount(env, carol) == 3); + + // Get the index of the middle page. + uint256 const carolMiddleNFTokenPageIndex = [&env, &carol]() { + auto lastNFTokenPage = env.le(keylet::nftpage_max(carol)); + return lastNFTokenPage->at(sfPreviousPageMin); + }(); + + // carol sells all of the tokens in the very last page to daria. + std::vector dariaNFTs; + dariaNFTs.reserve(32); + for (int i = 0; i < 32; ++i) + { + uint256 const offerIndex = + keylet::nftoffer(carol, env.seq(carol)).key; + env(token::createOffer(carol, carolNFTs.back(), XRP(0)), + txflags(tfSellNFToken)); + env.close(); + + env(token::acceptSellOffer(daria, offerIndex)); + env.close(); + + dariaNFTs.push_back(carolNFTs.back()); + carolNFTs.pop_back(); + } + BEAST_EXPECT(nftCount(env, carol) == 64); + BEAST_EXPECT(ownerCount(env, carol) == 2); + + // Removing the last token from the last page deletes the last + // page. This is a bug. The contents of the next-to-last page + // should have been moved into the last page. + BEAST_EXPECT(!env.le(keylet::nftpage_max(carol))); + + // carol's "middle" page is still present, but has lost the + // NextPageMin field. + auto carolMiddleNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(carol), carolMiddleNFTokenPageIndex)); + if (!BEAST_EXPECT(carolMiddleNFTokenPage)) + return; + + BEAST_EXPECT(carolMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!carolMiddleNFTokenPage->isFieldPresent(sfNextPageMin)); + + // At this point carol's NFT directory has the same problem that + // bob's has: the last page is missing. Now we make things more + // complicated by putting the last page back. carol buys their NFTs + // back from daria. + for (uint256 const& nft : dariaNFTs) + { + uint256 const offerIndex = + keylet::nftoffer(carol, env.seq(carol)).key; + env(token::createOffer(carol, nft, drops(1)), token::owner(daria)); + env.close(); + + env(token::acceptBuyOffer(daria, offerIndex)); + env.close(); + + carolNFTs.push_back(nft); + } + + // Note that carol actually owns 96 NFTs, but only 64 are reported + // because the links are damaged. + BEAST_EXPECT(nftCount(env, carol) == 64); + BEAST_EXPECT(ownerCount(env, carol) == 3); + + // carol's "middle" page is present and still has no NextPageMin field. + { + auto carolMiddleNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(carol), carolMiddleNFTokenPageIndex)); + if (!BEAST_EXPECT(carolMiddleNFTokenPage)) + return; + + BEAST_EXPECT( + carolMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT( + !carolMiddleNFTokenPage->isFieldPresent(sfNextPageMin)); + } + // carol has a "last" page again, but it has no PreviousPageMin field. + { + auto carolLastNFTokenPage = env.le(keylet::nftpage_max(carol)); + + BEAST_EXPECT( + !carolLastNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!carolLastNFTokenPage->isFieldPresent(sfNextPageMin)); + } + + //********************************************************************** + // Step 2: Enable the fixNFTokenPageLinks amendment. + //********************************************************************** + // Verify that the LedgerStateFix transaction is not enabled. + auto const linkFixFee = drops(env.current()->fees().increment); + env(ledgerStateFix::nftPageLinks(daria, alice), + fee(linkFixFee), + ter(temDISABLED)); + + // Wait 15 ledgers so the LedgerStateFix transaction is no longer + // retried. + for (int i = 0; i < 15; ++i) + env.close(); + + env.enableFeature(fixNFTokenPageLinks); + env.close(); + + //********************************************************************** + // Step 3A: Repair the one-page directory (alice's) + //********************************************************************** + + // Verify that alice's NFToken directory is still damaged. + + // alice's last page should still be missing. + BEAST_EXPECT(!env.le(keylet::nftpage_max(alice))); + + // alice's "middle" page is still present and has no links. + { + auto aliceMiddleNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), aliceMiddleNFTokenPageIndex)); + if (!BEAST_EXPECT(aliceMiddleNFTokenPage)) + return; + + BEAST_EXPECT( + !aliceMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT( + !aliceMiddleNFTokenPage->isFieldPresent(sfNextPageMin)); + } + + // The server "remembers" daria's failed nftPageLinks transaction + // signature. So we need to advance daria's sequence number before + // daria can submit a similar transaction. + env(noop(daria)); + + // daria fixes the links in alice's NFToken directory. + env(ledgerStateFix::nftPageLinks(daria, alice), fee(linkFixFee)); + env.close(); + + // alices's last page should now be present and include no links. + { + auto aliceLastNFTokenPage = env.le(keylet::nftpage_max(alice)); + if (!BEAST_EXPECT(aliceLastNFTokenPage)) + return; + + BEAST_EXPECT( + !aliceLastNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!aliceLastNFTokenPage->isFieldPresent(sfNextPageMin)); + } + + // alice's middle page should be gone. + BEAST_EXPECT(!env.le(keylet::nftpage( + keylet::nftpage_min(alice), aliceMiddleNFTokenPageIndex))); + + BEAST_EXPECT(nftCount(env, alice) == 32); + BEAST_EXPECT(ownerCount(env, alice) == 1); + + //********************************************************************** + // Step 3B: Repair the two-page directory (bob's) + //********************************************************************** + + // Verify that bob's NFToken directory is still damaged. + + // bob's last page should still be missing. + BEAST_EXPECT(!env.le(keylet::nftpage_max(bob))); + + // bob's "middle" page is still present and missing NextPageMin. + { + auto bobMiddleNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(bob), bobMiddleNFTokenPageIndex)); + if (!BEAST_EXPECT(bobMiddleNFTokenPage)) + return; + + BEAST_EXPECT( + bobMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!bobMiddleNFTokenPage->isFieldPresent(sfNextPageMin)); + } + + // daria fixes the links in bob's NFToken directory. + env(ledgerStateFix::nftPageLinks(daria, bob), fee(linkFixFee)); + env.close(); + + // bob's last page should now be present and include a previous + // link but no next link. + { + auto const lastPageKeylet = keylet::nftpage_max(bob); + auto const bobLastNFTokenPage = env.le(lastPageKeylet); + if (!BEAST_EXPECT(bobLastNFTokenPage)) + return; + + BEAST_EXPECT(bobLastNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT( + bobLastNFTokenPage->at(sfPreviousPageMin) != + bobMiddleNFTokenPageIndex); + BEAST_EXPECT(!bobLastNFTokenPage->isFieldPresent(sfNextPageMin)); + + auto const bobNewFirstNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(bob), + bobLastNFTokenPage->at(sfPreviousPageMin))); + if (!BEAST_EXPECT(bobNewFirstNFTokenPage)) + return; + + BEAST_EXPECT( + bobNewFirstNFTokenPage->isFieldPresent(sfNextPageMin) && + bobNewFirstNFTokenPage->at(sfNextPageMin) == + lastPageKeylet.key); + BEAST_EXPECT( + !bobNewFirstNFTokenPage->isFieldPresent(sfPreviousPageMin)); + } + + // bob's middle page should be gone. + BEAST_EXPECT(!env.le(keylet::nftpage( + keylet::nftpage_min(bob), bobMiddleNFTokenPageIndex))); + + BEAST_EXPECT(nftCount(env, bob) == 64); + BEAST_EXPECT(ownerCount(env, bob) == 2); + + //********************************************************************** + // Step 3C: Repair the three-page directory (carol's) + //********************************************************************** + + // Verify that carol's NFToken directory is still damaged. + + // carol's "middle" page is present and has no NextPageMin field. + { + auto carolMiddleNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(carol), carolMiddleNFTokenPageIndex)); + if (!BEAST_EXPECT(carolMiddleNFTokenPage)) + return; + + BEAST_EXPECT( + carolMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT( + !carolMiddleNFTokenPage->isFieldPresent(sfNextPageMin)); + } + // carol has a "last" page, but it has no PreviousPageMin field. + { + auto carolLastNFTokenPage = env.le(keylet::nftpage_max(carol)); + + BEAST_EXPECT( + !carolLastNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!carolLastNFTokenPage->isFieldPresent(sfNextPageMin)); + } + + // carol fixes the links in their own NFToken directory. + env(ledgerStateFix::nftPageLinks(carol, carol), fee(linkFixFee)); + env.close(); + + { + // carol's "middle" page is present and now has a NextPageMin field. + auto const lastPageKeylet = keylet::nftpage_max(carol); + auto carolMiddleNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(carol), carolMiddleNFTokenPageIndex)); + if (!BEAST_EXPECT(carolMiddleNFTokenPage)) + return; + + BEAST_EXPECT( + carolMiddleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT( + carolMiddleNFTokenPage->isFieldPresent(sfNextPageMin) && + carolMiddleNFTokenPage->at(sfNextPageMin) == + lastPageKeylet.key); + + // carol has a "last" page that includes a PreviousPageMin field. + auto carolLastNFTokenPage = env.le(lastPageKeylet); + if (!BEAST_EXPECT(carolLastNFTokenPage)) + return; + + BEAST_EXPECT( + carolLastNFTokenPage->isFieldPresent(sfPreviousPageMin) && + carolLastNFTokenPage->at(sfPreviousPageMin) == + carolMiddleNFTokenPageIndex); + BEAST_EXPECT(!carolLastNFTokenPage->isFieldPresent(sfNextPageMin)); + + // carol also has a "first" page that includes a NextPageMin field. + auto carolFirstNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(carol), + carolMiddleNFTokenPage->at(sfPreviousPageMin))); + if (!BEAST_EXPECT(carolFirstNFTokenPage)) + return; + + BEAST_EXPECT( + carolFirstNFTokenPage->isFieldPresent(sfNextPageMin) && + carolFirstNFTokenPage->at(sfNextPageMin) == + carolMiddleNFTokenPageIndex); + BEAST_EXPECT( + !carolFirstNFTokenPage->isFieldPresent(sfPreviousPageMin)); + } + + // With the link repair, the server knows that carol has 96 NFTs. + BEAST_EXPECT(nftCount(env, carol) == 96); + BEAST_EXPECT(ownerCount(env, carol) == 3); + } + +public: + void + run() override + { + testLedgerStateFixErrors(); + testTokenPageLinkErrors(); + testFixNFTokenPageLinks(); + } +}; + +BEAST_DEFINE_TESTSUITE(FixNFTokenPageLinks, tx, ripple); + +} // namespace ripple diff --git a/src/test/app/NFTokenBurn_test.cpp b/src/test/app/NFTokenBurn_test.cpp index 8219889b4be..35a8858f868 100644 --- a/src/test/app/NFTokenBurn_test.cpp +++ b/src/test/app/NFTokenBurn_test.cpp @@ -80,6 +80,73 @@ class NFTokenBurnBaseUtil_test : public beast::unit_test::suite return nftokenID; }; + // printNFTPages is a helper function that may be used for debugging. + // + // It uses the ledger RPC command to show the NFT pages in the ledger. + // This parameter controls how noisy the output is. + enum Volume : bool { + quiet = false, + noisy = true, + }; + + void + printNFTPages(test::jtx::Env& env, Volume vol) + { + Json::Value jvParams; + jvParams[jss::ledger_index] = "current"; + jvParams[jss::binary] = false; + { + Json::Value jrr = env.rpc( + "json", + "ledger_data", + boost::lexical_cast(jvParams)); + + // Iterate the state and print all NFTokenPages. + if (!jrr.isMember(jss::result) || + !jrr[jss::result].isMember(jss::state)) + { + std::cout << "No ledger state found!" << std::endl; + return; + } + Json::Value& state = jrr[jss::result][jss::state]; + if (!state.isArray()) + { + std::cout << "Ledger state is not array!" << std::endl; + return; + } + for (Json::UInt i = 0; i < state.size(); ++i) + { + if (state[i].isMember(sfNFTokens.jsonName) && + state[i][sfNFTokens.jsonName].isArray()) + { + std::uint32_t tokenCount = + state[i][sfNFTokens.jsonName].size(); + std::cout << tokenCount << " NFtokens in page " + << state[i][jss::index].asString() << std::endl; + + if (vol == noisy) + { + std::cout << state[i].toStyledString() << std::endl; + } + else + { + if (tokenCount > 0) + std::cout << "first: " + << state[i][sfNFTokens.jsonName][0u] + .toStyledString() + << std::endl; + if (tokenCount > 1) + std::cout + << "last: " + << state[i][sfNFTokens.jsonName][tokenCount - 1] + .toStyledString() + << std::endl; + } + } + } + } + } + void testBurnRandom(FeatureBitset features) { @@ -297,76 +364,10 @@ class NFTokenBurnBaseUtil_test : public beast::unit_test::suite Env env{*this, features}; env.fund(XRP(1000), alice); - // printNFTPages is a lambda that may be used for debugging. - // - // It uses the ledger RPC command to show the NFT pages in the ledger. - // This parameter controls how noisy the output is. - enum Volume : bool { - quiet = false, - noisy = true, - }; - - [[maybe_unused]] auto printNFTPages = [&env](Volume vol) { - Json::Value jvParams; - jvParams[jss::ledger_index] = "current"; - jvParams[jss::binary] = false; - { - Json::Value jrr = env.rpc( - "json", - "ledger_data", - boost::lexical_cast(jvParams)); - - // Iterate the state and print all NFTokenPages. - if (!jrr.isMember(jss::result) || - !jrr[jss::result].isMember(jss::state)) - { - std::cout << "No ledger state found!" << std::endl; - return; - } - Json::Value& state = jrr[jss::result][jss::state]; - if (!state.isArray()) - { - std::cout << "Ledger state is not array!" << std::endl; - return; - } - for (Json::UInt i = 0; i < state.size(); ++i) - { - if (state[i].isMember(sfNFTokens.jsonName) && - state[i][sfNFTokens.jsonName].isArray()) - { - std::uint32_t tokenCount = - state[i][sfNFTokens.jsonName].size(); - std::cout << tokenCount << " NFTokens in page " - << state[i][jss::index].asString() - << std::endl; - - if (vol == noisy) - { - std::cout << state[i].toStyledString() << std::endl; - } - else - { - if (tokenCount > 0) - std::cout << "first: " - << state[i][sfNFTokens.jsonName][0u] - .toStyledString() - << std::endl; - if (tokenCount > 1) - std::cout << "last: " - << state[i][sfNFTokens.jsonName] - [tokenCount - 1] - .toStyledString() - << std::endl; - } - } - } - } - }; - // A lambda that generates 96 nfts packed into three pages of 32 each. - auto genPackedTokens = [this, &env, &alice]( - std::vector& nfts) { - nfts.clear(); + // Returns a sorted vector of the NFTokenIDs packed into the pages. + auto genPackedTokens = [this, &env, &alice]() { + std::vector nfts; nfts.reserve(96); // We want to create fully packed NFT pages. This is a little @@ -441,23 +442,24 @@ class NFTokenBurnBaseUtil_test : public beast::unit_test::suite // has changed. BEAST_EXPECT(pageCount == 3); } + return nfts; }; - - // Generate three packed pages. Then burn the tokens in order from - // first to last. This exercises specific cases where coalescing - // pages is not possible. - std::vector nfts; - genPackedTokens(nfts); - BEAST_EXPECT(nftCount(env, alice) == 96); - BEAST_EXPECT(ownerCount(env, alice) == 3); - - for (uint256 const& nft : nfts) { - env(token::burn(alice, {nft})); - env.close(); + // Generate three packed pages. Then burn the tokens in order from + // first to last. This exercises specific cases where coalescing + // pages is not possible. + std::vector nfts = genPackedTokens(); + BEAST_EXPECT(nftCount(env, alice) == 96); + BEAST_EXPECT(ownerCount(env, alice) == 3); + + for (uint256 const& nft : nfts) + { + env(token::burn(alice, {nft})); + env.close(); + } + BEAST_EXPECT(nftCount(env, alice) == 0); + BEAST_EXPECT(ownerCount(env, alice) == 0); } - BEAST_EXPECT(nftCount(env, alice) == 0); - BEAST_EXPECT(ownerCount(env, alice) == 0); // A lambda verifies that the ledger no longer contains any NFT pages. auto checkNoTokenPages = [this, &env]() { @@ -479,48 +481,421 @@ class NFTokenBurnBaseUtil_test : public beast::unit_test::suite } }; checkNoTokenPages(); + { + // Generate three packed pages. Then burn the tokens in order from + // last to first. This exercises different specific cases where + // coalescing pages is not possible. + std::vector nfts = genPackedTokens(); + BEAST_EXPECT(nftCount(env, alice) == 96); + BEAST_EXPECT(ownerCount(env, alice) == 3); + + // Verify that that all three pages are present and remember the + // indexes. + auto lastNFTokenPage = env.le(keylet::nftpage_max(alice)); + if (!BEAST_EXPECT(lastNFTokenPage)) + return; + + uint256 const middleNFTokenPageIndex = + lastNFTokenPage->at(sfPreviousPageMin); + auto middleNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), middleNFTokenPageIndex)); + if (!BEAST_EXPECT(middleNFTokenPage)) + return; + + uint256 const firstNFTokenPageIndex = + middleNFTokenPage->at(sfPreviousPageMin); + auto firstNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), firstNFTokenPageIndex)); + if (!BEAST_EXPECT(firstNFTokenPage)) + return; + + // Burn almost all the tokens in the very last page. + for (int i = 0; i < 31; ++i) + { + env(token::burn(alice, {nfts.back()})); + nfts.pop_back(); + env.close(); + } - // Generate three packed pages. Then burn the tokens in order from - // last to first. This exercises different specific cases where - // coalescing pages is not possible. - genPackedTokens(nfts); - BEAST_EXPECT(nftCount(env, alice) == 96); - BEAST_EXPECT(ownerCount(env, alice) == 3); + // Verify that the last page is still present and contains just one + // NFT. + lastNFTokenPage = env.le(keylet::nftpage_max(alice)); + if (!BEAST_EXPECT(lastNFTokenPage)) + return; - std::reverse(nfts.begin(), nfts.end()); - for (uint256 const& nft : nfts) - { - env(token::burn(alice, {nft})); + BEAST_EXPECT( + lastNFTokenPage->getFieldArray(sfNFTokens).size() == 1); + BEAST_EXPECT(lastNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!lastNFTokenPage->isFieldPresent(sfNextPageMin)); + + // Delete the last token from the last page. + env(token::burn(alice, {nfts.back()})); + nfts.pop_back(); env.close(); + + if (features[fixNFTokenPageLinks]) + { + // Removing the last token from the last page deletes the + // _previous_ page because we need to preserve that last + // page an an anchor. The contents of the next-to-last page + // are moved into the last page. + lastNFTokenPage = env.le(keylet::nftpage_max(alice)); + BEAST_EXPECT(lastNFTokenPage); + BEAST_EXPECT( + lastNFTokenPage->at(~sfPreviousPageMin) == + firstNFTokenPageIndex); + BEAST_EXPECT(!lastNFTokenPage->isFieldPresent(sfNextPageMin)); + BEAST_EXPECT( + lastNFTokenPage->getFieldArray(sfNFTokens).size() == 32); + + // The "middle" page should be gone. + middleNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), middleNFTokenPageIndex)); + BEAST_EXPECT(!middleNFTokenPage); + + // The "first" page should still be present and linked to + // the last page. + firstNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), firstNFTokenPageIndex)); + BEAST_EXPECT(firstNFTokenPage); + BEAST_EXPECT( + !firstNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT( + firstNFTokenPage->at(~sfNextPageMin) == + lastNFTokenPage->key()); + BEAST_EXPECT( + lastNFTokenPage->getFieldArray(sfNFTokens).size() == 32); + } + else + { + // Removing the last token from the last page deletes the last + // page. This is a bug. The contents of the next-to-last page + // should have been moved into the last page. + lastNFTokenPage = env.le(keylet::nftpage_max(alice)); + BEAST_EXPECT(!lastNFTokenPage); + + // The "middle" page is still present, but has lost the + // NextPageMin field. + middleNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), middleNFTokenPageIndex)); + if (!BEAST_EXPECT(middleNFTokenPage)) + return; + BEAST_EXPECT( + middleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!middleNFTokenPage->isFieldPresent(sfNextPageMin)); + } + + // Delete the rest of the NFTokens. + while (!nfts.empty()) + { + env(token::burn(alice, {nfts.back()})); + nfts.pop_back(); + env.close(); + } + BEAST_EXPECT(nftCount(env, alice) == 0); + BEAST_EXPECT(ownerCount(env, alice) == 0); + } + checkNoTokenPages(); + { + // Generate three packed pages. Then burn all tokens in the middle + // page. This exercises the case where a page is removed between + // two fully populated pages. + std::vector nfts = genPackedTokens(); + BEAST_EXPECT(nftCount(env, alice) == 96); + BEAST_EXPECT(ownerCount(env, alice) == 3); + + // Verify that that all three pages are present and remember the + // indexes. + auto lastNFTokenPage = env.le(keylet::nftpage_max(alice)); + if (!BEAST_EXPECT(lastNFTokenPage)) + return; + + uint256 const middleNFTokenPageIndex = + lastNFTokenPage->at(sfPreviousPageMin); + auto middleNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), middleNFTokenPageIndex)); + if (!BEAST_EXPECT(middleNFTokenPage)) + return; + + uint256 const firstNFTokenPageIndex = + middleNFTokenPage->at(sfPreviousPageMin); + auto firstNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), firstNFTokenPageIndex)); + if (!BEAST_EXPECT(firstNFTokenPage)) + return; + + for (std::size_t i = 32; i < 64; ++i) + { + env(token::burn(alice, nfts[i])); + env.close(); + } + nfts.erase(nfts.begin() + 32, nfts.begin() + 64); + BEAST_EXPECT(nftCount(env, alice) == 64); + BEAST_EXPECT(ownerCount(env, alice) == 2); + + // Verify that middle page is gone and the links in the two + // remaining pages are correct. + middleNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), middleNFTokenPageIndex)); + BEAST_EXPECT(!middleNFTokenPage); + + lastNFTokenPage = env.le(keylet::nftpage_max(alice)); + BEAST_EXPECT(!lastNFTokenPage->isFieldPresent(sfNextPageMin)); + BEAST_EXPECT( + lastNFTokenPage->getFieldH256(sfPreviousPageMin) == + firstNFTokenPageIndex); + + firstNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), firstNFTokenPageIndex)); + BEAST_EXPECT( + firstNFTokenPage->getFieldH256(sfNextPageMin) == + keylet::nftpage_max(alice).key); + BEAST_EXPECT(!firstNFTokenPage->isFieldPresent(sfPreviousPageMin)); + + // Burn the remaining nfts. + for (uint256 const& nft : nfts) + { + env(token::burn(alice, {nft})); + env.close(); + } + BEAST_EXPECT(nftCount(env, alice) == 0); + BEAST_EXPECT(ownerCount(env, alice) == 0); } - BEAST_EXPECT(nftCount(env, alice) == 0); - BEAST_EXPECT(ownerCount(env, alice) == 0); checkNoTokenPages(); + { + // Generate three packed pages. Then burn all the tokens in the + // first page followed by all the tokens in the last page. This + // exercises a specific case where coalescing pages is not possible. + std::vector nfts = genPackedTokens(); + BEAST_EXPECT(nftCount(env, alice) == 96); + BEAST_EXPECT(ownerCount(env, alice) == 3); + + // Verify that that all three pages are present and remember the + // indexes. + auto lastNFTokenPage = env.le(keylet::nftpage_max(alice)); + if (!BEAST_EXPECT(lastNFTokenPage)) + return; + + uint256 const middleNFTokenPageIndex = + lastNFTokenPage->at(sfPreviousPageMin); + auto middleNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), middleNFTokenPageIndex)); + if (!BEAST_EXPECT(middleNFTokenPage)) + return; + + uint256 const firstNFTokenPageIndex = + middleNFTokenPage->at(sfPreviousPageMin); + auto firstNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), firstNFTokenPageIndex)); + if (!BEAST_EXPECT(firstNFTokenPage)) + return; + + // Burn all the tokens in the first page. + std::reverse(nfts.begin(), nfts.end()); + for (int i = 0; i < 32; ++i) + { + env(token::burn(alice, {nfts.back()})); + nfts.pop_back(); + env.close(); + } - // Generate three packed pages. Then burn all tokens in the middle - // page. This exercises the case where a page is removed between - // two fully populated pages. - genPackedTokens(nfts); - BEAST_EXPECT(nftCount(env, alice) == 96); - BEAST_EXPECT(ownerCount(env, alice) == 3); + // Verify the first page is gone. + firstNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), firstNFTokenPageIndex)); + BEAST_EXPECT(!firstNFTokenPage); + + // Check the links in the other two pages. + middleNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), middleNFTokenPageIndex)); + if (!BEAST_EXPECT(middleNFTokenPage)) + return; + BEAST_EXPECT(!middleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(middleNFTokenPage->isFieldPresent(sfNextPageMin)); + + lastNFTokenPage = env.le(keylet::nftpage_max(alice)); + if (!BEAST_EXPECT(lastNFTokenPage)) + return; + BEAST_EXPECT(lastNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!lastNFTokenPage->isFieldPresent(sfNextPageMin)); + + // Burn all the tokens in the last page. + std::reverse(nfts.begin(), nfts.end()); + for (int i = 0; i < 32; ++i) + { + env(token::burn(alice, {nfts.back()})); + nfts.pop_back(); + env.close(); + } - for (std::size_t i = 32; i < 64; ++i) - { - env(token::burn(alice, nfts[i])); - env.close(); + if (features[fixNFTokenPageLinks]) + { + // Removing the last token from the last page deletes the + // _previous_ page because we need to preserve that last + // page an an anchor. The contents of the next-to-last page + // are moved into the last page. + lastNFTokenPage = env.le(keylet::nftpage_max(alice)); + BEAST_EXPECT(lastNFTokenPage); + BEAST_EXPECT( + !lastNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!lastNFTokenPage->isFieldPresent(sfNextPageMin)); + BEAST_EXPECT( + lastNFTokenPage->getFieldArray(sfNFTokens).size() == 32); + + // The "middle" page should be gone. + middleNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), middleNFTokenPageIndex)); + BEAST_EXPECT(!middleNFTokenPage); + + // The "first" page should still be gone. + firstNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), firstNFTokenPageIndex)); + BEAST_EXPECT(!firstNFTokenPage); + } + else + { + // Removing the last token from the last page deletes the last + // page. This is a bug. The contents of the next-to-last page + // should have been moved into the last page. + lastNFTokenPage = env.le(keylet::nftpage_max(alice)); + BEAST_EXPECT(!lastNFTokenPage); + + // The "middle" page is still present, but has lost the + // NextPageMin field. + middleNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), middleNFTokenPageIndex)); + if (!BEAST_EXPECT(middleNFTokenPage)) + return; + BEAST_EXPECT( + !middleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!middleNFTokenPage->isFieldPresent(sfNextPageMin)); + } + + // Delete the rest of the NFTokens. + while (!nfts.empty()) + { + env(token::burn(alice, {nfts.back()})); + nfts.pop_back(); + env.close(); + } + BEAST_EXPECT(nftCount(env, alice) == 0); + BEAST_EXPECT(ownerCount(env, alice) == 0); } - nfts.erase(nfts.begin() + 32, nfts.begin() + 64); - BEAST_EXPECT(nftCount(env, alice) == 64); - BEAST_EXPECT(ownerCount(env, alice) == 2); + checkNoTokenPages(); - // Burn the remaining nfts. - for (uint256 const& nft : nfts) + if (features[fixNFTokenPageLinks]) { - env(token::burn(alice, {nft})); - env.close(); + // Exercise the invariant that the final NFTokenPage of a directory + // may not be removed if there are NFTokens in other pages of the + // directory. + // + // We're going to fire an Invariant failure that is difficult to + // cause. We do it here because the tools are here. + // + // See Invariants_test.cpp for examples of other invariant tests + // that this one is modeled after. + + // Generate three closely packed NFTokenPages. + std::vector nfts = genPackedTokens(); + BEAST_EXPECT(nftCount(env, alice) == 96); + BEAST_EXPECT(ownerCount(env, alice) == 3); + + // Burn almost all the tokens in the very last page. + for (int i = 0; i < 31; ++i) + { + env(token::burn(alice, {nfts.back()})); + nfts.pop_back(); + env.close(); + } + { + // Create an ApplyContext we can use to run the invariant + // checks. These variables must outlive the ApplyContext. + OpenView ov{*env.current()}; + STTx tx{ttACCOUNT_SET, [](STObject&) {}}; + test::StreamSink sink{beast::severities::kWarning}; + beast::Journal jlog{sink}; + ApplyContext ac{ + env.app(), + ov, + tx, + tesSUCCESS, + env.current()->fees().base, + tapNONE, + jlog}; + + // Verify that the last page is present and contains one NFT. + auto lastNFTokenPage = + ac.view().peek(keylet::nftpage_max(alice)); + if (!BEAST_EXPECT(lastNFTokenPage)) + return; + BEAST_EXPECT( + lastNFTokenPage->getFieldArray(sfNFTokens).size() == 1); + + // Erase that last page. + ac.view().erase(lastNFTokenPage); + + // Exercise the invariant. + TER terActual = tesSUCCESS; + for (TER const& terExpect : + {TER(tecINVARIANT_FAILED), TER(tefINVARIANT_FAILED)}) + { + terActual = ac.checkInvariants(terActual, XRPAmount{}); + BEAST_EXPECT(terExpect == terActual); + BEAST_EXPECT( + sink.messages().str().starts_with("Invariant failed:")); + // uncomment to log the invariant failure message + // log << " --> " << sink.messages().str() << std::endl; + BEAST_EXPECT( + sink.messages().str().find( + "Last NFT page deleted with non-empty directory") != + std::string::npos); + } + } + { + // Create an ApplyContext we can use to run the invariant + // checks. These variables must outlive the ApplyContext. + OpenView ov{*env.current()}; + STTx tx{ttACCOUNT_SET, [](STObject&) {}}; + test::StreamSink sink{beast::severities::kWarning}; + beast::Journal jlog{sink}; + ApplyContext ac{ + env.app(), + ov, + tx, + tesSUCCESS, + env.current()->fees().base, + tapNONE, + jlog}; + + // Verify that the middle page is present. + auto lastNFTokenPage = + ac.view().peek(keylet::nftpage_max(alice)); + auto middleNFTokenPage = ac.view().peek(keylet::nftpage( + keylet::nftpage_min(alice), + lastNFTokenPage->getFieldH256(sfPreviousPageMin))); + BEAST_EXPECT(middleNFTokenPage); + + // Remove the NextMinPage link from the middle page to fire + // the invariant. + middleNFTokenPage->makeFieldAbsent(sfNextPageMin); + ac.view().update(middleNFTokenPage); + + // Exercise the invariant. + TER terActual = tesSUCCESS; + for (TER const& terExpect : + {TER(tecINVARIANT_FAILED), TER(tefINVARIANT_FAILED)}) + { + terActual = ac.checkInvariants(terActual, XRPAmount{}); + BEAST_EXPECT(terExpect == terActual); + BEAST_EXPECT( + sink.messages().str().starts_with("Invariant failed:")); + // uncomment to log the invariant failure message + // log << " --> " << sink.messages().str() << std::endl; + BEAST_EXPECT( + sink.messages().str().find("Lost NextMinPage link") != + std::string::npos); + } + } } - BEAST_EXPECT(nftCount(env, alice) == 0); - checkNoTokenPages(); } void @@ -778,12 +1153,238 @@ class NFTokenBurnBaseUtil_test : public beast::unit_test::suite } } + void + exerciseBrokenLinks(FeatureBitset features) + { + // Amendment fixNFTokenPageLinks prevents the breakage we want + // to observe. + if (features[fixNFTokenPageLinks]) + return; + + // a couple of directory merging scenarios that can only be tested by + // inserting and deleting in an ordered fashion. We do that testing + // now. + testcase("Exercise broken links"); + + using namespace test::jtx; + + Account const alice{"alice"}; + Account const minter{"minter"}; + + Env env{*this, features}; + env.fund(XRP(1000), alice, minter); + + // A lambda that generates 96 nfts packed into three pages of 32 each. + // Returns a sorted vector of the NFTokenIDs packed into the pages. + auto genPackedTokens = [this, &env, &alice, &minter]() { + std::vector nfts; + nfts.reserve(96); + + // We want to create fully packed NFT pages. This is a little + // tricky since the system currently in place is inclined to + // assign consecutive tokens to only 16 entries per page. + // + // By manipulating the internal form of the taxon we can force + // creation of NFT pages that are completely full. This lambda + // tells us the taxon value we should pass in in order for the + // internal representation to match the passed in value. + auto internalTaxon = [&env]( + Account const& acct, + std::uint32_t taxon) -> std::uint32_t { + std::uint32_t tokenSeq = + env.le(acct)->at(~sfMintedNFTokens).value_or(0); + + // If fixNFTokenRemint amendment is on, we must + // add FirstNFTokenSequence. + if (env.current()->rules().enabled(fixNFTokenRemint)) + tokenSeq += env.le(acct) + ->at(~sfFirstNFTokenSequence) + .value_or(env.seq(acct)); + + return toUInt32( + nft::cipheredTaxon(tokenSeq, nft::toTaxon(taxon))); + }; + + for (std::uint32_t i = 0; i < 96; ++i) + { + // In order to fill the pages we use the taxon to break them + // into groups of 16 entries. By having the internal + // representation of the taxon go... + // 0, 3, 2, 5, 4, 7... + // in sets of 16 NFTs we can get each page to be fully + // populated. + std::uint32_t const intTaxon = (i / 16) + (i & 0b10000 ? 2 : 0); + uint32_t const extTaxon = internalTaxon(minter, intTaxon); + nfts.push_back( + token::getNextID(env, minter, extTaxon, tfTransferable)); + env(token::mint(minter, extTaxon), txflags(tfTransferable)); + env.close(); + + // Minter creates an offer for the NFToken. + uint256 const minterOfferIndex = + keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nfts.back(), XRP(0)), + txflags(tfSellNFToken)); + env.close(); + + // alice accepts the offer. + env(token::acceptSellOffer(alice, minterOfferIndex)); + env.close(); + } + + // Sort the NFTs so they are listed in storage order, not + // creation order. + std::sort(nfts.begin(), nfts.end()); + + // Verify that the ledger does indeed contain exactly three pages + // of NFTs with 32 entries in each page. + Json::Value jvParams; + jvParams[jss::ledger_index] = "current"; + jvParams[jss::binary] = false; + { + Json::Value jrr = env.rpc( + "json", + "ledger_data", + boost::lexical_cast(jvParams)); + + Json::Value& state = jrr[jss::result][jss::state]; + + int pageCount = 0; + for (Json::UInt i = 0; i < state.size(); ++i) + { + if (state[i].isMember(sfNFTokens.jsonName) && + state[i][sfNFTokens.jsonName].isArray()) + { + BEAST_EXPECT( + state[i][sfNFTokens.jsonName].size() == 32); + ++pageCount; + } + } + // If this check fails then the internal NFT directory logic + // has changed. + BEAST_EXPECT(pageCount == 3); + } + return nfts; + }; + + // Generate three packed pages. + std::vector nfts = genPackedTokens(); + BEAST_EXPECT(nftCount(env, alice) == 96); + BEAST_EXPECT(ownerCount(env, alice) == 3); + + // Verify that that all three pages are present and remember the + // indexes. + auto lastNFTokenPage = env.le(keylet::nftpage_max(alice)); + if (!BEAST_EXPECT(lastNFTokenPage)) + return; + + uint256 const middleNFTokenPageIndex = + lastNFTokenPage->at(sfPreviousPageMin); + auto middleNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), middleNFTokenPageIndex)); + if (!BEAST_EXPECT(middleNFTokenPage)) + return; + + uint256 const firstNFTokenPageIndex = + middleNFTokenPage->at(sfPreviousPageMin); + auto firstNFTokenPage = env.le( + keylet::nftpage(keylet::nftpage_min(alice), firstNFTokenPageIndex)); + if (!BEAST_EXPECT(firstNFTokenPage)) + return; + + // Sell all the tokens in the very last page back to minter. + std::vector last32NFTs; + for (int i = 0; i < 32; ++i) + { + last32NFTs.push_back(nfts.back()); + nfts.pop_back(); + + // alice creates an offer for the NFToken. + uint256 const aliceOfferIndex = + keylet::nftoffer(alice, env.seq(alice)).key; + env(token::createOffer(alice, last32NFTs.back(), XRP(0)), + txflags(tfSellNFToken)); + env.close(); + + // minter accepts the offer. + env(token::acceptSellOffer(minter, aliceOfferIndex)); + env.close(); + } + + // Removing the last token from the last page deletes alice's last + // page. This is a bug. The contents of the next-to-last page + // should have been moved into the last page. + lastNFTokenPage = env.le(keylet::nftpage_max(alice)); + BEAST_EXPECT(!lastNFTokenPage); + BEAST_EXPECT(ownerCount(env, alice) == 2); + + // The "middle" page is still present, but has lost the + // NextPageMin field. + middleNFTokenPage = env.le(keylet::nftpage( + keylet::nftpage_min(alice), middleNFTokenPageIndex)); + if (!BEAST_EXPECT(middleNFTokenPage)) + return; + BEAST_EXPECT(middleNFTokenPage->isFieldPresent(sfPreviousPageMin)); + BEAST_EXPECT(!middleNFTokenPage->isFieldPresent(sfNextPageMin)); + + // Attempt to delete alice's account, but fail because she owns NFTs. + auto const acctDelFee{drops(env.current()->fees().increment)}; + env(acctdelete(alice, minter), + fee(acctDelFee), + ter(tecHAS_OBLIGATIONS)); + env.close(); + + // minter sells the last 32 NFTs back to alice. + for (uint256 nftID : last32NFTs) + { + // minter creates an offer for the NFToken. + uint256 const minterOfferIndex = + keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftID, XRP(0)), + txflags(tfSellNFToken)); + env.close(); + + // alice accepts the offer. + env(token::acceptSellOffer(alice, minterOfferIndex)); + env.close(); + } + BEAST_EXPECT(ownerCount(env, alice) == 3); // Three NFTokenPages. + + // alice has an NFToken directory with a broken link in the middle. + { + // Try the account_objects RPC command. Alice's account only shows + // two NFT pages even though she owns more. + Json::Value acctObjs = [&env, &alice]() { + Json::Value params; + params[jss::account] = alice.human(); + return env.rpc("json", "account_objects", to_string(params)); + }(); + BEAST_EXPECT(!acctObjs.isMember(jss::marker)); + BEAST_EXPECT( + acctObjs[jss::result][jss::account_objects].size() == 2); + } + { + // Try the account_nfts RPC command. It only returns 64 NFTs + // although alice owns 96. + Json::Value aliceNFTs = [&env, &alice]() { + Json::Value params; + params[jss::account] = alice.human(); + params[jss::type] = "state"; + return env.rpc("json", "account_nfts", to_string(params)); + }(); + BEAST_EXPECT(!aliceNFTs.isMember(jss::marker)); + BEAST_EXPECT( + aliceNFTs[jss::result][jss::account_nfts].size() == 64); + } + } + void testWithFeats(FeatureBitset features) { testBurnRandom(features); testBurnSequential(features); testBurnTooManyOffers(features); + exerciseBrokenLinks(features); } protected: @@ -792,13 +1393,18 @@ class NFTokenBurnBaseUtil_test : public beast::unit_test::suite { using namespace test::jtx; static FeatureBitset const all{supported_amendments()}; + static FeatureBitset const fixNFTV1_2{fixNonFungibleTokensV1_2}; static FeatureBitset const fixNFTDir{fixNFTokenDirV1}; - - static std::array const feats{ - all - fixNonFungibleTokensV1_2 - fixNFTDir - fixNFTokenRemint, - all - fixNonFungibleTokensV1_2 - fixNFTokenRemint, - all - fixNFTokenRemint, - all}; + static FeatureBitset const fixNFTRemint{fixNFTokenRemint}; + static FeatureBitset const fixNFTPageLinks{fixNFTokenPageLinks}; + + static std::array const feats{ + all - fixNFTV1_2 - fixNFTDir - fixNFTRemint - fixNFTPageLinks, + all - fixNFTV1_2 - fixNFTRemint - fixNFTPageLinks, + all - fixNFTRemint - fixNFTPageLinks, + all - fixNFTPageLinks, + all, + }; if (BEAST_EXPECT(instance < feats.size())) { @@ -835,19 +1441,30 @@ class NFTokenBurnWOFixTokenRemint_test : public NFTokenBurnBaseUtil_test } }; +class NFTokenBurnWOFixNFTPageLinks_test : public NFTokenBurnBaseUtil_test +{ +public: + void + run() override + { + NFTokenBurnBaseUtil_test::run(3); + } +}; + class NFTokenBurnAllFeatures_test : public NFTokenBurnBaseUtil_test { public: void run() override { - NFTokenBurnBaseUtil_test::run(3, true); + NFTokenBurnBaseUtil_test::run(4, true); } }; BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBurnBaseUtil, tx, ripple, 3); BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBurnWOfixFungTokens, tx, ripple, 3); BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBurnWOFixTokenRemint, tx, ripple, 3); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBurnWOFixNFTPageLinks, tx, ripple, 3); BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBurnAllFeatures, tx, ripple, 3); } // namespace ripple diff --git a/src/test/jtx.h b/src/test/jtx.h index a3255ef3af9..6de7cd480fa 100644 --- a/src/test/jtx.h +++ b/src/test/jtx.h @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include diff --git a/src/test/jtx/impl/ledgerStateFix.cpp b/src/test/jtx/impl/ledgerStateFix.cpp new file mode 100644 index 00000000000..2f121dc2671 --- /dev/null +++ b/src/test/jtx/impl/ledgerStateFix.cpp @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 + +#include +#include +#include + +namespace ripple { +namespace test { +namespace jtx { + +namespace ledgerStateFix { + +// Fix NFTokenPage links on owner's account. acct pays fee. +Json::Value +nftPageLinks(jtx::Account const& acct, jtx::Account const& owner) +{ + Json::Value jv; + jv[sfAccount.jsonName] = acct.human(); + jv[sfLedgerFixType.jsonName] = LedgerStateFix::nfTokenPageLink; + jv[sfOwner.jsonName] = owner.human(); + jv[sfTransactionType.jsonName] = jss::LedgerStateFix; + jv[sfFlags.jsonName] = tfUniversal; + return jv; +} + +} // namespace ledgerStateFix + +} // namespace jtx +} // namespace test +} // namespace ripple diff --git a/src/test/jtx/ledgerStateFix.h b/src/test/jtx/ledgerStateFix.h new file mode 100644 index 00000000000..bf0a56cabe3 --- /dev/null +++ b/src/test/jtx/ledgerStateFix.h @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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_TEST_JTX_LEDGER_STATE_FIX_H_INCLUDED +#define RIPPLE_TEST_JTX_LEDGER_STATE_FIX_H_INCLUDED + +#include +#include + +namespace ripple { +namespace test { +namespace jtx { + +/** LedgerStateFix operations. */ +namespace ledgerStateFix { + +/** Repair the links in an NFToken directory. */ +Json::Value +nftPageLinks(jtx::Account const& acct, jtx::Account const& owner); + +} // namespace ledgerStateFix + +} // namespace jtx + +} // namespace test +} // namespace ripple + +#endif diff --git a/src/test/ledger/Invariants_test.cpp b/src/test/ledger/Invariants_test.cpp index 66523700a88..8d7b08fa1ab 100644 --- a/src/test/ledger/Invariants_test.cpp +++ b/src/test/ledger/Invariants_test.cpp @@ -24,7 +24,9 @@ #include #include #include +#include #include + #include namespace ripple { @@ -110,10 +112,9 @@ class Invariants_test : public beast::unit_test::suite terActual = ac.checkInvariants(terActual, fee); BEAST_EXPECT(terExpect == terActual); BEAST_EXPECT( - boost::starts_with( - sink.messages().str(), "Invariant failed:") || - boost::starts_with( - sink.messages().str(), "Transaction caused an exception")); + sink.messages().str().starts_with("Invariant failed:") || + sink.messages().str().starts_with( + "Transaction caused an exception")); // uncomment if you want to log the invariant failure message // log << " --> " << sink.messages().str() << std::endl; for (auto const& m : expect_logs) @@ -650,6 +651,153 @@ class Invariants_test : public beast::unit_test::suite STTx{ttPAYMENT, [](STObject& tx) {}}); } + void + testNFTokenPageInvariants() + { + using namespace test::jtx; + testcase << "NFTokenPage"; + + // lambda that returns an STArray of NFTokenIDs. + uint256 const firstNFTID( + "0000000000000000000000000000000000000001FFFFFFFFFFFFFFFF00000000"); + auto makeNFTokenIDs = [&firstNFTID](unsigned int nftCount) { + SOTemplate const* nfTokenTemplate = + InnerObjectFormats::getInstance().findSOTemplateBySField( + sfNFToken); + + uint256 nftID(firstNFTID); + STArray ret; + for (int i = 0; i < nftCount; ++i) + { + STObject newNFToken( + *nfTokenTemplate, sfNFToken, [&nftID](STObject& object) { + object.setFieldH256(sfNFTokenID, nftID); + }); + ret.push_back(std::move(newNFToken)); + ++nftID; + } + return ret; + }; + + doInvariantCheck( + {{"NFT page has invalid size"}}, + [&makeNFTokenIDs]( + Account const& A1, Account const&, ApplyContext& ac) { + auto nftPage = std::make_shared(keylet::nftpage_max(A1)); + nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(0)); + + ac.view().insert(nftPage); + return true; + }); + + doInvariantCheck( + {{"NFT page has invalid size"}}, + [&makeNFTokenIDs]( + Account const& A1, Account const&, ApplyContext& ac) { + auto nftPage = std::make_shared(keylet::nftpage_max(A1)); + nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(33)); + + ac.view().insert(nftPage); + return true; + }); + + doInvariantCheck( + {{"NFTs on page are not sorted"}}, + [&makeNFTokenIDs]( + Account const& A1, Account const&, ApplyContext& ac) { + STArray nfTokens = makeNFTokenIDs(2); + std::iter_swap(nfTokens.begin(), nfTokens.begin() + 1); + + auto nftPage = std::make_shared(keylet::nftpage_max(A1)); + nftPage->setFieldArray(sfNFTokens, nfTokens); + + ac.view().insert(nftPage); + return true; + }); + + doInvariantCheck( + {{"NFT contains empty URI"}}, + [&makeNFTokenIDs]( + Account const& A1, Account const&, ApplyContext& ac) { + STArray nfTokens = makeNFTokenIDs(1); + nfTokens[0].setFieldVL(sfURI, Blob{}); + + auto nftPage = std::make_shared(keylet::nftpage_max(A1)); + nftPage->setFieldArray(sfNFTokens, nfTokens); + + ac.view().insert(nftPage); + return true; + }); + + doInvariantCheck( + {{"NFT page is improperly linked"}}, + [&makeNFTokenIDs]( + Account const& A1, Account const&, ApplyContext& ac) { + auto nftPage = std::make_shared(keylet::nftpage_max(A1)); + nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(1)); + nftPage->setFieldH256( + sfPreviousPageMin, keylet::nftpage_max(A1).key); + + ac.view().insert(nftPage); + return true; + }); + + doInvariantCheck( + {{"NFT page is improperly linked"}}, + [&makeNFTokenIDs]( + Account const& A1, Account const& A2, ApplyContext& ac) { + auto nftPage = std::make_shared(keylet::nftpage_max(A1)); + nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(1)); + nftPage->setFieldH256( + sfPreviousPageMin, keylet::nftpage_min(A2).key); + + ac.view().insert(nftPage); + return true; + }); + + doInvariantCheck( + {{"NFT page is improperly linked"}}, + [&makeNFTokenIDs]( + Account const& A1, Account const&, ApplyContext& ac) { + auto nftPage = std::make_shared(keylet::nftpage_max(A1)); + nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(1)); + nftPage->setFieldH256(sfNextPageMin, nftPage->key()); + + ac.view().insert(nftPage); + return true; + }); + + doInvariantCheck( + {{"NFT page is improperly linked"}}, + [&makeNFTokenIDs]( + Account const& A1, Account const& A2, ApplyContext& ac) { + STArray nfTokens = makeNFTokenIDs(1); + auto nftPage = std::make_shared(keylet::nftpage( + keylet::nftpage_max(A1), + ++(nfTokens[0].getFieldH256(sfNFTokenID)))); + nftPage->setFieldArray(sfNFTokens, std::move(nfTokens)); + nftPage->setFieldH256( + sfNextPageMin, keylet::nftpage_max(A2).key); + + ac.view().insert(nftPage); + return true; + }); + + doInvariantCheck( + {{"NFT found in incorrect page"}}, + [&makeNFTokenIDs]( + Account const& A1, Account const&, ApplyContext& ac) { + STArray nfTokens = makeNFTokenIDs(2); + auto nftPage = std::make_shared(keylet::nftpage( + keylet::nftpage_max(A1), + (nfTokens[1].getFieldH256(sfNFTokenID)))); + nftPage->setFieldArray(sfNFTokens, std::move(nfTokens)); + + ac.view().insert(nftPage); + return true; + }); + } + public: void run() override @@ -664,6 +812,7 @@ class Invariants_test : public beast::unit_test::suite testNoBadOffers(); testNoZeroEscrow(); testValidNewAccountRoot(); + testNFTokenPageInvariants(); } }; diff --git a/src/xrpld/app/tx/detail/InvariantCheck.cpp b/src/xrpld/app/tx/detail/InvariantCheck.cpp index 70210b90d75..f855ad8578c 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.cpp +++ b/src/xrpld/app/tx/detail/InvariantCheck.cpp @@ -612,6 +612,10 @@ ValidNFTokenPage::visitEntry( static constexpr uint256 const& pageBits = nft::pageMask; static constexpr uint256 const accountBits = ~pageBits; + if ((before && before->getType() != ltNFTOKEN_PAGE) || + (after && after->getType() != ltNFTOKEN_PAGE)) + return; + auto check = [this, isDelete](std::shared_ptr const& sle) { uint256 const account = sle->key() & accountBits; uint256 const hiLimit = sle->key() & pageBits; @@ -673,11 +677,37 @@ ValidNFTokenPage::visitEntry( } }; - if (before && before->getType() == ltNFTOKEN_PAGE) + if (before) + { check(before); - if (after && after->getType() == ltNFTOKEN_PAGE) + // While an account's NFToken directory contains any NFTokens, the last + // NFTokenPage (with 96 bits of 1 in the low part of the index) should + // never be deleted. + if (isDelete && (before->key() & nft::pageMask) == nft::pageMask && + before->isFieldPresent(sfPreviousPageMin)) + { + deletedFinalPage_ = true; + } + } + + if (after) check(after); + + if (!isDelete && before && after) + { + // If the NFTokenPage + // 1. Has a NextMinPage field in before, but loses it in after, and + // 2. This is not the last page in the directory + // Then we have identified a corruption in the links between the + // NFToken pages in the NFToken directory. + if ((before->key() & nft::pageMask) != nft::pageMask && + before->isFieldPresent(sfNextPageMin) && + !after->isFieldPresent(sfNextPageMin)) + { + deletedLink_ = true; + } + } } bool @@ -718,6 +748,21 @@ ValidNFTokenPage::finalize( return false; } + if (view.rules().enabled(fixNFTokenPageLinks)) + { + if (deletedFinalPage_) + { + JLOG(j.fatal()) << "Invariant failed: Last NFT page deleted with " + "non-empty directory."; + return false; + } + if (deletedLink_) + { + JLOG(j.fatal()) << "Invariant failed: Lost NextMinPage link."; + return false; + } + } + return true; } diff --git a/src/xrpld/app/tx/detail/InvariantCheck.h b/src/xrpld/app/tx/detail/InvariantCheck.h index 6a83f5c9b7b..1b3234bae69 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.h +++ b/src/xrpld/app/tx/detail/InvariantCheck.h @@ -367,6 +367,8 @@ class ValidNFTokenPage bool badSort_ = false; bool badURI_ = false; bool invalidSize_ = false; + bool deletedFinalPage_ = false; + bool deletedLink_ = false; public: void diff --git a/src/xrpld/app/tx/detail/LedgerStateFix.cpp b/src/xrpld/app/tx/detail/LedgerStateFix.cpp new file mode 100644 index 00000000000..568ed49304a --- /dev/null +++ b/src/xrpld/app/tx/detail/LedgerStateFix.cpp @@ -0,0 +1,99 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 + +#include +#include +#include +#include +#include +#include + +namespace ripple { + +NotTEC +LedgerStateFix::preflight(PreflightContext const& ctx) +{ + if (!ctx.rules.enabled(fixNFTokenPageLinks)) + return temDISABLED; + + if (ctx.tx.getFlags() & tfUniversalMask) + return temINVALID_FLAG; + + if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) + return ret; + + switch (ctx.tx[sfLedgerFixType]) + { + case FixType::nfTokenPageLink: + if (!ctx.tx.isFieldPresent(sfOwner)) + return temINVALID; + break; + + default: + return tefINVALID_LEDGER_FIX_TYPE; + } + + return preflight2(ctx); +} + +XRPAmount +LedgerStateFix::calculateBaseFee(ReadView const& view, STTx const& tx) +{ + // The fee required for LedgerStateFix is one owner reserve, just like + // the fee for AccountDelete. + return view.fees().increment; +} + +TER +LedgerStateFix::preclaim(PreclaimContext const& ctx) +{ + switch (ctx.tx[sfLedgerFixType]) + { + case FixType::nfTokenPageLink: { + AccountID const owner{ctx.tx[sfOwner]}; + if (!ctx.view.read(keylet::account(owner))) + return tecOBJECT_NOT_FOUND; + + return tesSUCCESS; + } + } + + // preflight is supposed to verify that only valid FixTypes get to preclaim. + return tecINTERNAL; +} + +TER +LedgerStateFix::doApply() +{ + switch (ctx_.tx[sfLedgerFixType]) + { + case FixType::nfTokenPageLink: + if (!nft::repairNFTokenDirectoryLinks(view(), ctx_.tx[sfOwner])) + return tecFAILED_PROCESSING; + + return tesSUCCESS; + } + + // preflight is supposed to verify that only valid FixTypes get to doApply. + return tecINTERNAL; +} + +} // namespace ripple diff --git a/src/xrpld/app/tx/detail/LedgerStateFix.h b/src/xrpld/app/tx/detail/LedgerStateFix.h new file mode 100644 index 00000000000..b480d239291 --- /dev/null +++ b/src/xrpld/app/tx/detail/LedgerStateFix.h @@ -0,0 +1,57 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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_TX_LEDGER_STATE_FIX_H_INCLUDED +#define RIPPLE_TX_LEDGER_STATE_FIX_H_INCLUDED + +#include +#include +#include + +namespace ripple { + +class LedgerStateFix : public Transactor +{ +public: + enum FixType : std::uint16_t { + nfTokenPageLink = 1, + }; + + static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; + + explicit LedgerStateFix(ApplyContext& ctx) : Transactor(ctx) + { + } + + static NotTEC + preflight(PreflightContext const& ctx); + + static XRPAmount + calculateBaseFee(ReadView const& view, STTx const& tx); + + static TER + preclaim(PreclaimContext const& ctx); + + TER + doApply() override; +}; + +} // namespace ripple + +#endif diff --git a/src/xrpld/app/tx/detail/NFTokenUtils.cpp b/src/xrpld/app/tx/detail/NFTokenUtils.cpp index 279bf6b9816..61ff8e200b3 100644 --- a/src/xrpld/app/tx/detail/NFTokenUtils.cpp +++ b/src/xrpld/app/tx/detail/NFTokenUtils.cpp @@ -429,10 +429,48 @@ removeToken( return tesSUCCESS; } - // The page is empty, so we can just unlink it and then remove it. if (prev) { - // Make our previous page point to our next page: + // With fixNFTokenPageLinks... + // The page is empty and there is a prev. If the last page of the + // directory is empty then we need to: + // 1. Move the contents of the previous page into the last page. + // 2. Fix up the link from prev's previous page. + // 3. Fix up the owner count. + // 4. Erase the previous page. + if (view.rules().enabled(fixNFTokenPageLinks) && + ((curr->key() & nft::pageMask) == pageMask)) + { + // Copy all relevant information from prev to curr. + curr->peekFieldArray(sfNFTokens) = prev->peekFieldArray(sfNFTokens); + + if (auto const prevLink = prev->at(~sfPreviousPageMin)) + { + curr->at(sfPreviousPageMin) = *prevLink; + + // Also fix up the NextPageMin link in the new Previous. + auto const newPrev = loadPage(curr, sfPreviousPageMin); + newPrev->at(sfNextPageMin) = curr->key(); + view.update(newPrev); + } + else + { + curr->makeFieldAbsent(sfPreviousPageMin); + } + + adjustOwnerCount( + view, + view.peek(keylet::account(owner)), + -1, + beast::Journal{beast::Journal::getNullSink()}); + + view.update(curr); + view.erase(prev); + return tesSUCCESS; + } + + // The page is empty and not the last page, so we can just unlink it + // and then remove it. if (next) prev->setFieldH256(sfNextPageMin, next->key()); else @@ -637,6 +675,124 @@ deleteTokenOffer(ApplyView& view, std::shared_ptr const& offer) return true; } +bool +repairNFTokenDirectoryLinks(ApplyView& view, AccountID const& owner) +{ + bool didRepair = false; + + auto const last = keylet::nftpage_max(owner); + + std::shared_ptr page = view.peek(Keylet( + ltNFTOKEN_PAGE, + view.succ(keylet::nftpage_min(owner).key, last.key.next()) + .value_or(last.key))); + + if (!page) + return didRepair; + + if (page->key() == last.key) + { + // There's only one page in this entire directory. There should be + // no links on that page. + bool const nextPresent = page->isFieldPresent(sfNextPageMin); + bool const prevPresent = page->isFieldPresent(sfPreviousPageMin); + if (nextPresent || prevPresent) + { + didRepair = true; + if (prevPresent) + page->makeFieldAbsent(sfPreviousPageMin); + if (nextPresent) + page->makeFieldAbsent(sfNextPageMin); + view.update(page); + } + return didRepair; + } + + // First page is not the same as last page. The first page should not + // contain a previous link. + if (page->isFieldPresent(sfPreviousPageMin)) + { + didRepair = true; + page->makeFieldAbsent(sfPreviousPageMin); + view.update(page); + } + + std::shared_ptr nextPage; + while ( + (nextPage = view.peek(Keylet( + ltNFTOKEN_PAGE, + view.succ(page->key().next(), last.key.next()) + .value_or(last.key))))) + { + if (!page->isFieldPresent(sfNextPageMin) || + page->getFieldH256(sfNextPageMin) != nextPage->key()) + { + didRepair = true; + page->setFieldH256(sfNextPageMin, nextPage->key()); + view.update(page); + } + + if (!nextPage->isFieldPresent(sfPreviousPageMin) || + nextPage->getFieldH256(sfPreviousPageMin) != page->key()) + { + didRepair = true; + nextPage->setFieldH256(sfPreviousPageMin, page->key()); + view.update(nextPage); + } + + if (nextPage->key() == last.key) + // We need special handling for the last page. + break; + + page = nextPage; + } + + // When we arrive here, nextPage should have the same index as last. + // If not, then that's something we need to fix. + if (!nextPage) + { + // It turns out that page is the last page for this owner, but + // that last page does not have the expected final index. We need + // to move the contents of the current last page into a page with the + // correct index. + // + // The owner count does not need to change because, even though + // we're adding a page, we'll also remove the page that used to be + // last. + didRepair = true; + nextPage = std::make_shared(last); + + // Copy all relevant information from prev to curr. + nextPage->peekFieldArray(sfNFTokens) = page->peekFieldArray(sfNFTokens); + + if (auto const prevLink = page->at(~sfPreviousPageMin)) + { + nextPage->at(sfPreviousPageMin) = *prevLink; + + // Also fix up the NextPageMin link in the new Previous. + auto const newPrev = view.peek(Keylet(ltNFTOKEN_PAGE, *prevLink)); + if (!newPrev) + Throw( + "NFTokenPage directory for " + to_string(owner) + + " cannot be repaired. Unexpected link problem."); + newPrev->at(sfNextPageMin) = nextPage->key(); + view.update(newPrev); + } + view.erase(page); + view.insert(nextPage); + return didRepair; + } + + assert(nextPage); + if (nextPage->isFieldPresent(sfNextPageMin)) + { + didRepair = true; + nextPage->makeFieldAbsent(sfNextPageMin); + view.update(nextPage); + } + return didRepair; +} + NotTEC tokenOfferCreatePreflight( AccountID const& acctID, diff --git a/src/xrpld/app/tx/detail/NFTokenUtils.h b/src/xrpld/app/tx/detail/NFTokenUtils.h index 243c5273399..97d109b8318 100644 --- a/src/xrpld/app/tx/detail/NFTokenUtils.h +++ b/src/xrpld/app/tx/detail/NFTokenUtils.h @@ -95,6 +95,13 @@ removeToken( bool deleteTokenOffer(ApplyView& view, std::shared_ptr const& offer); +/** Repairs the links in an NFTokenPage directory. + + Returns true if a repair took place, otherwise false. +*/ +bool +repairNFTokenDirectoryLinks(ApplyView& view, AccountID const& owner); + bool compareTokens(uint256 const& a, uint256 const& b); diff --git a/src/xrpld/app/tx/detail/applySteps.cpp b/src/xrpld/app/tx/detail/applySteps.cpp index 9ddaa3051c4..cbeabb6fc9c 100644 --- a/src/xrpld/app/tx/detail/applySteps.cpp +++ b/src/xrpld/app/tx/detail/applySteps.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -97,6 +98,8 @@ with_txn_type(TxType txnType, F&& f) return f.template operator()(); case ttESCROW_CANCEL: return f.template operator()(); + case ttLEDGER_STATE_FIX: + return f.template operator()(); case ttPAYCHAN_CLAIM: return f.template operator()(); case ttPAYCHAN_CREATE: From 93d8bafb24a7846210b49376f6c0e78eea484a0f Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Thu, 15 Aug 2024 12:51:50 -0400 Subject: [PATCH 43/82] chore: libxrpl verification on CI (#5028) Implements a CI workflow that detects when a new version of libxrpl is proposed, uploads it to artifactory under the `clio` channel and notifies Clio's CI to check this newly proposed version. --- .github/workflows/libxrpl.yml | 88 +++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 .github/workflows/libxrpl.yml diff --git a/.github/workflows/libxrpl.yml b/.github/workflows/libxrpl.yml new file mode 100644 index 00000000000..fe4a2c3e220 --- /dev/null +++ b/.github/workflows/libxrpl.yml @@ -0,0 +1,88 @@ +name: Check libXRPL compatibility with Clio +env: + CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod + CONAN_LOGIN_USERNAME_RIPPLE: ${{ secrets.CONAN_USERNAME }} + CONAN_PASSWORD_RIPPLE: ${{ secrets.CONAN_TOKEN }} +on: + pull_request: + paths: + - 'src/libxrpl/protocol/BuildInfo.cpp' + - '.github/workflows/libxrpl.yml' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + publish: + name: Publish libXRPL + outputs: + outcome: ${{ steps.upload.outputs.outcome }} + version: ${{ steps.version.outputs.version }} + channel: ${{ steps.channel.outputs.channel }} + runs-on: [self-hosted, heavy] + container: rippleci/rippled-build-ubuntu:aaf5e3e + steps: + - name: Wait for essential checks to succeed + uses: lewagon/wait-on-check-action@v1.3.4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + running-workflow-name: wait-for-check-regexp + check-regexp: '(dependencies|test).*linux.*' # Ignore windows and mac tests but make sure linux passes + repo-token: ${{ secrets.GITHUB_TOKEN }} + wait-interval: 10 + - name: Checkout + uses: actions/checkout@v4 + - name: Generate channel + id: channel + shell: bash + run: | + echo channel="clio/pr_${{ github.event.pull_request.number }}" | tee ${GITHUB_OUTPUT} + - name: Export new package + shell: bash + run: | + conan export . ${{ steps.channel.outputs.channel }} + - name: Add Ripple Conan remote + shell: bash + run: | + conan remote list + conan remote remove ripple || true + # Do not quote the URL. An empty string will be accepted (with a non-fatal warning), but a missing argument will not. + conan remote add ripple ${{ env.CONAN_URL }} --insert 0 + - name: Parse new version + id: version + shell: bash + run: | + echo version="$(cat src/libxrpl/protocol/BuildInfo.cpp | grep "versionString =" \ + | awk -F '"' '{print $2}')" | tee ${GITHUB_OUTPUT} + - name: Try to authenticate to Ripple Conan remote + id: remote + shell: bash + run: | + # `conan user` implicitly uses the environment variables CONAN_LOGIN_USERNAME_ and CONAN_PASSWORD_. + # https://docs.conan.io/1/reference/commands/misc/user.html#using-environment-variables + # https://docs.conan.io/1/reference/env_vars.html#conan-login-username-conan-login-username-remote-name + # https://docs.conan.io/1/reference/env_vars.html#conan-password-conan-password-remote-name + echo outcome=$(conan user --remote ripple --password >&2 \ + && echo success || echo failure) | tee ${GITHUB_OUTPUT} + - name: Upload new package + id: upload + if: (steps.remote.outputs.outcome == 'success') + shell: bash + run: | + echo "conan upload version ${{ steps.version.outputs.version }} on channel ${{ steps.channel.outputs.channel }}" + echo outcome=$(conan upload xrpl/${{ steps.version.outputs.version }}@${{ steps.channel.outputs.channel }} --remote ripple --confirm >&2 \ + && echo success || echo failure) | tee ${GITHUB_OUTPUT} + notify_clio: + name: Notify Clio + runs-on: ubuntu-latest + needs: publish + env: + GH_TOKEN: ${{ secrets.CLIO_NOTIFY_TOKEN }} + steps: + - name: Notify Clio about new version + if: (needs.publish.outputs.outcome == 'success') + shell: bash + run: | + gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" \ + /repos/xrplf/clio/dispatches -f "event_type=check_libxrpl" \ + -F "client_payload[version]=${{ needs.publish.outputs.version }}@${{ needs.publish.outputs.channel }}" From d9bd75e68326861fb38fd5b27d47da1054a7fc3b Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Thu, 15 Aug 2024 17:03:50 -0400 Subject: [PATCH 44/82] chore: Fix documentation generation job: (#5091) * Add "doxygen" to list of supported branches to allow for testing and development. * Add titles / H1 to some .md files that don't have them. --- .github/workflows/doxygen.yml | 1 + bin/ci/README.md | 2 ++ cmake/RippledDocs.cmake | 18 ++++++++++-------- docs/Doxyfile | 15 +++++++-------- external/README.md | 2 ++ include/xrpl/proto/org/xrpl/rpc/v1/README.md | 2 ++ src/xrpld/app/reporting/README.md | 2 ++ 7 files changed, 26 insertions(+), 16 deletions(-) diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index 10a1465192a..e2265d1b83b 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -4,6 +4,7 @@ on: push: branches: - develop + - doxygen concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true diff --git a/bin/ci/README.md b/bin/ci/README.md index 36d4fc1d310..32ae24b3a20 100644 --- a/bin/ci/README.md +++ b/bin/ci/README.md @@ -1,3 +1,5 @@ +# Continuous Integration (CI) Scripts + In this directory are two scripts, `build.sh` and `test.sh` used for building and testing rippled. diff --git a/cmake/RippledDocs.cmake b/cmake/RippledDocs.cmake index a9b8b283bf0..d93bc119c0d 100644 --- a/cmake/RippledDocs.cmake +++ b/cmake/RippledDocs.cmake @@ -21,15 +21,17 @@ set(doxyfile "${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile") file(GLOB_RECURSE doxygen_input docs/*.md - src/ripple/*.h - src/ripple/*.cpp - src/ripple/*.md - src/test/*.h - src/test/*.md) + include/*.h + include/*.cpp + include/*.md + src/*.h + src/*.cpp + src/*.md + Builds/*.md + *.md) list(APPEND doxygen_input - README.md - RELEASENOTES.md - src/README.md) + external/README.md + ) set(dependencies "${doxygen_input}" "${doxyfile}") function(verbose_find_path variable name) diff --git a/docs/Doxyfile b/docs/Doxyfile index 48a0b5d1e1a..750ae0fb649 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -103,18 +103,17 @@ WARN_LOGFILE = # Configuration options related to the input files #--------------------------------------------------------------------------- INPUT = \ - docs \ - src/ripple \ - src/test \ - src/README.md \ - README.md \ - RELEASENOTES.md \ + . \ INPUT_ENCODING = UTF-8 FILE_PATTERNS = *.h *.cpp *.md RECURSIVE = YES -EXCLUDE = +EXCLUDE = \ + .github \ + external/ed25519-donna \ + external/secp256k1 \ + EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXCLUDE_SYMBOLS = @@ -130,7 +129,7 @@ INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO FILTER_SOURCE_PATTERNS = -USE_MDFILE_AS_MAINPAGE = src/README.md +USE_MDFILE_AS_MAINPAGE = ./README.md #--------------------------------------------------------------------------- # Configuration options related to source browsing diff --git a/external/README.md b/external/README.md index f45f80965a5..25ae577ba58 100644 --- a/external/README.md +++ b/external/README.md @@ -1,3 +1,5 @@ +# External Conan recipes + The subdirectories in this directory contain either copies or Conan recipes of external libraries used by rippled. The Conan recipes include patches we have not yet pushed upstream. diff --git a/include/xrpl/proto/org/xrpl/rpc/v1/README.md b/include/xrpl/proto/org/xrpl/rpc/v1/README.md index c5000104257..9268439847d 100644 --- a/include/xrpl/proto/org/xrpl/rpc/v1/README.md +++ b/include/xrpl/proto/org/xrpl/rpc/v1/README.md @@ -1,3 +1,5 @@ +# Protocol buffer definitions for gRPC + This folder contains the protocol buffer definitions used by the rippled gRPC API. The gRPC API attempts to mimic the JSON/Websocket API as much as possible. As of April 2020, the gRPC API supports a subset of the full rippled API: diff --git a/src/xrpld/app/reporting/README.md b/src/xrpld/app/reporting/README.md index 745cbb633a9..f55b2d8d60d 100644 --- a/src/xrpld/app/reporting/README.md +++ b/src/xrpld/app/reporting/README.md @@ -1,3 +1,5 @@ +# Reporting mode + Reporting mode is a special operating mode of rippled, designed to handle RPCs for validated data. A server running in reporting mode does not connect to the p2p network, but rather extracts validated data from a node that is connected From 4d7aed84ec1285397c44ee9f0beb529218068706 Mon Sep 17 00:00:00 2001 From: John Freeman Date: Wed, 28 Aug 2024 13:00:50 -0500 Subject: [PATCH 45/82] refactor: Remove reporting mode (#5092) --- BUILD.md | 1 - CMakeLists.txt | 9 - README.md | 2 +- cfg/initdb.sh | 10 - cfg/rippled-example.cfg | 228 +-- cfg/rippled-reporting.cfg | 1638 ----------------- cmake/RippledCore.cmake | 8 - cmake/RippledSettings.cmake | 2 - conanfile.py | 9 - .../proto/org/xrpl/rpc/v1/xrp_ledger.proto | 2 +- include/xrpl/protocol/ErrorCodes.h | 9 +- src/libxrpl/protocol/ErrorCodes.cpp | 2 - src/test/rpc/ReportingETL_test.cpp | 1144 ------------ src/xrpld/app/ledger/AcceptedLedger.cpp | 13 +- src/xrpld/app/ledger/Ledger.cpp | 102 +- src/xrpld/app/ledger/Ledger.h | 26 - src/xrpld/app/ledger/LedgerMaster.h | 22 - src/xrpld/app/ledger/detail/LedgerMaster.cpp | 62 +- src/xrpld/app/ledger/detail/LedgerToJson.cpp | 10 +- src/xrpld/app/main/Application.cpp | 218 +-- src/xrpld/app/main/Application.h | 5 - src/xrpld/app/main/GRPCServer.cpp | 118 +- src/xrpld/app/main/Main.cpp | 15 - src/xrpld/app/misc/NetworkOPs.cpp | 384 +--- src/xrpld/app/misc/NetworkOPs.h | 9 - src/xrpld/app/misc/SHAMapStoreImp.cpp | 28 - src/xrpld/app/misc/detail/Transaction.cpp | 16 - src/xrpld/app/rdb/README.md | 3 - src/xrpld/app/rdb/RelationalDatabase.h | 23 - src/xrpld/app/rdb/backend/PostgresDatabase.h | 113 -- .../rdb/backend/detail/PostgresDatabase.cpp | 1072 ----------- .../app/rdb/detail/RelationalDatabase.cpp | 37 +- src/xrpld/app/reporting/ETLHelpers.h | 195 -- src/xrpld/app/reporting/ETLSource.cpp | 982 ---------- src/xrpld/app/reporting/ETLSource.h | 435 ----- src/xrpld/app/reporting/P2pProxy.cpp | 84 - src/xrpld/app/reporting/P2pProxy.h | 113 -- src/xrpld/app/reporting/README.md | 110 -- src/xrpld/app/reporting/ReportingETL.cpp | 960 ---------- src/xrpld/app/reporting/ReportingETL.h | 367 ---- src/xrpld/core/Config.h | 21 - src/xrpld/core/DatabaseCon.h | 4 +- src/xrpld/core/Pg.cpp | 1415 -------------- src/xrpld/core/Pg.h | 520 ------ src/xrpld/core/detail/Config.cpp | 5 - src/xrpld/core/detail/DatabaseCon.cpp | 1 - src/xrpld/nodestore/Backend.h | 34 - src/xrpld/nodestore/Database.h | 11 - .../nodestore/backend/CassandraFactory.cpp | 983 ---------- src/xrpld/nodestore/detail/Database.cpp | 9 - src/xrpld/nodestore/detail/DatabaseNodeImp.h | 6 - src/xrpld/nodestore/detail/ManagerImp.cpp | 6 - src/xrpld/rpc/detail/DeliveredAmount.cpp | 18 +- src/xrpld/rpc/detail/Handler.cpp | 4 - src/xrpld/rpc/detail/Handler.h | 16 - src/xrpld/rpc/detail/RPCHandler.cpp | 34 - src/xrpld/rpc/detail/RPCHelpers.cpp | 34 +- src/xrpld/rpc/detail/TransactionSign.cpp | 6 +- src/xrpld/rpc/handlers/AccountTx.cpp | 14 - src/xrpld/rpc/handlers/CanDelete.cpp | 3 - src/xrpld/rpc/handlers/Connect.cpp | 3 - src/xrpld/rpc/handlers/ConsensusInfo.cpp | 3 - src/xrpld/rpc/handlers/Feature1.cpp | 3 - src/xrpld/rpc/handlers/FetchInfo.cpp | 3 - src/xrpld/rpc/handlers/GetCounts.cpp | 2 +- src/xrpld/rpc/handlers/LedgerAccept.cpp | 2 +- src/xrpld/rpc/handlers/LedgerHandler.cpp | 3 +- src/xrpld/rpc/handlers/Manifest.cpp | 3 - src/xrpld/rpc/handlers/Peers.cpp | 3 - src/xrpld/rpc/handlers/Reservations.cpp | 9 - src/xrpld/rpc/handlers/ServerInfo.cpp | 9 - src/xrpld/rpc/handlers/Subscribe.cpp | 6 - src/xrpld/rpc/handlers/Tx.cpp | 121 +- src/xrpld/rpc/handlers/TxHistory.cpp | 3 - src/xrpld/rpc/handlers/UnlList.cpp | 2 - src/xrpld/rpc/handlers/ValidatorListSites.cpp | 3 - src/xrpld/rpc/handlers/Validators.cpp | 3 - src/xrpld/shamap/Family.h | 2 - src/xrpld/shamap/detail/NodeFamily.cpp | 8 - 79 files changed, 217 insertions(+), 11704 deletions(-) delete mode 100755 cfg/initdb.sh delete mode 100644 cfg/rippled-reporting.cfg delete mode 100644 src/test/rpc/ReportingETL_test.cpp delete mode 100644 src/xrpld/app/rdb/backend/PostgresDatabase.h delete mode 100644 src/xrpld/app/rdb/backend/detail/PostgresDatabase.cpp delete mode 100644 src/xrpld/app/reporting/ETLHelpers.h delete mode 100644 src/xrpld/app/reporting/ETLSource.cpp delete mode 100644 src/xrpld/app/reporting/ETLSource.h delete mode 100644 src/xrpld/app/reporting/P2pProxy.cpp delete mode 100644 src/xrpld/app/reporting/P2pProxy.h delete mode 100644 src/xrpld/app/reporting/README.md delete mode 100644 src/xrpld/app/reporting/ReportingETL.cpp delete mode 100644 src/xrpld/app/reporting/ReportingETL.h delete mode 100644 src/xrpld/core/Pg.cpp delete mode 100644 src/xrpld/core/Pg.h delete mode 100644 src/xrpld/nodestore/backend/CassandraFactory.cpp diff --git a/BUILD.md b/BUILD.md index b4201ef0437..a39df98a5a6 100644 --- a/BUILD.md +++ b/BUILD.md @@ -376,7 +376,6 @@ stored inside the build directory, as either of: | Option | Default Value | Description | | --- | ---| ---| | `assert` | OFF | Enable assertions. -| `reporting` | OFF | Build the reporting mode feature. | | `coverage` | OFF | Prepare the coverage report. | | `tests` | ON | Build tests. | | `unity` | ON | Configure a unity build. | diff --git a/CMakeLists.txt b/CMakeLists.txt index a69583f9cbf..0c34f89397d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,15 +115,6 @@ else() endif() target_link_libraries(ripple_libs INTERFACE ${nudb}) -if(reporting) - find_package(cassandra-cpp-driver REQUIRED) - find_package(PostgreSQL REQUIRED) - target_link_libraries(ripple_libs INTERFACE - cassandra-cpp-driver::cassandra-cpp-driver - PostgreSQL::PostgreSQL - ) -endif() - if(coverage) include(RippledCov) endif() diff --git a/README.md b/README.md index 45dc2005ea2..cc002a2dd82 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ The [XRP Ledger](https://xrpl.org/) is a decentralized cryptographic ledger powe ## rippled The server software that powers the XRP Ledger is called `rippled` and is available in this repository under the permissive [ISC open-source license](LICENSE.md). The `rippled` server software is written primarily in C++ and runs on a variety of platforms. The `rippled` server software can run in several modes depending on its [configuration](https://xrpl.org/rippled-server-modes.html). -If you are interested in running an **API Server** (including a **Full History Server**) or a **Reporting Mode** server, take a look at [Clio](https://github.com/XRPLF/clio). rippled Reporting Mode is expected to be replaced by Clio. +If you are interested in running an **API Server** (including a **Full History Server**), take a look at [Clio](https://github.com/XRPLF/clio). (rippled Reporting Mode has been replaced by Clio.) ### Build from Source diff --git a/cfg/initdb.sh b/cfg/initdb.sh deleted file mode 100755 index 9ca02ed5632..00000000000 --- a/cfg/initdb.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh - -# Execute this script with a running Postgres server on the current host. -# It should work with the most generic installation of Postgres, -# and is necessary for rippled to store data in Postgres. - -# usage: sudo -u postgres ./initdb.sh -psql -c "CREATE USER rippled" -psql -c "CREATE DATABASE rippled WITH OWNER = rippled" - diff --git a/cfg/rippled-example.cfg b/cfg/rippled-example.cfg index b283900d013..673ab3213e8 100644 --- a/cfg/rippled-example.cfg +++ b/cfg/rippled-example.cfg @@ -13,7 +13,7 @@ # # 4. HTTPS Client # -# 5. Reporting Mode +# 5. # # 6. Database # @@ -883,119 +883,6 @@ # #------------------------------------------------------------------------------- # -# 5. Reporting Mode -# -#------------ -# -# rippled has an optional operating mode called Reporting Mode. In Reporting -# Mode, rippled does not connect to the peer to peer network. Instead, rippled -# will continuously extract data from one or more rippled servers that are -# connected to the peer to peer network (referred to as an ETL source). -# Reporting mode servers will forward RPC requests that require access to the -# peer to peer network (submit, fee, etc) to an ETL source. -# -# [reporting] Settings for Reporting Mode. If and only if this section is -# present, rippled will start in reporting mode. This section -# contains a list of ETL source names, and key-value pairs. The -# ETL source names each correspond to a configuration file -# section; the names must match exactly. The key-value pairs are -# optional. -# -# -# [] -# -# A series of key/value pairs that specify an ETL source. -# -# source_ip = -# -# Required. IP address of the ETL source. Can also be a DNS record. -# -# source_ws_port = -# -# Required. Port on which ETL source is accepting unencrypted websocket -# connections. -# -# source_grpc_port = -# -# Required for ETL. Port on which ETL source is accepting gRPC requests. -# If this option is ommitted, this ETL source cannot actually be used for -# ETL; the Reporting Mode server can still forward RPCs to this ETL -# source, but cannot extract data from this ETL source. -# -# -# Key-value pairs (all optional): -# -# read_only Valid values: 0, 1. Default is 0. If set to 1, the server -# will start in strict read-only mode, and will not perform -# ETL. The server will still handle RPC requests, and will -# still forward RPC requests that require access to the p2p -# network. -# -# start_sequence -# Sequence of first ledger to extract if the database is empty. -# ETL extracts ledgers in order. If this setting is absent and -# the database is empty, ETL will start with the next ledger -# validated by the network. If this setting is present and the -# database is not empty, an exception is thrown. -# -# num_markers Degree of parallelism used during the initial ledger -# download. Only used if the database is empty. Valid values -# are 1-256. A higher degree of parallelism results in a -# faster download, but puts more load on the ETL source. -# Default is 2. -# -# Example: -# -# [reporting] -# etl_source1 -# etl_source2 -# read_only=0 -# start_sequence=32570 -# num_markers=8 -# -# [etl_source1] -# source_ip=1.2.3.4 -# source_ws_port=6005 -# source_grpc_port=50051 -# -# [etl_source2] -# source_ip=5.6.7.8 -# source_ws_port=6005 -# source_grpc_port=50051 -# -# Minimal Example: -# -# [reporting] -# etl_source1 -# -# [etl_source1] -# source_ip=1.2.3.4 -# source_ws_port=6005 -# source_grpc_port=50051 -# -# -# Notes: -# -# Reporting Mode requires Postgres (instead of SQLite). The Postgres -# connection info is specified under the [ledger_tx_tables] config section; -# see the Database section for further documentation. -# -# Each ETL source specified must have gRPC enabled (by adding a [port_grpc] -# section to the config). It is recommended to add a secure_gateway entry to -# the gRPC section, in order to bypass the server's rate limiting. -# This section needs to be added to the config of the ETL source, not -# the config of the reporting node. In the example below, the -# reporting server is running at 127.0.0.1. Multiple IPs can be -# specified in secure_gateway via a comma separated list. -# -# [port_grpc] -# ip = 0.0.0.0 -# port = 50051 -# secure_gateway = 127.0.0.1 -# -# -#------------------------------------------------------------------------------- -# # 6. Database # #------------ @@ -1003,13 +890,7 @@ # rippled creates 4 SQLite database to hold bookkeeping information # about transactions, local credentials, and various other things. # It also creates the NodeDB, which holds all the objects that -# make up the current and historical ledgers. In Reporting Mode, rippled -# uses a Postgres database instead of SQLite. -# -# The simplest way to work with Postgres is to install it locally. -# When it is running, execute the initdb.sh script in the current -# directory as: sudo -u postgres ./initdb.sh -# This will create the rippled user and an empty database of the same name. +# make up the current and historical ledgers. # # The size of the NodeDB grows in proportion to the amount of new data and the # amount of historical data (a configurable setting) so the performance of the @@ -1051,33 +932,10 @@ # keeping full history is not advised, and using online delete is # recommended. # -# type = Cassandra -# -# Apache Cassandra is an open-source, distributed key-value store - see -# https://cassandra.apache.org/ for more details. -# -# Cassandra is an alternative backend to be used only with Reporting Mode. -# See the Reporting Mode section for more details about Reporting Mode. -# # Required keys for NuDB and RocksDB: # # path Location to store the database # -# Required keys for Cassandra: -# -# contact_points IP of a node in the Cassandra cluster -# -# port CQL Native Transport Port -# -# secure_connect_bundle -# Absolute path to a secure connect bundle. When using -# a secure connect bundle, contact_points and port are -# not required. -# -# keyspace Name of Cassandra keyspace to use -# -# table_name Name of table in above keyspace to use -# # Optional keys # # cache_size Size of cache for database records. Default is 16384. @@ -1153,25 +1011,6 @@ # checking until healthy. # Default is 5. # -# Optional keys for Cassandra: -# -# username Username to use if Cassandra cluster requires -# authentication -# -# password Password to use if Cassandra cluster requires -# authentication -# -# max_requests_outstanding -# Limits the maximum number of concurrent database -# writes. Default is 10 million. For slower clusters, -# large numbers of concurrent writes can overload the -# cluster. Setting this option can help eliminate -# write timeouts and other write errors due to the -# cluster being overloaded. -# io_threads -# Set the number of IO threads used by the -# Cassandra driver. Defaults to 4. -# # Notes: # The 'node_db' entry configures the primary, persistent storage. # @@ -1267,42 +1106,6 @@ # This setting may not be combined with the # "safety_level" setting. # -# [ledger_tx_tables] (optional) -# -# conninfo Info for connecting to Postgres. Format is -# postgres://[username]:[password]@[ip]/[database]. -# The database and user must already exist. If this -# section is missing and rippled is running in -# Reporting Mode, rippled will connect as the -# user running rippled to a database with the -# same name. On Linux and Mac OS X, the connection -# will take place using the server's UNIX domain -# socket. On Windows, through the localhost IP -# address. Default is empty. -# -# use_tx_tables Valid values: 1, 0 -# The default is 1 (true). Determines whether to use -# the SQLite transaction database. If set to 0, -# rippled will not write to the transaction database, -# and will reject tx, account_tx and tx_history RPCs. -# In Reporting Mode, this setting is ignored. -# -# max_connections Valid values: any positive integer up to 64 bit -# storage length. This configures the maximum -# number of concurrent connections to postgres. -# Default is the maximum possible value to -# fit in a 64 bit integer. -# -# timeout Number of seconds after which idle postgres -# connections are discconnected. If set to 0, -# connections never timeout. Default is 600. -# -# -# remember_ip Value values: 1, 0 -# Default is 1 (true). Whether to cache host and -# port connection settings. -# -# #------------------------------------------------------------------------------- # # 7. Diagnostics @@ -1566,6 +1369,12 @@ # Admin level API commands over Secure Websockets, when originating # from the same machine (via the loopback adapter at 127.0.0.1). # +# "grpc" +# +# ETL commands for Clio. We recommend setting secure_gateway +# in this section to a comma-separated list of the addresses +# of your Clio servers, in order to bypass rippled's rate limiting. +# # This port is commented out but can be enabled by removing # the '#' from each corresponding line including the entry under [server] # @@ -1648,15 +1457,6 @@ advisory_delete=0 /var/lib/rippled/db -# To use Postgres, uncomment this section and fill in the appropriate connection -# info. Postgres can only be used in Reporting Mode. -# To disable writing to the transaction database, uncomment this section, and -# set use_tx_tables=0 -# [ledger_tx_tables] -# conninfo = postgres://[username]:[password]@[ip]/[database] -# use_tx_tables=1 - - # This needs to be an absolute directory reference, not a relative one. # Modify this value as required. [debug_logfile] @@ -1684,15 +1484,3 @@ validators.txt # set to ssl_verify to 0. [ssl_verify] 1 - - -# To run in Reporting Mode, uncomment this section and fill in the appropriate -# connection info for one or more ETL sources. -# [reporting] -# etl_source -# -# -# [etl_source] -# source_grpc_port=50051 -# source_ws_port=6005 -# source_ip=127.0.0.1 diff --git a/cfg/rippled-reporting.cfg b/cfg/rippled-reporting.cfg deleted file mode 100644 index 9776ef5ee45..00000000000 --- a/cfg/rippled-reporting.cfg +++ /dev/null @@ -1,1638 +0,0 @@ -#------------------------------------------------------------------------------- -# -# -#------------------------------------------------------------------------------- -# -# Contents -# -# 1. Server -# -# 2. Peer Protocol -# -# 3. Ripple Protocol -# -# 4. HTTPS Client -# -# 5. Reporting Mode -# -# 6. Database -# -# 7. Diagnostics -# -# 8. Voting -# -# 9. Misc Settings -# -# 10. Example Settings -# -#------------------------------------------------------------------------------- -# -# Purpose -# -# This file documents and provides examples of all rippled server process -# configuration options. When the rippled server instance is launched, it -# looks for a file with the following name: -# -# rippled.cfg -# -# For more information on where the rippled server instance searches for the -# file, visit: -# -# https://xrpl.org/commandline-usage.html#generic-options -# -# This file should be named rippled.cfg. This file is UTF-8 with DOS, UNIX, -# or Mac style end of lines. Blank lines and lines beginning with '#' are -# ignored. Undefined sections are reserved. No escapes are currently defined. -# -# Notation -# -# In this document a simple BNF notation is used. Angle brackets denote -# required elements, square brackets denote optional elements, and single -# quotes indicate string literals. A vertical bar separating 1 or more -# elements is a logical "or"; any one of the elements may be chosen. -# Parentheses are notational only, and used to group elements; they are not -# part of the syntax unless they appear in quotes. White space may always -# appear between elements, it has no effect on values. -# -# A required identifier -# '=' The equals sign character -# | Logical "or" -# ( ) Used for grouping -# -# -# An identifier is a string of upper or lower case letters, digits, or -# underscores subject to the requirement that the first character of an -# identifier must be a letter. Identifiers are not case sensitive (but -# values may be). -# -# Some configuration sections contain key/value pairs. A line containing -# a key/value pair has this syntax: -# -# '=' -# -# Depending on the section and key, different value types are possible: -# -# A signed integer -# An unsigned integer -# A boolean. 1 = true/yes/on, 0 = false/no/off. -# -# Consult the documentation on the key in question to determine the possible -# value types. -# -# -# -#------------------------------------------------------------------------------- -# -# 1. Server -# -#---------- -# -# -# -# rippled offers various server protocols to clients making inbound -# connections. The listening ports rippled uses are "universal" ports -# which may be configured to handshake in one or more of the available -# supported protocols. These universal ports simplify administration: -# A single open port can be used for multiple protocols. -# -# NOTE At least one server port must be defined in order -# to accept incoming network connections. -# -# -# [server] -# -# A list of port names and key/value pairs. A port name must start with a -# letter and contain only letters and numbers. The name is not case-sensitive. -# For each name in this list, rippled will look for a configuration file -# section with the same name and use it to create a listening port. The -# name is informational only; the choice of name does not affect the function -# of the listening port. -# -# Key/value pairs specified in this section are optional, and apply to all -# listening ports unless the port overrides the value in its section. They -# may be considered default values. -# -# Suggestion: -# -# To avoid a conflict with port names and future configuration sections, -# we recommend prepending "port_" to the port name. This prefix is not -# required, but suggested. -# -# This example defines two ports with different port numbers and settings: -# -# [server] -# port_public -# port_private -# port = 80 -# -# [port_public] -# ip = 0.0.0.0 -# port = 443 -# protocol = peer,https -# -# [port_private] -# ip = 127.0.0.1 -# protocol = http -# -# When rippled is used as a command line client (for example, issuing a -# server stop command), the first port advertising the http or https -# protocol will be used to make the connection. -# -# -# -# [] -# -# A series of key/value pairs that define the settings for the port with -# the corresponding name. These keys are possible: -# -# ip = -# -# Required. Determines the IP address of the network interface to bind -# to. To bind to all available IPv4 interfaces, use 0.0.0.0 -# To binding to all IPv4 and IPv6 interfaces, use :: -# -# NOTE if the ip value is ::, then any incoming IPv4 connections will -# be made as mapped IPv4 addresses. -# -# port = -# -# Required. Sets the port number to use for this port. -# -# protocol = [ http, https, peer ] -# -# Required. A comma-separated list of protocols to support: -# -# http JSON-RPC over HTTP -# https JSON-RPC over HTTPS -# ws Websockets -# wss Secure Websockets -# peer Peer Protocol -# -# Restrictions: -# -# Only one port may be configured to support the peer protocol. -# A port cannot have websocket and non websocket protocols at the -# same time. It is possible have both Websockets and Secure Websockets -# together in one port. -# -# NOTE If no ports support the peer protocol, rippled cannot -# receive incoming peer connections or become a superpeer. -# -# limit = -# -# Optional. An integer value that will limit the number of connected -# clients that the port will accept. Once the limit is reached, new -# connections will be refused until other clients disconnect. -# Omit or set to 0 to allow unlimited numbers of clients. -# -# user = -# password = -# -# When set, these credentials will be required on HTTP/S requests. -# The credentials must be provided using HTTP's Basic Authentication -# headers. If either or both fields are empty, then no credentials are -# required. IP address restrictions, if any, will be checked in addition -# to the credentials specified here. -# -# When acting in the client role, rippled will supply these credentials -# using HTTP's Basic Authentication headers when making outbound HTTP/S -# requests. -# -# admin = [ IP, IP, IP, ... ] -# -# A comma-separated list of IP addresses. -# -# When set, grants administrative command access to the specified IP -# addresses. These commands may be issued over http, https, ws, or wss -# if configured on the port. If not provided, the default is to not allow -# administrative commands. -# -# NOTE A common configuration value for the admin field is "localhost". -# If you are listening on all IPv4/IPv6 addresses by specifing -# ip = :: then you can use admin = ::ffff:127.0.0.1,::1 to allow -# administrative access from both IPv4 and IPv6 localhost -# connections. -# -# *SECURITY WARNING* -# 0.0.0.0 or :: may be used to allow access from any IP address. It must -# be the only address specified and cannot be combined with other IPs. -# Use of this address can compromise server security, please consider its -# use carefully. -# -# admin_user = -# admin_password = -# -# When set, clients must provide these credentials in the submitted -# JSON for any administrative command requests submitted to the HTTP/S, -# WS, or WSS protocol interfaces. If administrative commands are -# disabled for a port, these credentials have no effect. -# -# When acting in the client role, rippled will supply these credentials -# in the submitted JSON for any administrative command requests when -# invoking JSON-RPC commands on remote servers. -# -# secure_gateway = [ IP, IP, IP, ... ] -# -# A comma-separated list of IP addresses. -# -# When set, allows the specified IP addresses to pass HTTP headers -# containing username and remote IP address for each session. If a -# non-empty username is passed in this way, then resource controls -# such as often resulting in "tooBusy" errors will be lifted. However, -# administrative RPC commands such as "stop" will not be allowed. -# The HTTP headers that secure_gateway hosts can set are X-User and -# X-Forwarded-For. Only the X-User header affects resource controls. -# However, both header values are logged to help identify user activity. -# If no X-User header is passed, or if its value is empty, then -# resource controls will default to those for non-administrative users. -# -# The secure_gateway IP addresses are intended to represent -# proxies. Since rippled trusts these hosts, they must be -# responsible for properly authenticating the remote user. -# -# The same IP address cannot be used in both "admin" and "secure_gateway" -# lists for the same port. In this case, rippled will abort with an error -# message to the console shortly after startup -# -# ssl_key = -# ssl_cert = -# ssl_chain = -# -# Use the specified files when configuring SSL on the port. -# -# NOTE If no files are specified and secure protocols are selected, -# rippled will generate an internal self-signed certificate. -# -# The files have these meanings: -# -# ssl_key -# -# Specifies the filename holding the SSL key in PEM format. -# -# ssl_cert -# -# Specifies the path to the SSL certificate file in PEM format. -# This is not needed if the chain includes it. -# -# ssl_chain -# -# If you need a certificate chain, specify the path to the -# certificate chain here. The chain may include the end certificate. -# -# ssl_ciphers = -# -# Control the ciphers which the server will support over SSL on the port, -# specified using the OpenSSL "cipher list format". -# -# NOTE If unspecified, rippled will automatically configure a modern -# cipher suite. This default suite should be widely supported. -# -# You should not modify this string unless you have a specific -# reason and cryptographic expertise. Incorrect modification may -# keep rippled from connecting to other instances of rippled or -# prevent RPC and WebSocket clients from connecting. -# -# send_queue_limit = [1..65535] -# -# A Websocket will disconnect when its send queue exceeds this limit. -# The default is 100. A larger value may help with erratic disconnects but -# may adversely affect server performance. -# -# WebSocket permessage-deflate extension options -# -# These settings configure the optional permessage-deflate extension -# options and may appear on any port configuration entry. They are meaningful -# only to ports which have enabled a WebSocket protocol. -# -# permessage_deflate = -# -# Determines if permessage_deflate extension negotiations are enabled. -# When enabled, clients may request the extension and the server will -# offer the enabled extension in response. -# -# client_max_window_bits = [9..15] -# server_max_window_bits = [9..15] -# client_no_context_takeover = -# server_no_context_takeover = -# -# These optional settings control options related to the permessage-deflate -# extension negotiation. For precise definitions of these fields please see -# the RFC 7692, "Compression Extensions for WebSocket": -# https://tools.ietf.org/html/rfc7692 -# -# compress_level = [0..9] -# -# When set, determines the amount of compression attempted, where 0 is -# the least amount and 9 is the most amount. Higher levels require more -# CPU resources. Levels 1 through 3 use a fast compression algorithm, -# while levels 4 through 9 use a more compact algorithm which uses more -# CPU resources. If unspecified, a default of 3 is used. -# -# memory_level = [1..9] -# -# When set, determines the relative amount of memory used to hold -# intermediate compression data. Higher numbers can give better compression -# ratios at the cost of higher memory and CPU resources. -# -# [rpc_startup] -# -# Specify a list of RPC commands to run at startup. -# -# Examples: -# { "command" : "server_info" } -# { "command" : "log_level", "partition" : "ripplecalc", "severity" : "trace" } -# -# -# -# [websocket_ping_frequency] -# -# -# -# The amount of time to wait in seconds, before sending a websocket 'ping' -# message. Ping messages are used to determine if the remote end of the -# connection is no longer available. -# -# -# [server_domain] -# -# domain name -# -# The domain under which a TOML file applicable to this server can be -# found. A server may lie about its domain so the TOML should contain -# a reference to this server by pubkey in the [nodes] array. -# -# -#------------------------------------------------------------------------------- -# -# 2. Peer Protocol -# -#----------------- -# -# These settings control security and access attributes of the Peer to Peer -# server section of the rippled process. Peer Protocol implements the -# Ripple Payment protocol. It is over peer connections that transactions -# and validations are passed from to machine to machine, to determine the -# contents of validated ledgers. -# -# -# -# [ips] -# -# List of hostnames or ips where the Ripple protocol is served. A default -# starter list is included in the code and used if no other hostnames are -# available. -# -# One address or domain name per line is allowed. A port may must be -# specified after adding a space to the address. The ordering of entries -# does not generally matter. -# -# The default list of entries is: -# - r.ripple.com 51235 -# - sahyadri.isrdc.in 51235 -# -# Examples: -# -# [ips] -# 192.168.0.1 -# 192.168.0.1 2459 -# r.ripple.com 51235 -# -# -# [ips_fixed] -# -# List of IP addresses or hostnames to which rippled should always attempt to -# maintain peer connections with. This is useful for manually forming private -# networks, for example to configure a validation server that connects to the -# Ripple network through a public-facing server, or for building a set -# of cluster peers. -# -# One address or domain names per line is allowed. A port must be specified -# after adding a space to the address. -# -# -# -# [peer_private] -# -# 0 or 1. -# -# 0: Request peers to broadcast your address. Normal outbound peer connections [default] -# 1: Request peers not broadcast your address. Only connect to configured peers. -# -# -# -# [peers_max] -# -# The largest number of desired peer connections (incoming or outgoing). -# Cluster and fixed peers do not count towards this total. There are -# implementation-defined lower limits imposed on this value for security -# purposes. -# -# -# -# [node_seed] -# -# This is used for clustering. To force a particular node seed or key, the -# key can be set here. The format is the same as the validation_seed field. -# To obtain a validation seed, use the validation_create command. -# -# Examples: RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE -# shfArahZT9Q9ckTf3s1psJ7C7qzVN -# -# -# -# [cluster_nodes] -# -# To extend full trust to other nodes, place their node public keys here. -# Generally, you should only do this for nodes under common administration. -# Node public keys start with an 'n'. To give a node a name for identification -# place a space after the public key and then the name. -# -# -# -# [max_transactions] -# -# Configure the maximum number of transactions to have in the job queue -# -# Must be a number between 100 and 1000, defaults to 250 -# -# -# [overlay] -# -# Controls settings related to the peer to peer overlay. -# -# A set of key/value pair parameters to configure the overlay. -# -# public_ip = -# -# If the server has a known, fixed public IPv4 address, -# specify that IP address here in dotted decimal notation. -# Peers will use this information to reject attempt to proxy -# connections to or from this server. -# -# ip_limit = -# -# The maximum number of incoming peer connections allowed by a single -# IP that isn't classified as "private" in RFC1918. The implementation -# imposes some hard and soft upper limits on this value to prevent a -# single host from consuming all inbound slots. If the value is not -# present the server will autoconfigure an appropriate limit. -# -# max_unknown_time = -# -# The maximum amount of time, in seconds, that an outbound connection -# is allowed to stay in the "unknown" tracking state. This option can -# take any value between 300 and 1800 seconds, inclusive. If the option -# is not present the server will autoconfigure an appropriate limit. -# -# The current default (which is subject to change) is 600 seconds. -# -# max_diverged_time = -# -# The maximum amount of time, in seconds, that an outbound connection -# is allowed to stay in the "diverged" tracking state. The option can -# take any value between 60 and 900 seconds, inclusive. If the option -# is not present the server will autoconfigure an appropriate limit. -# -# The current default (which is subject to change) is 300 seconds. -# -# -# [transaction_queue] EXPERIMENTAL -# -# This section is EXPERIMENTAL, and should not be -# present for production configuration settings. -# -# A set of key/value pair parameters to tune the performance of the -# transaction queue. -# -# ledgers_in_queue = -# -# The queue will be limited to this of average ledgers' -# worth of transactions. If the queue fills up, the transactions -# with the lowest fee levels will be dropped from the queue any -# time a transaction with a higher fee level is added. -# Default: 20. -# -# minimum_queue_size = -# -# The queue will always be able to hold at least this of -# transactions, regardless of recent ledger sizes or the value of -# ledgers_in_queue. Default: 2000. -# -# retry_sequence_percent = -# -# If a client replaces a transaction in the queue (same sequence -# number as a transaction already in the queue), the new -# transaction's fee must be more than percent higher -# than the original transaction's fee, or meet the current open -# ledger fee to be considered. Default: 25. -# -# minimum_escalation_multiplier = -# -# At ledger close time, the median fee level of the transactions -# in that ledger is used as a multiplier in escalation -# calculations of the next ledger. This minimum value ensures that -# the escalation is significant. Default: 500. -# -# minimum_txn_in_ledger = -# -# Minimum number of transactions that must be allowed into the -# ledger at the minimum required fee before the required fee -# escalates. Default: 5. -# -# minimum_txn_in_ledger_standalone = -# -# Like minimum_txn_in_ledger when rippled is running in standalone -# mode. Default: 1000. -# -# target_txn_in_ledger = -# -# Number of transactions allowed into the ledger at the minimum -# required fee that the queue will "work toward" as long as -# consensus stays healthy. The limit will grow quickly until it -# reaches or exceeds this number. After that the limit may still -# change, but will stay above the target. If consensus is not -# healthy, the limit will be clamped to this value or lower. -# Default: 50. -# -# maximum_txn_in_ledger = -# -# (Optional) Maximum number of transactions that will be allowed -# into the ledger at the minimum required fee before the required -# fee escalates. Default: no maximum. -# -# normal_consensus_increase_percent = -# -# (Optional) When the ledger has more transactions than "expected", -# and performance is humming along nicely, the expected ledger size -# is updated to the previous ledger size plus this percentage. -# Default: 20 -# -# slow_consensus_decrease_percent = -# -# (Optional) When consensus takes longer than appropriate, the -# expected ledger size is updated to the minimum of the previous -# ledger size or the "expected" ledger size minus this percentage. -# Default: 50 -# -# maximum_txn_per_account = -# -# Maximum number of transactions that one account can have in the -# queue at any given time. Default: 10. -# -# minimum_last_ledger_buffer = -# -# If a transaction has a LastLedgerSequence, it must be at least -# this much larger than the current open ledger sequence number. -# Default: 2. -# -# zero_basefee_transaction_feelevel = -# -# So we don't deal with infinite fee levels, treat any transaction -# with a 0 base fee (ie. SetRegularKey password recovery) as -# having this fee level. -# Default: 256000. -# -# -#------------------------------------------------------------------------------- -# -# 3. Protocol -# -#------------------- -# -# These settings affect the behavior of the server instance with respect -# to protocol level activities such as validating and closing ledgers -# adjusting fees in response to server overloads. -# -# -# -# -# [relay_proposals] -# -# Controls the relaying behavior for proposals received by this server that -# are issued by validators that are not on the server's UNL. -# -# Legal values are: "trusted" and "all". The default is "trusted". -# -# -# [relay_validations] -# -# Controls the relaying behavior for validations received by this server that -# are issued by validators that are not on the server's UNL. -# -# Legal values are: "trusted" and "all". The default is "all". -# -# -# -# -# -# [ledger_history] -# -# The number of past ledgers to acquire on server startup and the minimum to -# maintain while running. -# -# To serve clients, servers need historical ledger data. Servers that don't -# need to serve clients can set this to "none". Servers that want complete -# history can set this to "full". -# -# This must be less than or equal to online_delete (if online_delete is used) -# -# The default is: 256 -# -# -# -# [fetch_depth] -# -# The number of past ledgers to serve to other peers that request historical -# ledger data (or "full" for no limit). -# -# Servers that require low latency and high local performance may wish to -# restrict the historical ledgers they are willing to serve. Setting this -# below 32 can harm network stability as servers require easy access to -# recent history to stay in sync. Values below 128 are not recommended. -# -# The default is: full -# -# -# -# [validation_seed] -# -# To perform validation, this section should contain either a validation seed -# or key. The validation seed is used to generate the validation -# public/private key pair. To obtain a validation seed, use the -# validation_create command. -# -# Examples: RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE -# shfArahZT9Q9ckTf3s1psJ7C7qzVN -# -# -# -# [validator_token] -# -# This is an alternative to [validation_seed] that allows rippled to perform -# validation without having to store the validator keys on the network -# connected server. The field should contain a single token in the form of a -# base64-encoded blob. -# An external tool is available for generating validator keys and tokens. -# -# -# -# [validator_key_revocation] -# -# If a validator's secret key has been compromised, a revocation must be -# generated and added to this field. The revocation notifies peers that it is -# no longer safe to trust the revoked key. The field should contain a single -# revocation in the form of a base64-encoded blob. -# An external tool is available for generating and revoking validator keys. -# -# -# -# [validators_file] -# -# Path or name of a file that determines the nodes to always accept as validators. -# -# The contents of the file should include a [validators] and/or -# [validator_list_sites] and [validator_list_keys] entries. -# [validators] should be followed by a list of validation public keys of -# nodes, one per line. -# [validator_list_sites] should be followed by a list of URIs each serving a -# list of recommended validators. -# [validator_list_keys] should be followed by a list of keys belonging to -# trusted validator list publishers. Validator lists fetched from configured -# sites will only be considered if the list is accompanied by a valid -# signature from a trusted publisher key. -# -# Specify the file by its name or path. -# Unless an absolute path is specified, it will be considered relative to -# the folder in which the rippled.cfg file is located. -# -# Examples: -# /home/ripple/validators.txt -# C:/home/ripple/validators.txt -# -# Example content: -# [validators] -# n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7 -# n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj -# n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C -# n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS -# n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA -# -# -# -# [path_search] -# When searching for paths, the default search aggressiveness. This can take -# exponentially more resources as the size is increased. -# -# The default is: 7 -# -# [path_search_fast] -# [path_search_max] -# When searching for paths, the minimum and maximum search aggressiveness. -# -# If you do not need pathfinding, you can set path_search_max to zero to -# disable it and avoid some expensive bookkeeping. -# -# The default for 'path_search_fast' is 2. The default for 'path_search_max' is 10. -# -# [path_search_old] -# -# For clients that use the legacy path finding interfaces, the search -# aggressiveness to use. The default is 7. -# -# -# -# [fee_default] -# -# Sets the base cost of a transaction in drops. Used when the server has -# no other source of fee information, such as signing transactions offline. -# -# -# -# [workers] -# -# Configures the number of threads for processing work submitted by peers -# and clients. If not specified, then the value is automatically set to the -# number of processor threads plus 2 for networked nodes. Nodes running in -# stand alone mode default to 1 worker. -# -# -# -# [network_id] -# -# Specify the network which this server is configured to connect to and -# track. If set, the server will not establish connections with servers -# that are explicitly configured to track another network. -# -# Network identifiers are usually unsigned integers in the range 0 to -# 4294967295 inclusive. The server also maps the following well-known -# names to the corresponding numerical identifier: -# -# main -> 0 -# testnet -> 1 -# devnet -> 2 -# -# If this value is not specified the server is not explicitly configured -# to track a particular network. -# -# -# [ledger_replay] -# -# 0 or 1. -# -# 0: Disable the ledger replay feature [default] -# 1: Enable the ledger replay feature. With this feature enabled, when -# acquiring a ledger from the network, a rippled node only downloads -# the ledger header and the transactions instead of the whole ledger. -# And the ledger is built by applying the transactions to the parent -# ledger. -# -#------------------------------------------------------------------------------- -# -# 4. HTTPS Client -# -#---------------- -# -# The rippled server instance uses HTTPS GET requests in a variety of -# circumstances, including but not limited to contacting trusted domains to -# fetch information such as mapping an email address to a Ripple Payment -# Network address. -# -# [ssl_verify] -# -# 0 or 1. -# -# 0. HTTPS client connections will not verify certificates. -# 1. Certificates will be checked for HTTPS client connections. -# -# If not specified, this parameter defaults to 1. -# -# -# -# [ssl_verify_file] -# -# -# -# A file system path leading to the certificate verification file for -# HTTPS client requests. -# -# -# -# [ssl_verify_dir] -# -# -# -# -# A file system path leading to a file or directory containing the root -# certificates that the server will accept for verifying HTTP servers. -# Used only for outbound HTTPS client connections. -# -#------------------------------------------------------------------------------- -# -# 5. Reporting Mode -# -#------------ -# -# rippled has an optional operating mode called Reporting Mode. In Reporting -# Mode, rippled does not connect to the peer to peer network. Instead, rippled -# will continuously extract data from one or more rippled servers that are -# connected to the peer to peer network (referred to as an ETL source). -# Reporting mode servers will forward RPC requests that require access to the -# peer to peer network (submit, fee, etc) to an ETL source. -# -# [reporting] Settings for Reporting Mode. If and only if this section is -# present, rippled will start in reporting mode. This section -# contains a list of ETL source names, and key-value pairs. The -# ETL source names each correspond to a configuration file -# section; the names must match exactly. The key-value pairs are -# optional. -# -# -# [] -# -# A series of key/value pairs that specify an ETL source. -# -# source_ip = -# -# Required. IP address of the ETL source. Can also be a DNS record. -# -# source_ws_port = -# -# Required. Port on which ETL source is accepting unencrypted websocket -# connections. -# -# source_grpc_port = -# -# Required for ETL. Port on which ETL source is accepting gRPC requests. -# If this option is ommitted, this ETL source cannot actually be used for -# ETL; the Reporting Mode server can still forward RPCs to this ETL -# source, but cannot extract data from this ETL source. -# -# -# Key-value pairs (all optional): -# -# read_only Valid values: 0, 1. Default is 0. If set to 1, the server -# will start in strict read-only mode, and will not perform -# ETL. The server will still handle RPC requests, and will -# still forward RPC requests that require access to the p2p -# network. -# -# start_sequence -# Sequence of first ledger to extract if the database is empty. -# ETL extracts ledgers in order. If this setting is absent and -# the database is empty, ETL will start with the next ledger -# validated by the network. If this setting is present and the -# database is not empty, an exception is thrown. -# -# num_markers Degree of parallelism used during the initial ledger -# download. Only used if the database is empty. Valid values -# are 1-256. A higher degree of parallelism results in a -# faster download, but puts more load on the ETL source. -# Default is 2. -# -# Example: -# -# [reporting] -# etl_source1 -# etl_source2 -# read_only=0 -# start_sequence=32570 -# num_markers=8 -# -# [etl_source1] -# source_ip=1.2.3.4 -# source_ws_port=6005 -# source_grpc_port=50051 -# -# [etl_source2] -# source_ip=5.6.7.8 -# source_ws_port=6005 -# source_grpc_port=50051 -# -# Minimal Example: -# -# [reporting] -# etl_source1 -# -# [etl_source1] -# source_ip=1.2.3.4 -# source_ws_port=6005 -# source_grpc_port=50051 -# -# -# Notes: -# -# Reporting Mode requires Postgres (instead of SQLite). The Postgres -# connection info is specified under the [ledger_tx_tables] config section; -# see the Database section for further documentation. -# -# Each ETL source specified must have gRPC enabled (by adding a [port_grpc] -# section to the config). It is recommended to add a secure_gateway entry to -# the gRPC section, in order to bypass the server's rate limiting. -# This section needs to be added to the config of the ETL source, not -# the config of the reporting node. In the example below, the -# reporting server is running at 127.0.0.1. Multiple IPs can be -# specified in secure_gateway via a comma separated list. -# -# [port_grpc] -# ip = 0.0.0.0 -# port = 50051 -# secure_gateway = 127.0.0.1 -# -# -#------------------------------------------------------------------------------- -# -# 6. Database -# -#------------ -# -# rippled creates 4 SQLite database to hold bookkeeping information -# about transactions, local credentials, and various other things. -# It also creates the NodeDB, which holds all the objects that -# make up the current and historical ledgers. In Reporting Mode, rippled -# uses a Postgres database instead of SQLite. -# -# The simplest way to work with Postgres is to install it locally. -# When it is running, execute the initdb.sh script in the current -# directory as: sudo -u postgres ./initdb.sh -# This will create the rippled user and an empty database of the same name. -# -# The size of the NodeDB grows in proportion to the amount of new data and the -# amount of historical data (a configurable setting) so the performance of the -# underlying storage media where the NodeDB is placed can significantly affect -# the performance of the server. -# -# Partial pathnames will be considered relative to the location of -# the rippled.cfg file. -# -# [node_db] Settings for the Node Database (required) -# -# Format (without spaces): -# One or more lines of case-insensitive key / value pairs: -# '=' -# ... -# -# Example: -# type=nudb -# path=db/nudb -# -# The "type" field must be present and controls the choice of backend: -# -# type = NuDB -# -# NuDB is a high-performance database written by Ripple Labs and optimized -# for rippled and solid-state drives. -# -# NuDB maintains its high speed regardless of the amount of history -# stored. Online delete may be selected, but is not required. NuDB is -# available on all platforms that rippled runs on. -# -# type = RocksDB -# -# RocksDB is an open-source, general-purpose key/value store - see -# http://rocksdb.org/ for more details. -# -# RocksDB is an alternative backend for systems that don't use solid-state -# drives. Because RocksDB's performance degrades as it stores more data, -# keeping full history is not advised, and using online delete is -# recommended. -# -# type = Cassandra -# -# Apache Cassandra is an open-source, distributed key-value store - see -# https://cassandra.apache.org/ for more details. -# -# Cassandra is an alternative backend to be used only with Reporting Mode. -# See the Reporting Mode section for more details about Reporting Mode. -# -# Required keys for NuDB and RocksDB: -# -# path Location to store the database -# -# Required keys for Cassandra: -# -# contact_points IP of a node in the Cassandra cluster -# -# port CQL Native Transport Port -# -# secure_connect_bundle -# Absolute path to a secure connect bundle. When using -# a secure connect bundle, contact_points and port are -# not required. -# -# keyspace Name of Cassandra keyspace to use -# -# table_name Name of table in above keyspace to use -# -# Optional keys -# -# cache_size Size of cache for database records. Default is 16384. -# Setting this value to 0 will use the default value. -# -# cache_age Length of time in minutes to keep database records -# cached. Default is 5 minutes. Setting this value to -# 0 will use the default value. -# -# Note: if neither cache_size nor cache_age is -# specified, the cache for database records will not -# be created. If only one of cache_size or cache_age -# is specified, the cache will be created using the -# default value for the unspecified parameter. -# -# Note: the cache will not be created if online_delete -# is specified. -# -# Optional keys for NuDB or RocksDB: -# -# earliest_seq The default is 32570 to match the XRP ledger -# network's earliest allowed sequence. Alternate -# networks may set this value. Minimum value of 1. -# -# online_delete Minimum value of 256. Enable automatic purging -# of older ledger information. Maintain at least this -# number of ledger records online. Must be greater -# than or equal to ledger_history. -# -# These keys modify the behavior of online_delete, and thus are only -# relevant if online_delete is defined and non-zero: -# -# advisory_delete 0 for disabled, 1 for enabled. If set, the -# administrative RPC call "can_delete" is required -# to enable online deletion of ledger records. -# Online deletion does not run automatically if -# non-zero and the last deletion was on a ledger -# greater than the current "can_delete" setting. -# Default is 0. -# -# delete_batch When automatically purging, SQLite database -# records are deleted in batches. This value -# controls the maximum size of each batch. Larger -# batches keep the databases locked for more time, -# which may cause other functions to fall behind, -# and thus cause the node to lose sync. -# Default is 100. -# -# back_off_milliseconds -# Number of milliseconds to wait between -# online_delete batches to allow other functions -# to catch up. -# Default is 100. -# -# age_threshold_seconds -# The online delete process will only run if the -# latest validated ledger is younger than this -# number of seconds. -# Default is 60. -# -# recovery_wait_seconds -# The online delete process checks periodically -# that rippled is still in sync with the network, -# and that the validated ledger is less than -# 'age_threshold_seconds' old. By default, if it -# is not the online delete process aborts and -# tries again later. If 'recovery_wait_seconds' -# is set and rippled is out of sync, but likely to -# recover quickly, then online delete will wait -# this number of seconds for rippled to get back -# into sync before it aborts. -# Set this value if the node is otherwise staying -# in sync, or recovering quickly, but the online -# delete process is unable to finish. -# Default is unset. -# -# Optional keys for Cassandra: -# -# username Username to use if Cassandra cluster requires -# authentication -# -# password Password to use if Cassandra cluster requires -# authentication -# -# max_requests_outstanding -# Limits the maximum number of concurrent database -# writes. Default is 10 million. For slower clusters, -# large numbers of concurrent writes can overload the -# cluster. Setting this option can help eliminate -# write timeouts and other write errors due to the -# cluster being overloaded. -# -# Notes: -# The 'node_db' entry configures the primary, persistent storage. -# -# The 'import_db' is used with the '--import' command line option to -# migrate the specified database into the current database given -# in the [node_db] section. -# -# [import_db] Settings for performing a one-time import (optional) -# [database_path] Path to the book-keeping databases. -# -# The server creates and maintains 4 to 5 bookkeeping SQLite databases in -# the 'database_path' location. If you omit this configuration setting, -# the server creates a directory called "db" located in the same place as -# your rippled.cfg file. -# Partial pathnames are relative to the location of the rippled executable. -# -# [sqlite] Tuning settings for the SQLite databases (optional) -# -# Format (without spaces): -# One or more lines of case-insensitive key / value pairs: -# '=' -# ... -# -# Example 1: -# safety_level=low -# -# Example 2: -# journal_mode=off -# synchronous=off -# -# WARNING: These settings can have significant effects on data integrity, -# particularly in systemic failure scenarios. It is strongly recommended -# that they be left at their defaults unless the server is having -# performance issues during normal operation or during automatic purging -# (online_delete) operations. A warning will be logged on startup if -# 'ledger_history' is configured to store more than 10,000,000 ledgers and -# any of these settings are less safe than the default. This is due to the -# inordinate amount of time and bandwidth it will take to safely rebuild a -# corrupted database of that size from other peers. -# -# Optional keys: -# -# safety_level Valid values: high, low -# The default is "high", which tunes the SQLite -# databases in the most reliable mode, and is -# equivalent to: -# journal_mode=wal -# synchronous=normal -# temp_store=file -# "low" is equivalent to: -# journal_mode=memory -# synchronous=off -# temp_store=memory -# These "low" settings trade speed and reduced I/O -# for a higher risk of data loss. See the -# individual settings below for more information. -# This setting may not be combined with any of the -# other tuning settings: "journal_mode", -# "synchronous", or "temp_store". -# -# journal_mode Valid values: delete, truncate, persist, memory, wal, off -# The default is "wal", which uses a write-ahead -# log to implement database transactions. -# Alternately, "memory" saves disk I/O, but if -# rippled crashes during a transaction, the -# database is likely to be corrupted. -# See https://www.sqlite.org/pragma.html#pragma_journal_mode -# for more details about the available options. -# This setting may not be combined with the -# "safety_level" setting. -# -# synchronous Valid values: off, normal, full, extra -# The default is "normal", which works well with -# the "wal" journal mode. Alternatively, "off" -# allows rippled to continue as soon as data is -# passed to the OS, which can significantly -# increase speed, but risks data corruption if -# the host computer crashes before writing that -# data to disk. -# See https://www.sqlite.org/pragma.html#pragma_synchronous -# for more details about the available options. -# This setting may not be combined with the -# "safety_level" setting. -# -# temp_store Valid values: default, file, memory -# The default is "file", which will use files -# for temporary database tables and indices. -# Alternatively, "memory" may save I/O, but -# rippled does not currently use many, if any, -# of these temporary objects. -# See https://www.sqlite.org/pragma.html#pragma_temp_store -# for more details about the available options. -# This setting may not be combined with the -# "safety_level" setting. -# -# [ledger_tx_tables] (optional) -# -# conninfo Info for connecting to Postgres. Format is -# postgres://[username]:[password]@[ip]/[database]. -# The database and user must already exist. If this -# section is missing and rippled is running in -# Reporting Mode, rippled will connect as the -# user running rippled to a database with the -# same name. On Linux and Mac OS X, the connection -# will take place using the server's UNIX domain -# socket. On Windows, through the localhost IP -# address. Default is empty. -# -# use_tx_tables Valid values: 1, 0 -# The default is 1 (true). Determines whether to use -# the SQLite transaction database. If set to 0, -# rippled will not write to the transaction database, -# and will reject tx, account_tx and tx_history RPCs. -# In Reporting Mode, this setting is ignored. -# -# max_connections Valid values: any positive integer up to 64 bit -# storage length. This configures the maximum -# number of concurrent connections to postgres. -# Default is the maximum possible value to -# fit in a 64 bit integer. -# -# timeout Number of seconds after which idle postgres -# connections are discconnected. If set to 0, -# connections never timeout. Default is 600. -# -# -# remember_ip Value values: 1, 0 -# Default is 1 (true). Whether to cache host and -# port connection settings. -# -# -#------------------------------------------------------------------------------- -# -# 7. Diagnostics -# -#--------------- -# -# These settings are designed to help server administrators diagnose -# problems, and obtain detailed information about the activities being -# performed by the rippled process. -# -# -# -# [debug_logfile] -# -# Specifies where a debug logfile is kept. By default, no debug log is kept. -# Unless absolute, the path is relative the directory containing this file. -# -# Example: debug.log -# -# -# -# [insight] -# -# Configuration parameters for the Beast. Insight stats collection module. -# -# Insight is a module that collects information from the areas of rippled -# that have instrumentation. The configuration parameters control where the -# collection metrics are sent. The parameters are expressed as key = value -# pairs with no white space. The main parameter is the choice of server: -# -# "server" -# -# Choice of server to send metrics to. Currently the only choice is -# "statsd" which sends UDP packets to a StatsD daemon, which must be -# running while rippled is running. More information on StatsD is -# available here: -# https://github.com/b/statsd_spec -# -# When server=statsd, these additional keys are used: -# -# "address" The UDP address and port of the listening StatsD server, -# in the format, n.n.n.n:port. -# -# "prefix" A string prepended to each collected metric. This is used -# to distinguish between different running instances of rippled. -# -# If this section is missing, or the server type is unspecified or unknown, -# statistics are not collected or reported. -# -# Example: -# -# [insight] -# server=statsd -# address=192.168.0.95:4201 -# prefix=my_validator -# -# [perf] -# -# Configuration of performance logging. If enabled, write Json-formatted -# performance-oriented data periodically to a distinct log file. -# -# "perf_log" A string specifying the pathname of the performance log -# file. A relative pathname will log relative to the -# configuration directory. Required to enable -# performance logging. -# -# "log_interval" Integer value for number of seconds between writing -# to performance log. Default 1. -# -# Example: -# [perf] -# perf_log=/var/log/rippled/perf.log -# log_interval=2 -# -#------------------------------------------------------------------------------- -# -# 8. Voting -# -#---------- -# -# The vote settings configure settings for the entire Ripple network. -# While a single instance of rippled cannot unilaterally enforce network-wide -# settings, these choices become part of the instance's vote during the -# consensus process for each voting ledger. -# -# [voting] -# -# A set of key/value pair parameters used during voting ledgers. -# -# reference_fee = -# -# The cost of the reference transaction fee, specified in drops. -# The reference transaction is the simplest form of transaction. -# It represents an XRP payment between two parties. -# -# If this parameter is unspecified, rippled will use an internal -# default. Don't change this without understanding the consequences. -# -# Example: -# reference_fee = 10 # 10 drops -# -# account_reserve = -# -# The account reserve requirement is specified in drops. The portion of an -# account's XRP balance that is at or below the reserve may only be -# spent on transaction fees, and not transferred out of the account. -# -# If this parameter is unspecified, rippled will use an internal -# default. Don't change this without understanding the consequences. -# -# Example: -# account_reserve = 10000000 # 10 XRP -# -# owner_reserve = -# -# The owner reserve is the amount of XRP reserved in the account for -# each ledger item owned by the account. Ledger items an account may -# own include trust lines, open orders, and tickets. -# -# If this parameter is unspecified, rippled will use an internal -# default. Don't change this without understanding the consequences. -# -# Example: -# owner_reserve = 2000000 # 2 XRP -# -#------------------------------------------------------------------------------- -# -# 9. Misc Settings -# -#----------------- -# -# [node_size] -# -# Tunes the servers based on the expected load and available memory. Legal -# sizes are "tiny", "small", "medium", "large", and "huge". We recommend -# you start at the default and raise the setting if you have extra memory. -# -# The code attempts to automatically determine the appropriate size for -# this parameter based on the amount of RAM and the number of execution -# cores available to the server. The current decision matrix is: -# -# | | Cores | -# |---------|------------------------| -# | RAM | 1 | 2 or 3 | ≥ 4 | -# |---------|------|--------|--------| -# | < ~8GB | tiny | tiny | tiny | -# | < ~12GB | tiny | small | small | -# | < ~16GB | tiny | small | medium | -# | < ~24GB | tiny | small | large | -# | < ~32GB | tiny | small | huge | -# -# [signing_support] -# -# Specifies whether the server will accept "sign" and "sign_for" commands -# from remote users. Even if the commands are sent over a secure protocol -# like secure websocket, this should generally be discouraged, because it -# requires sending the secret to use for signing to the server. In order -# to sign transactions, users should prefer to use a standalone signing -# tool instead. -# -# This flag has no effect on the "sign" and "sign_for" command line options -# that rippled makes available. -# -# The default value of this field is "false" -# -# Example: -# -# [signing_support] -# true -# -# [crawl] -# -# List of options to control what data is reported through the /crawl endpoint -# See https://xrpl.org/peer-crawler.html -# -# -# -# Enable or disable access to /crawl requests. Default is '1' which -# enables access. -# -# overlay = -# -# Report information about peers this server is connected to, similar -# to the "peers" RPC API. Default is '1' which means to report peer -# overlay info. -# -# server = -# -# Report information about the local server, similar to the "server_state" -# RPC API. Default is '1' which means to report local server info. -# -# counts = -# -# Report information about the local server health counters, similar to -# the "get_counts" RPC API. Default is '0' which means not to report -# server counts. -# -# unl = -# -# Report information about the local server's validator lists, similar to -# the "validators" and "validator_list_sites" RPC APIs. Default is '1' -# which means to report server validator lists. -# -# Examples: -# -# [crawl] -# 0 -# -# [crawl] -# overlay = 1 -# server = 1 -# counts = 0 -# unl = 1 -# -# [vl] -# -# Options to control what data is reported through the /vl endpoint -# See [...] -# -# enable = -# -# Enable or disable access to /vl requests. Default is '1' which -# enables access. -# -# [beta_rpc_api] -# -# 0 or 1. -# -# 0: Disable the beta API version for JSON-RPC and WebSocket [default] -# 1: Enable the beta API version for testing. The beta API version -# contains breaking changes that require a new API version number. -# They are not ready for public consumption. -# -#------------------------------------------------------------------------------- -# -# 10. Example Settings -# -#-------------------- -# -# Administrators can use these values as a starting point for configuring -# their instance of rippled, but each value should be checked to make sure -# it meets the business requirements for the organization. -# -# Server -# -# These example configuration settings create these ports: -# -# "peer" -# -# Peer protocol open to everyone. This is required to accept -# incoming rippled connections. This does not affect automatic -# or manual outgoing Peer protocol connections. -# -# "rpc" -# -# Administrative RPC commands over HTTPS, when originating from -# the same machine (via the loopback adapter at 127.0.0.1). -# -# "wss_admin" -# -# Admin level API commands over Secure Websockets, when originating -# from the same machine (via the loopback adapter at 127.0.0.1). -# -# This port is commented out but can be enabled by removing -# the '#' from each corresponding line including the entry under [server] -# -# "wss_public" -# -# Guest level API commands over Secure Websockets, open to everyone. -# -# For HTTPS and Secure Websockets ports, if no certificate and key file -# are specified then a self-signed certificate will be generated on startup. -# If you have a certificate and key file, uncomment the corresponding lines -# and ensure the paths to the files are correct. -# -# NOTE -# -# To accept connections on well known ports such as 80 (HTTP) or -# 443 (HTTPS), most operating systems will require rippled to -# run with administrator privileges, or else rippled will not start. - -[server] -port_rpc_admin_local -port_peer -port_ws_admin_local -port_ws_public -#port_grpc -#ssl_key = /etc/ssl/private/server.key -#ssl_cert = /etc/ssl/certs/server.crt - -[port_rpc_admin_local] -port = 5006 -ip = 127.0.0.1 -admin = 127.0.0.1 -protocol = http - -[port_peer] -port = 51235 -ip = 0.0.0.0 -# alternatively, to accept connections on IPv4 + IPv6, use: -#ip = :: -protocol = peer - -[port_ws_admin_local] -port = 6007 -ip = 127.0.0.1 -admin = 127.0.0.1 -protocol = ws - -#[port_grpc#] -#port = 50051 -#ip = 0.0.0.0 -#secure_gateway = 127.0.0.1 - -[port_ws_public] -port = 6008 -ip = 127.0.0.1 -protocol = ws - -#------------------------------------------------------------------------------- - -# This is primary persistent datastore for rippled. This includes transaction -# metadata, account states, and ledger headers. Helpful information can be -# found at https://xrpl.org/capacity-planning.html#node-db-type -# type=NuDB is recommended for non-validators with fast SSDs. Validators or -# slow / spinning disks should use RocksDB. Caution: Spinning disks are -# not recommended. They do not perform well enough to consistently remain -# synced to the network. -# online_delete=512 is recommended to delete old ledgers while maintaining at -# least 512. -# advisory_delete=0 allows the online delete process to run automatically -# when the node has approximately two times the "online_delete" value of -# ledgers. No external administrative command is required to initiate -# deletion. -[node_db] -type=NuDB -path=/var/lib/rippled-reporting/db/nudb -# online_delete=512 # -advisory_delete=0 - -[database_path] -/var/lib/rippled-reporting/db - -# To use Postgres, uncomment this section and fill in the appropriate connection -# info. Postgres can only be used in Reporting Mode. -# To disable writing to the transaction database, uncomment this section, and -# set use_tx_tables=0 -# [ledger_tx_tables] -# conninfo = postgres://:@localhost/ -# use_tx_tables=1 - - -# This needs to be an absolute directory reference, not a relative one. -# Modify this value as required. -[debug_logfile] -/var/log/rippled-reporting/debug.log - -# To use the XRP test network -# (see https://xrpl.org/connect-your-rippled-to-the-xrp-test-net.html), -# use the following [ips] section: -# [ips] -# r.altnet.rippletest.net 51235 - -# File containing trusted validator keys or validator list publishers. -# Unless an absolute path is specified, it will be considered relative to the -# folder in which the rippled.cfg file is located. -[validators_file] -/opt/rippled-reporting/etc/validators.txt - -# 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": "info" } - -# If ssl_verify is 1, certificates will be validated. -# To allow the use of self-signed certificates for development or internal use, -# set to ssl_verify to 0. -[ssl_verify] -1 - - -# To run in Reporting Mode, uncomment this section and fill in the appropriate -# connection info for one or more ETL sources. -[reporting] -etl_source - -[etl_source] -source_grpc_port=50051 -source_ws_port=6005 -source_ip=127.0.0.1 diff --git a/cmake/RippledCore.cmake b/cmake/RippledCore.cmake index 18a424c484b..3b850354ed4 100644 --- a/cmake/RippledCore.cmake +++ b/cmake/RippledCore.cmake @@ -129,14 +129,6 @@ if(xrpld) target_compile_definitions(rippled PRIVATE RIPPLED_RUNNING_IN_CI) endif () - if(reporting) - set(suffix -reporting) - set_target_properties(rippled PROPERTIES OUTPUT_NAME rippled-reporting) - get_target_property(BIN_NAME rippled OUTPUT_NAME) - message(STATUS "Reporting mode build: rippled renamed ${BIN_NAME}") - target_compile_definitions(rippled PRIVATE RIPPLED_REPORTING) - endif() - # any files that don't play well with unity should be added here if(tests) set_source_files_properties( diff --git a/cmake/RippledSettings.cmake b/cmake/RippledSettings.cmake index a431bb61389..b81843cd5b5 100644 --- a/cmake/RippledSettings.cmake +++ b/cmake/RippledSettings.cmake @@ -10,8 +10,6 @@ option(assert "Enables asserts, even in release builds" OFF) option(xrpld "Build xrpld" ON) -option(reporting "Build rippled with reporting mode enabled" OFF) - option(tests "Build tests" ON) option(unity "Creates a build using UNITY support in cmake. This is the default" ON) diff --git a/conanfile.py b/conanfile.py index 425fee8b682..14fc49a1946 100644 --- a/conanfile.py +++ b/conanfile.py @@ -15,7 +15,6 @@ class Xrpl(ConanFile): 'coverage': [True, False], 'fPIC': [True, False], 'jemalloc': [True, False], - 'reporting': [True, False], 'rocksdb': [True, False], 'shared': [True, False], 'static': [True, False], @@ -44,7 +43,6 @@ class Xrpl(ConanFile): 'coverage': False, 'fPIC': True, 'jemalloc': False, - 'reporting': False, 'rocksdb': True, 'shared': False, 'static': True, @@ -52,8 +50,6 @@ class Xrpl(ConanFile): 'unity': False, 'xrpld': False, - 'cassandra-cpp-driver/*:shared': False, - 'cassandra-cpp-driver/*:use_atomic': None, 'date/*:header_only': True, 'grpc/*:shared': False, 'grpc/*:secure': True, @@ -72,7 +68,6 @@ class Xrpl(ConanFile): 'libarchive/*:with_pcreposix': False, 'libarchive/*:with_xattr': False, 'libarchive/*:with_zlib': False, - 'libpq/*:shared': False, 'lz4/*:shared': False, 'openssl/*:shared': False, 'protobuf/*:shared': False, @@ -110,9 +105,6 @@ def requirements(self): self.requires('sqlite3/3.42.0', force=True) if self.options.jemalloc: self.requires('jemalloc/5.3.0') - if self.options.reporting: - self.requires('cassandra-cpp-driver/2.15.3') - self.requires('libpq/14.7') if self.options.rocksdb: self.requires('rocksdb/6.29.5') @@ -139,7 +131,6 @@ def generate(self): tc.variables['assert'] = self.options.assertions tc.variables['coverage'] = self.options.coverage tc.variables['jemalloc'] = self.options.jemalloc - tc.variables['reporting'] = self.options.reporting tc.variables['rocksdb'] = self.options.rocksdb tc.variables['BUILD_SHARED_LIBS'] = self.options.shared tc.variables['static'] = self.options.static diff --git a/include/xrpl/proto/org/xrpl/rpc/v1/xrp_ledger.proto b/include/xrpl/proto/org/xrpl/rpc/v1/xrp_ledger.proto index 995edba48a1..01a23fbe375 100644 --- a/include/xrpl/proto/org/xrpl/rpc/v1/xrp_ledger.proto +++ b/include/xrpl/proto/org/xrpl/rpc/v1/xrp_ledger.proto @@ -11,7 +11,7 @@ import "org/xrpl/rpc/v1/get_ledger_diff.proto"; // These methods are binary only methods for retrieiving arbitrary ledger state -// via gRPC. These methods are used by clio and reporting mode, but can also be +// via gRPC. These methods are used by clio, but can also be // used by any client that wants to extract ledger state in an efficient manner. // They do not directly mimic the JSON equivalent methods. service XRPLedgerAPIService { diff --git a/include/xrpl/protocol/ErrorCodes.h b/include/xrpl/protocol/ErrorCodes.h index 6d5590ec605..d8ec3052b7b 100644 --- a/include/xrpl/protocol/ErrorCodes.h +++ b/include/xrpl/protocol/ErrorCodes.h @@ -136,8 +136,8 @@ enum error_code_i { rpcINVALID_LGR_RANGE = 79, rpcEXPIRED_VALIDATOR_LIST = 80, - // Reporting - rpcFAILED_TO_FORWARD = 90, + // unused = 90, + // DEPRECATED. New code must not use this value. rpcREPORTING_UNSUPPORTED = 91, rpcOBJECT_NOT_FOUND = 92, @@ -148,8 +148,7 @@ enum error_code_i { // Oracle rpcORACLE_MALFORMED = 94, - rpcLAST = - rpcORACLE_MALFORMED // rpcLAST should always equal the last code.= + rpcLAST = rpcORACLE_MALFORMED // rpcLAST should always equal the last code. }; /** Codes returned in the `warnings` array of certain RPC commands. @@ -160,7 +159,7 @@ enum warning_code_i { warnRPC_UNSUPPORTED_MAJORITY = 1001, warnRPC_AMENDMENT_BLOCKED = 1002, warnRPC_EXPIRED_VALIDATOR_LIST = 1003, - warnRPC_REPORTING = 1004 + // unused = 1004 }; //------------------------------------------------------------------------------ diff --git a/src/libxrpl/protocol/ErrorCodes.cpp b/src/libxrpl/protocol/ErrorCodes.cpp index 28024fab093..4c934f4fd53 100644 --- a/src/libxrpl/protocol/ErrorCodes.cpp +++ b/src/libxrpl/protocol/ErrorCodes.cpp @@ -71,7 +71,6 @@ constexpr static ErrorInfo unorderedErrorInfos[]{ {rpcDST_ISR_MALFORMED, "dstIsrMalformed", "Destination issuer is malformed.", 400}, {rpcEXCESSIVE_LGR_RANGE, "excessiveLgrRange", "Ledger range exceeds 1000.", 400}, {rpcFORBIDDEN, "forbidden", "Bad credentials.", 403}, - {rpcFAILED_TO_FORWARD, "failedToForward", "Failed to forward request to p2p node", 503}, {rpcHIGH_FEE, "highFee", "Current transaction fee exceeds your limit.", 402}, {rpcINTERNAL, "internal", "Internal error.", 500}, {rpcINVALID_LGR_RANGE, "invalidLgrRange", "Ledger range is invalid.", 400}, @@ -97,7 +96,6 @@ constexpr static ErrorInfo unorderedErrorInfos[]{ {rpcNO_PF_REQUEST, "noPathRequest", "No pathfinding request in progress.", 404}, {rpcOBJECT_NOT_FOUND, "objectNotFound", "The requested object was not found.", 404}, {rpcPUBLIC_MALFORMED, "publicMalformed", "Public key is malformed.", 400}, - {rpcREPORTING_UNSUPPORTED, "reportingUnsupported", "Requested operation not supported by reporting mode server", 405}, {rpcSENDMAX_MALFORMED, "sendMaxMalformed", "SendMax amount malformed.", 400}, {rpcSIGNING_MALFORMED, "signingMalformed", "Signing of transaction is malformed.", 400}, {rpcSLOW_DOWN, "slowDown", "You are placing too much load on the server.", 429}, diff --git a/src/test/rpc/ReportingETL_test.cpp b/src/test/rpc/ReportingETL_test.cpp deleted file mode 100644 index 8a030938832..00000000000 --- a/src/test/rpc/ReportingETL_test.cpp +++ /dev/null @@ -1,1144 +0,0 @@ - -//------------------------------------------------------------------------------ -/* - 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 -#include -#include - -#include -#include -#include -#include -#include - -namespace ripple { -namespace test { - -class ReportingETL_test : public beast::unit_test::suite -{ - // gRPC stuff - class GrpcLedgerClient : public GRPCTestClientBase - { - public: - org::xrpl::rpc::v1::GetLedgerRequest request; - org::xrpl::rpc::v1::GetLedgerResponse reply; - - explicit GrpcLedgerClient(std::string const& port) - : GRPCTestClientBase(port) - { - } - - void - GetLedger() - { - status = stub_->GetLedger(&context, request, &reply); - } - }; - void - testGetLedger() - { - testcase("GetLedger"); - using namespace test::jtx; - std::unique_ptr config = envconfig(addGrpcConfig); - std::string grpcPort = - *(*config)[SECTION_PORT_GRPC].get("port"); - Env env(*this, std::move(config)); - - env.close(); - - auto ledger = env.app().getLedgerMaster().getLedgerBySeq(3); - - BEAST_EXPECT(env.current()->info().seq == 4); - - auto grpcLedger = [&grpcPort]( - auto sequence, - bool transactions, - bool expand, - bool get_objects, - bool get_object_neighbors) { - GrpcLedgerClient grpcClient{grpcPort}; - - grpcClient.request.mutable_ledger()->set_sequence(sequence); - grpcClient.request.set_transactions(transactions); - grpcClient.request.set_expand(expand); - grpcClient.request.set_get_objects(get_objects); - grpcClient.request.set_get_object_neighbors(get_object_neighbors); - - grpcClient.GetLedger(); - return std::make_pair(grpcClient.status, grpcClient.reply); - }; - - { - auto [status, reply] = grpcLedger(3, false, false, false, false); - - BEAST_EXPECT(status.ok()); - BEAST_EXPECT(reply.validated()); - BEAST_EXPECT(!reply.has_hashes_list()); - BEAST_EXPECT(!reply.has_transactions_list()); - BEAST_EXPECT(!reply.skiplist_included()); - BEAST_EXPECT(reply.ledger_objects().objects_size() == 0); - - Serializer s; - addRaw(ledger->info(), s, true); - BEAST_EXPECT(s.slice() == makeSlice(reply.ledger_header())); - } - - Account const alice{"alice"}; - Account const bob{"bob"}; - env.fund(XRP(10000), alice); - env.fund(XRP(10000), bob); - env.close(); - - ledger = env.app().getLedgerMaster().getLedgerBySeq(4); - - std::vector hashes; - std::vector> transactions; - std::vector> metas; - for (auto& [sttx, meta] : ledger->txs) - { - hashes.push_back(sttx->getTransactionID()); - transactions.push_back(sttx); - metas.push_back(meta); - } - - Serializer s; - addRaw(ledger->info(), s, true); - - { - auto [status, reply] = grpcLedger(4, true, false, false, false); - BEAST_EXPECT(status.ok()); - BEAST_EXPECT(reply.validated()); - BEAST_EXPECT(reply.has_hashes_list()); - BEAST_EXPECT(reply.hashes_list().hashes_size() == hashes.size()); - BEAST_EXPECT( - uint256::fromVoid(reply.hashes_list().hashes(0).data()) == - hashes[0]); - BEAST_EXPECT( - uint256::fromVoid(reply.hashes_list().hashes(1).data()) == - hashes[1]); - BEAST_EXPECT( - uint256::fromVoid(reply.hashes_list().hashes(2).data()) == - hashes[2]); - BEAST_EXPECT( - uint256::fromVoid(reply.hashes_list().hashes(3).data()) == - hashes[3]); - - BEAST_EXPECT(!reply.has_transactions_list()); - BEAST_EXPECT(!reply.skiplist_included()); - BEAST_EXPECT(reply.ledger_objects().objects_size() == 0); - - BEAST_EXPECT(s.slice() == makeSlice(reply.ledger_header())); - } - - { - auto [status, reply] = grpcLedger(4, true, true, false, false); - - BEAST_EXPECT(status.ok()); - BEAST_EXPECT(reply.validated()); - BEAST_EXPECT(!reply.has_hashes_list()); - - BEAST_EXPECT(reply.has_transactions_list()); - BEAST_EXPECT(reply.transactions_list().transactions_size() == 4); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(0) - .transaction_blob()) == - transactions[0]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(0) - .metadata_blob()) == - metas[0]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(1) - .transaction_blob()) == - transactions[1]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(1) - .metadata_blob()) == - metas[1]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(2) - .transaction_blob()) == - transactions[2]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(2) - .metadata_blob()) == - metas[2]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(3) - .transaction_blob()) == - transactions[3]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(3) - .metadata_blob()) == - metas[3]->getSerializer().slice()); - - BEAST_EXPECT(!reply.skiplist_included()); - BEAST_EXPECT(reply.ledger_objects().objects_size() == 0); - - BEAST_EXPECT(s.slice() == makeSlice(reply.ledger_header())); - } - - { - auto [status, reply] = grpcLedger(4, true, true, true, false); - - BEAST_EXPECT(status.ok()); - BEAST_EXPECT(reply.validated()); - BEAST_EXPECT(!reply.has_hashes_list()); - - BEAST_EXPECT(reply.has_transactions_list()); - BEAST_EXPECT(reply.transactions_list().transactions_size() == 4); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(0) - .transaction_blob()) == - transactions[0]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(0) - .metadata_blob()) == - metas[0]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(1) - .transaction_blob()) == - transactions[1]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(1) - .metadata_blob()) == - metas[1]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(2) - .transaction_blob()) == - transactions[2]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(2) - .metadata_blob()) == - metas[2]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(3) - .transaction_blob()) == - transactions[3]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(3) - .metadata_blob()) == - metas[3]->getSerializer().slice()); - BEAST_EXPECT(reply.skiplist_included()); - - BEAST_EXPECT(s.slice() == makeSlice(reply.ledger_header())); - - auto parent = env.app().getLedgerMaster().getLedgerBySeq(3); - - SHAMap::Delta differences; - - int maxDifferences = std::numeric_limits::max(); - - bool res = parent->stateMap().compare( - ledger->stateMap(), differences, maxDifferences); - BEAST_EXPECT(res); - - size_t idx = 0; - for (auto& [k, v] : differences) - { - BEAST_EXPECT( - k == - uint256::fromVoid( - reply.ledger_objects().objects(idx).key().data())); - if (v.second) - { - BEAST_EXPECT( - v.second->slice() == - makeSlice(reply.ledger_objects().objects(idx).data())); - } - ++idx; - } - } - { - auto [status, reply] = grpcLedger(4, true, true, true, true); - - BEAST_EXPECT(status.ok()); - BEAST_EXPECT(reply.validated()); - BEAST_EXPECT(!reply.has_hashes_list()); - BEAST_EXPECT(reply.object_neighbors_included()); - - BEAST_EXPECT(reply.has_transactions_list()); - BEAST_EXPECT(reply.transactions_list().transactions_size() == 4); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(0) - .transaction_blob()) == - transactions[0]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(0) - .metadata_blob()) == - metas[0]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(1) - .transaction_blob()) == - transactions[1]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(1) - .metadata_blob()) == - metas[1]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(2) - .transaction_blob()) == - transactions[2]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(2) - .metadata_blob()) == - metas[2]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(3) - .transaction_blob()) == - transactions[3]->getSerializer().slice()); - - BEAST_EXPECT( - makeSlice(reply.transactions_list() - .transactions(3) - .metadata_blob()) == - metas[3]->getSerializer().slice()); - BEAST_EXPECT(reply.skiplist_included()); - - BEAST_EXPECT(s.slice() == makeSlice(reply.ledger_header())); - - auto parent = env.app().getLedgerMaster().getLedgerBySeq(3); - - SHAMap::Delta differences; - - int maxDifferences = std::numeric_limits::max(); - - bool res = parent->stateMap().compare( - ledger->stateMap(), differences, maxDifferences); - BEAST_EXPECT(res); - - size_t idx = 0; - - for (auto& [k, v] : differences) - { - auto obj = reply.ledger_objects().objects(idx); - BEAST_EXPECT(k == uint256::fromVoid(obj.key().data())); - if (v.second) - { - BEAST_EXPECT(v.second->slice() == makeSlice(obj.data())); - } - else - BEAST_EXPECT(obj.data().size() == 0); - - if (!(v.first && v.second)) - { - auto succ = ledger->stateMap().upper_bound(k); - auto pred = ledger->stateMap().lower_bound(k); - - if (succ != ledger->stateMap().end()) - BEAST_EXPECT( - succ->key() == - uint256::fromVoid(obj.successor().data())); - else - BEAST_EXPECT(obj.successor().size() == 0); - if (pred != ledger->stateMap().end()) - BEAST_EXPECT( - pred->key() == - uint256::fromVoid(obj.predecessor().data())); - else - BEAST_EXPECT(obj.predecessor().size() == 0); - } - ++idx; - } - } - - // Delete an account - - env(noop(alice)); - - std::uint32_t const ledgerCount{ - env.current()->seq() + 257 - env.seq(alice)}; - - for (std::uint32_t i = 0; i < ledgerCount; ++i) - env.close(); - - auto const acctDelFee{drops(env.current()->fees().increment)}; - env(acctdelete(alice, bob), fee(acctDelFee)); - env.close(); - - { - auto [status, reply] = - grpcLedger(env.closed()->seq(), true, true, true, true); - - BEAST_EXPECT(status.ok()); - BEAST_EXPECT(reply.validated()); - auto base = - env.app().getLedgerMaster().getLedgerBySeq(env.closed()->seq()); - - auto parent = env.app().getLedgerMaster().getLedgerBySeq( - env.closed()->seq() - 1); - - SHAMap::Delta differences; - - int maxDifferences = std::numeric_limits::max(); - - bool res = parent->stateMap().compare( - base->stateMap(), differences, maxDifferences); - BEAST_EXPECT(res); - - size_t idx = 0; - for (auto& [k, v] : differences) - { - auto obj = reply.ledger_objects().objects(idx); - BEAST_EXPECT(k == uint256::fromVoid(obj.key().data())); - if (v.second) - { - BEAST_EXPECT( - v.second->slice() == - makeSlice(reply.ledger_objects().objects(idx).data())); - } - else - BEAST_EXPECT(obj.data().size() == 0); - if (!(v.first && v.second)) - { - auto succ = base->stateMap().upper_bound(k); - auto pred = base->stateMap().lower_bound(k); - - if (succ != base->stateMap().end()) - BEAST_EXPECT( - succ->key() == - uint256::fromVoid(obj.successor().data())); - else - BEAST_EXPECT(obj.successor().size() == 0); - if (pred != base->stateMap().end()) - BEAST_EXPECT( - pred->key() == - uint256::fromVoid(obj.predecessor().data())); - else - BEAST_EXPECT(obj.predecessor().size() == 0); - } - - ++idx; - } - } - } - - // gRPC stuff - class GrpcLedgerDataClient : public GRPCTestClientBase - { - public: - org::xrpl::rpc::v1::GetLedgerDataRequest request; - org::xrpl::rpc::v1::GetLedgerDataResponse reply; - - explicit GrpcLedgerDataClient(std::string const& port) - : GRPCTestClientBase(port) - { - } - - void - GetLedgerData() - { - status = stub_->GetLedgerData(&context, request, &reply); - } - }; - void - testGetLedgerData() - { - testcase("GetLedgerData"); - using namespace test::jtx; - std::unique_ptr config = envconfig(addGrpcConfig); - std::string grpcPort = - *(*config)[SECTION_PORT_GRPC].get("port"); - Env env(*this, std::move(config)); - auto grpcLedgerData = [&grpcPort]( - auto sequence, std::string marker = "") { - GrpcLedgerDataClient grpcClient{grpcPort}; - - grpcClient.request.mutable_ledger()->set_sequence(sequence); - if (marker.size()) - { - grpcClient.request.set_marker(marker); - } - - grpcClient.GetLedgerData(); - return std::make_pair(grpcClient.status, grpcClient.reply); - }; - - Account const alice{"alice"}; - env.fund(XRP(100000), alice); - - int num_accounts = 10; - - for (auto i = 0; i < num_accounts; i++) - { - Account const bob{std::string("bob") + std::to_string(i)}; - env.fund(XRP(1000), bob); - } - env.close(); - - { - auto [status, reply] = grpcLedgerData(env.closed()->seq()); - BEAST_EXPECT(status.ok()); - - BEAST_EXPECT( - reply.ledger_objects().objects_size() == num_accounts + 4); - BEAST_EXPECT(reply.marker().size() == 0); - auto ledger = env.closed(); - size_t idx = 0; - for (auto& sle : ledger->sles) - { - BEAST_EXPECT( - sle->getSerializer().slice() == - makeSlice(reply.ledger_objects().objects(idx).data())); - ++idx; - } - } - - { - auto [status, reply] = - grpcLedgerData(env.closed()->seq(), "bad marker"); - BEAST_EXPECT(!status.ok()); - BEAST_EXPECT( - status.error_code() == grpc::StatusCode::INVALID_ARGUMENT); - } - - num_accounts = 3000; - - for (auto i = 0; i < num_accounts; i++) - { - Account const cat{std::string("cat") + std::to_string(i)}; - env.fund(XRP(1000), cat); - if (i % 100 == 0) - env.close(); - } - env.close(); - - { - auto [status, reply] = grpcLedgerData(env.closed()->seq()); - BEAST_EXPECT(status.ok()); - - int maxLimit = RPC::Tuning::pageLength(true); - BEAST_EXPECT(reply.ledger_objects().objects_size() == maxLimit); - BEAST_EXPECT(reply.marker().size() != 0); - - auto [status2, reply2] = - grpcLedgerData(env.closed()->seq(), reply.marker()); - BEAST_EXPECT(status2.ok()); - BEAST_EXPECT(reply2.marker().size() == 0); - - auto ledger = env.closed(); - size_t idx = 0; - for (auto& sle : ledger->sles) - { - auto& obj = idx < maxLimit - ? reply.ledger_objects().objects(idx) - : reply2.ledger_objects().objects(idx - maxLimit); - - BEAST_EXPECT( - sle->getSerializer().slice() == makeSlice(obj.data())); - ++idx; - } - BEAST_EXPECT( - idx == - reply.ledger_objects().objects_size() + - reply2.ledger_objects().objects_size()); - } - } - - // gRPC stuff - class GrpcLedgerDiffClient : public GRPCTestClientBase - { - public: - org::xrpl::rpc::v1::GetLedgerDiffRequest request; - org::xrpl::rpc::v1::GetLedgerDiffResponse reply; - - explicit GrpcLedgerDiffClient(std::string const& port) - : GRPCTestClientBase(port) - { - } - - void - GetLedgerDiff() - { - status = stub_->GetLedgerDiff(&context, request, &reply); - } - }; - - void - testGetLedgerDiff() - { - testcase("GetLedgerDiff"); - using namespace test::jtx; - std::unique_ptr config = envconfig(addGrpcConfig); - std::string grpcPort = - *(*config)[SECTION_PORT_GRPC].get("port"); - Env env(*this, std::move(config)); - - auto grpcLedgerDiff = [&grpcPort]( - auto baseSequence, auto desiredSequence) { - GrpcLedgerDiffClient grpcClient{grpcPort}; - - grpcClient.request.mutable_base_ledger()->set_sequence( - baseSequence); - grpcClient.request.mutable_desired_ledger()->set_sequence( - desiredSequence); - grpcClient.request.set_include_blobs(true); - - grpcClient.GetLedgerDiff(); - return std::make_pair(grpcClient.status, grpcClient.reply); - }; - - int num_accounts = 20; - for (auto i = 0; i < num_accounts; i++) - { - Account const cat{std::string("cat") + std::to_string(i)}; - env.fund(XRP(1000), cat); - if (i % 2 == 0) - env.close(); - } - env.close(); - - auto compareDiffs = [&](auto baseSequence, auto desiredSequence) { - auto [status, reply] = - grpcLedgerDiff(baseSequence, desiredSequence); - - BEAST_EXPECT(status.ok()); - auto desired = - env.app().getLedgerMaster().getLedgerBySeq(desiredSequence); - - auto base = - env.app().getLedgerMaster().getLedgerBySeq(baseSequence); - - SHAMap::Delta differences; - - int maxDifferences = std::numeric_limits::max(); - - bool res = base->stateMap().compare( - desired->stateMap(), differences, maxDifferences); - if (!BEAST_EXPECT(res)) - return false; - - size_t idx = 0; - for (auto& [k, v] : differences) - { - if (!BEAST_EXPECT( - k == - uint256::fromVoid( - reply.ledger_objects().objects(idx).key().data()))) - return false; - if (v.second) - { - if (!BEAST_EXPECT( - v.second->slice() == - makeSlice( - reply.ledger_objects().objects(idx).data()))) - return false; - } - - ++idx; - } - return true; - }; - - // Adjacent ledgers - BEAST_EXPECT( - compareDiffs(env.closed()->seq() - 1, env.closed()->seq())); - - // Adjacent ledgers further in the past - BEAST_EXPECT( - compareDiffs(env.closed()->seq() - 3, env.closed()->seq() - 2)); - - // Non-adjacent ledgers - BEAST_EXPECT( - compareDiffs(env.closed()->seq() - 5, env.closed()->seq() - 1)); - - // Adjacent ledgers but in reverse order - BEAST_EXPECT( - compareDiffs(env.closed()->seq(), env.closed()->seq() - 1)); - - // Non-adjacent ledgers in reverse order - BEAST_EXPECT( - compareDiffs(env.closed()->seq() - 1, env.closed()->seq() - 5)); - } - - // gRPC stuff - class GrpcLedgerEntryClient : public GRPCTestClientBase - { - public: - org::xrpl::rpc::v1::GetLedgerEntryRequest request; - org::xrpl::rpc::v1::GetLedgerEntryResponse reply; - - explicit GrpcLedgerEntryClient(std::string const& port) - : GRPCTestClientBase(port) - { - } - - void - GetLedgerEntry() - { - status = stub_->GetLedgerEntry(&context, request, &reply); - } - }; - - void - testGetLedgerEntry() - { - testcase("GetLedgerDiff"); - using namespace test::jtx; - std::unique_ptr config = envconfig(addGrpcConfig); - std::string grpcPort = - *(*config)[SECTION_PORT_GRPC].get("port"); - Env env(*this, std::move(config)); - - auto grpcLedgerEntry = [&grpcPort](auto sequence, auto key) { - GrpcLedgerEntryClient grpcClient{grpcPort}; - - grpcClient.request.mutable_ledger()->set_sequence(sequence); - grpcClient.request.set_key(key.data(), key.size()); - - grpcClient.GetLedgerEntry(); - return std::make_pair(grpcClient.status, grpcClient.reply); - }; - - Account const alice{"alice"}; - env.fund(XRP(1000), alice); - env.close(); - - for (auto& sle : env.closed()->sles) - { - auto [status, reply] = - grpcLedgerEntry(env.closed()->seq(), sle->key()); - - BEAST_EXPECT(status.ok()); - - BEAST_EXPECT( - uint256::fromVoid(reply.ledger_object().key().data()) == - sle->key()); - BEAST_EXPECT( - makeSlice(reply.ledger_object().data()) == - sle->getSerializer().slice()); - } - } - - void - testNeedCurrentOrClosed() - { - testcase("NeedCurrentOrClosed"); - - { - org::xrpl::rpc::v1::GetLedgerRequest request; - request.mutable_ledger()->set_sequence(1); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_ledger()->set_hash(""); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_UNSPECIFIED); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT); - BEAST_EXPECT(needCurrentOrClosed(request)); - request.mutable_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CLOSED); - BEAST_EXPECT(needCurrentOrClosed(request)); - } - - { - org::xrpl::rpc::v1::GetLedgerDataRequest request; - request.mutable_ledger()->set_sequence(1); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_ledger()->set_hash(""); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_UNSPECIFIED); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT); - BEAST_EXPECT(needCurrentOrClosed(request)); - request.mutable_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CLOSED); - BEAST_EXPECT(needCurrentOrClosed(request)); - } - - { - org::xrpl::rpc::v1::GetLedgerEntryRequest request; - request.mutable_ledger()->set_sequence(1); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_ledger()->set_hash(""); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_UNSPECIFIED); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT); - BEAST_EXPECT(needCurrentOrClosed(request)); - request.mutable_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CLOSED); - BEAST_EXPECT(needCurrentOrClosed(request)); - } - - { - org::xrpl::rpc::v1::GetLedgerDiffRequest request; - - // set desired ledger, so desired ledger does not need current or - // closed - request.mutable_base_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED); - - request.mutable_base_ledger()->set_sequence(1); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_base_ledger()->set_hash(""); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_base_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_base_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_UNSPECIFIED); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_base_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT); - BEAST_EXPECT(needCurrentOrClosed(request)); - request.mutable_base_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CLOSED); - BEAST_EXPECT(needCurrentOrClosed(request)); - - // reset base ledger, so base ledger doesn't need current or closed - request.mutable_base_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED); - - request.mutable_desired_ledger()->set_sequence(1); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_desired_ledger()->set_hash(""); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_desired_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_desired_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_UNSPECIFIED); - BEAST_EXPECT(!needCurrentOrClosed(request)); - request.mutable_desired_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT); - BEAST_EXPECT(needCurrentOrClosed(request)); - request.mutable_desired_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CLOSED); - BEAST_EXPECT(needCurrentOrClosed(request)); - - // both base and desired need current or closed - request.mutable_base_ledger()->set_shortcut( - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT); - BEAST_EXPECT(needCurrentOrClosed(request)); - } - } - - void - testSecureGateway() - { - testcase("SecureGateway"); - using namespace test::jtx; - { - std::unique_ptr config = envconfig( - addGrpcConfigWithSecureGateway, getEnvLocalhostAddr()); - std::string grpcPort = - *(*config)[SECTION_PORT_GRPC].get("port"); - Env env(*this, std::move(config)); - - env.close(); - - auto ledger = env.app().getLedgerMaster().getLedgerBySeq(3); - - BEAST_EXPECT(env.current()->info().seq == 4); - - auto grpcLedger = [&grpcPort]( - auto sequence, - std::string const& clientIp, - std::string const& user) { - GrpcLedgerClient grpcClient{grpcPort}; - - grpcClient.request.mutable_ledger()->set_sequence(sequence); - grpcClient.request.set_client_ip(clientIp); - grpcClient.request.set_user(user); - - grpcClient.GetLedger(); - return std::make_pair(grpcClient.status, grpcClient.reply); - }; - - { - auto [status, reply] = - grpcLedger(env.current()->info().seq, "", ""); - BEAST_EXPECT(!reply.is_unlimited()); - BEAST_EXPECT(status.ok()); - } - { - auto [status, reply] = - grpcLedger(env.current()->info().seq, "", "ETL"); - BEAST_EXPECT(reply.is_unlimited()); - BEAST_EXPECT(status.ok()); - } - { - auto [status, reply] = - grpcLedger(env.current()->info().seq, "", "Reporting"); - BEAST_EXPECT(reply.is_unlimited()); - BEAST_EXPECT(status.ok()); - } - { - auto [status, reply] = - grpcLedger(env.current()->info().seq, "127.0.0.1", "ETL"); - BEAST_EXPECT(!reply.is_unlimited()); - BEAST_EXPECT(status.ok()); - } - { - auto [status, reply] = - grpcLedger(env.current()->info().seq, "127.0.0.1", ""); - BEAST_EXPECT(!reply.is_unlimited()); - BEAST_EXPECT(status.ok()); - } - } - - { - std::string secureGatewayIp = "44.124.234.79"; - std::unique_ptr config = - envconfig(addGrpcConfigWithSecureGateway, secureGatewayIp); - std::string grpcPort = - *(*config)[SECTION_PORT_GRPC].get("port"); - Env env(*this, std::move(config)); - - env.close(); - - auto ledger = env.app().getLedgerMaster().getLedgerBySeq(3); - - BEAST_EXPECT(env.current()->info().seq == 4); - - auto grpcLedger = [&grpcPort]( - auto sequence, - std::string const& clientIp, - std::string const& user) { - GrpcLedgerClient grpcClient{grpcPort}; - - grpcClient.request.mutable_ledger()->set_sequence(sequence); - grpcClient.request.set_client_ip(clientIp); - grpcClient.request.set_user(user); - - grpcClient.GetLedger(); - return std::make_pair(grpcClient.status, grpcClient.reply); - }; - - { - auto [status, reply] = - grpcLedger(env.current()->info().seq, "", ""); - BEAST_EXPECT(!reply.is_unlimited()); - BEAST_EXPECT(status.ok()); - } - { - auto [status, reply] = - grpcLedger(env.current()->info().seq, "", "ETL"); - BEAST_EXPECT(!reply.is_unlimited()); - BEAST_EXPECT(status.ok()); - } - { - auto [status, reply] = grpcLedger( - env.current()->info().seq, secureGatewayIp, "ETL"); - BEAST_EXPECT(!reply.is_unlimited()); - BEAST_EXPECT(status.ok()); - } - { - auto [status, reply] = - grpcLedger(env.current()->info().seq, secureGatewayIp, ""); - BEAST_EXPECT(!reply.is_unlimited()); - BEAST_EXPECT(status.ok()); - } - } - - { - std::unique_ptr config = envconfig( - addGrpcConfigWithSecureGateway, getEnvLocalhostAddr()); - std::string grpcPort = - *(*config)[SECTION_PORT_GRPC].get("port"); - Env env(*this, std::move(config)); - - env.close(); - - auto ledger = env.app().getLedgerMaster().getLedgerBySeq(3); - - BEAST_EXPECT(env.current()->info().seq == 4); - auto grpcLedgerData = [&grpcPort]( - auto sequence, - std::string const& clientIp, - std::string const& user) { - GrpcLedgerDataClient grpcClient{grpcPort}; - - grpcClient.request.mutable_ledger()->set_sequence(sequence); - grpcClient.request.set_client_ip(clientIp); - grpcClient.request.set_user(user); - - grpcClient.GetLedgerData(); - return std::make_pair(grpcClient.status, grpcClient.reply); - }; - { - auto [status, reply] = - grpcLedgerData(env.current()->info().seq, "", ""); - BEAST_EXPECT(!reply.is_unlimited()); - BEAST_EXPECT(status.ok()); - } - { - auto [status, reply] = - grpcLedgerData(env.current()->info().seq, "", "ETL"); - BEAST_EXPECT(reply.is_unlimited()); - BEAST_EXPECT(status.ok()); - } - { - auto [status, reply] = - grpcLedgerData(env.current()->info().seq, "", "Reporting"); - BEAST_EXPECT(reply.is_unlimited()); - BEAST_EXPECT(status.ok()); - } - { - auto [status, reply] = grpcLedgerData( - env.current()->info().seq, "127.0.0.1", "ETL"); - BEAST_EXPECT(!reply.is_unlimited()); - BEAST_EXPECT(status.ok()); - } - { - auto [status, reply] = - grpcLedgerData(env.current()->info().seq, "127.0.0.1", ""); - BEAST_EXPECT(!reply.is_unlimited()); - BEAST_EXPECT(status.ok()); - } - } - { - std::string secureGatewayIp = "44.124.234.79"; - std::unique_ptr config = - envconfig(addGrpcConfigWithSecureGateway, secureGatewayIp); - std::string grpcPort = - *(*config)[SECTION_PORT_GRPC].get("port"); - Env env(*this, std::move(config)); - - env.close(); - - auto ledger = env.app().getLedgerMaster().getLedgerBySeq(3); - - BEAST_EXPECT(env.current()->info().seq == 4); - - auto grpcLedgerData = [&grpcPort]( - auto sequence, - std::string const& clientIp, - std::string const& user) { - GrpcLedgerDataClient grpcClient{grpcPort}; - - grpcClient.request.mutable_ledger()->set_sequence(sequence); - grpcClient.request.set_client_ip(clientIp); - grpcClient.request.set_user(user); - - grpcClient.GetLedgerData(); - return std::make_pair(grpcClient.status, grpcClient.reply); - }; - - { - auto [status, reply] = - grpcLedgerData(env.current()->info().seq, "", ""); - BEAST_EXPECT(!reply.is_unlimited()); - BEAST_EXPECT(status.ok()); - } - { - auto [status, reply] = - grpcLedgerData(env.current()->info().seq, "", "ETL"); - BEAST_EXPECT(!reply.is_unlimited()); - BEAST_EXPECT(status.ok()); - } - { - auto [status, reply] = grpcLedgerData( - env.current()->info().seq, secureGatewayIp, "ETL"); - BEAST_EXPECT(!reply.is_unlimited()); - BEAST_EXPECT(status.ok()); - } - { - auto [status, reply] = grpcLedgerData( - env.current()->info().seq, secureGatewayIp, ""); - BEAST_EXPECT(!reply.is_unlimited()); - BEAST_EXPECT(status.ok()); - } - } - } - -public: - void - run() override - { - testGetLedger(); - - testGetLedgerData(); - - testGetLedgerDiff(); - - testGetLedgerEntry(); - - testNeedCurrentOrClosed(); - - testSecureGateway(); - } -}; - -BEAST_DEFINE_TESTSUITE_PRIO(ReportingETL, app, ripple, 2); - -} // namespace test -} // namespace ripple diff --git a/src/xrpld/app/ledger/AcceptedLedger.cpp b/src/xrpld/app/ledger/AcceptedLedger.cpp index 37c943679da..a82323f6286 100644 --- a/src/xrpld/app/ledger/AcceptedLedger.cpp +++ b/src/xrpld/app/ledger/AcceptedLedger.cpp @@ -36,17 +36,8 @@ AcceptedLedger::AcceptedLedger( ledger, item.first, item.second)); }; - if (app.config().reporting()) - { - auto const txs = flatFetchTransactions(*ledger, app); - transactions_.reserve(txs.size()); - insertAll(txs); - } - else - { - transactions_.reserve(256); - insertAll(ledger->txs); - } + transactions_.reserve(256); + insertAll(ledger->txs); std::sort( transactions_.begin(), diff --git a/src/xrpld/app/ledger/Ledger.cpp b/src/xrpld/app/ledger/Ledger.cpp index bcd3b6d4ba7..4991b551cd1 100644 --- a/src/xrpld/app/ledger/Ledger.cpp +++ b/src/xrpld/app/ledger/Ledger.cpp @@ -29,12 +29,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include #include @@ -258,11 +256,6 @@ Ledger::Ledger( if (info_.txHash.isNonZero() && !txMap_.fetchRoot(SHAMapHash{info_.txHash}, nullptr)) { - if (config.reporting()) - { - // Reporting should never have incomplete data - Throw("Missing tx map root for ledger"); - } loaded = false; JLOG(j.warn()) << "Don't have transaction root for ledger" << info_.seq; } @@ -270,11 +263,6 @@ Ledger::Ledger( if (info_.accountHash.isNonZero() && !stateMap_.fetchRoot(SHAMapHash{info_.accountHash}, nullptr)) { - if (config.reporting()) - { - // Reporting should never have incomplete data - Throw("Missing state map root for ledger"); - } loaded = false; JLOG(j.warn()) << "Don't have state data root for ledger" << info_.seq; } @@ -289,7 +277,7 @@ Ledger::Ledger( if (!loaded) { info_.hash = calculateLedgerHash(info_); - if (acquire && !config.reporting()) + if (acquire) family.missingNodeAcquireByHash(info_.hash, info_.seq); } } @@ -1146,92 +1134,4 @@ loadByHash(uint256 const& ledgerHash, Application& app, bool acquire) return {}; } -std::vector< - std::pair, std::shared_ptr>> -flatFetchTransactions(Application& app, std::vector& nodestoreHashes) -{ - if (!app.config().reporting()) - { - assert(false); - Throw( - "flatFetchTransactions: not running in reporting mode"); - } - - std::vector< - std::pair, std::shared_ptr>> - txns; - auto start = std::chrono::system_clock::now(); - auto nodeDb = - dynamic_cast(&(app.getNodeStore())); - if (!nodeDb) - { - assert(false); - Throw( - "Called flatFetchTransactions but database is not DatabaseNodeImp"); - } - auto objs = nodeDb->fetchBatch(nodestoreHashes); - - auto end = std::chrono::system_clock::now(); - JLOG(app.journal("Ledger").debug()) - << " Flat fetch time : " << ((end - start).count() / 1000000000.0) - << " number of transactions " << nodestoreHashes.size(); - assert(objs.size() == nodestoreHashes.size()); - for (size_t i = 0; i < objs.size(); ++i) - { - uint256& nodestoreHash = nodestoreHashes[i]; - auto& obj = objs[i]; - if (obj) - { - auto node = SHAMapTreeNode::makeFromPrefix( - makeSlice(obj->getData()), SHAMapHash{nodestoreHash}); - if (!node) - { - assert(false); - Throw( - "flatFetchTransactions : Error making SHAMap node"); - } - auto item = (static_cast(node.get()))->peekItem(); - if (!item) - { - assert(false); - Throw( - "flatFetchTransactions : Error reading SHAMap node"); - } - auto txnPlusMeta = deserializeTxPlusMeta(*item); - if (!txnPlusMeta.first || !txnPlusMeta.second) - { - assert(false); - Throw( - "flatFetchTransactions : Error deserializing SHAMap node"); - } - txns.push_back(std::move(txnPlusMeta)); - } - else - { - assert(false); - Throw( - "flatFetchTransactions : Containing SHAMap node not found"); - } - } - return txns; -} -std::vector< - std::pair, std::shared_ptr>> -flatFetchTransactions(ReadView const& ledger, Application& app) -{ - if (!app.config().reporting()) - { - assert(false); - return {}; - } - - auto const db = - dynamic_cast(&app.getRelationalDatabase()); - if (!db) - Throw("Failed to get relational database"); - - auto nodestoreHashes = db->getTxHashes(ledger.info().seq); - - return flatFetchTransactions(app, nodestoreHashes); -} } // namespace ripple diff --git a/src/xrpld/app/ledger/Ledger.h b/src/xrpld/app/ledger/Ledger.h index 1591fae1472..0eb102eb518 100644 --- a/src/xrpld/app/ledger/Ledger.h +++ b/src/xrpld/app/ledger/Ledger.h @@ -454,32 +454,6 @@ loadByHash(uint256 const& ledgerHash, Application& app, bool acquire = true); extern std::tuple, std::uint32_t, uint256> getLatestLedger(Application& app); -// *** Reporting Mode Only *** -// Fetch all of the transactions contained in ledger from the nodestore. -// The transactions are fetched directly as a batch, instead of traversing the -// transaction SHAMap. Fetching directly is significantly faster than -// traversing, as there are less database reads, and all of the reads can -// executed concurrently. This function only works in reporting mode. -// @param ledger the ledger for which to fetch the contained transactions -// @param app reference to the Application -// @return vector of (transaction, metadata) pairs -extern std::vector< - std::pair, std::shared_ptr>> -flatFetchTransactions(ReadView const& ledger, Application& app); - -// *** Reporting Mode Only *** -// For each nodestore hash, fetch the transaction. -// The transactions are fetched directly as a batch, instead of traversing the -// transaction SHAMap. Fetching directly is significantly faster than -// traversing, as there are less database reads, and all of the reads can -// executed concurrently. This function only works in reporting mode. -// @param nodestoreHashes hashes of the transactions to fetch -// @param app reference to the Application -// @return vector of (transaction, metadata) pairs -extern std::vector< - std::pair, std::shared_ptr>> -flatFetchTransactions(Application& app, std::vector& nodestoreHashes); - /** Deserialize a SHAMapItem containing a single STTx Throw: diff --git a/src/xrpld/app/ledger/LedgerMaster.h b/src/xrpld/app/ledger/LedgerMaster.h index 5149424e285..dd7f0b6a614 100644 --- a/src/xrpld/app/ledger/LedgerMaster.h +++ b/src/xrpld/app/ledger/LedgerMaster.h @@ -46,24 +46,6 @@ namespace ripple { class Peer; class Transaction; -// This error is thrown when a codepath tries to access the open or closed -// ledger while the server is running in reporting mode. Any RPCs that request -// the open or closed ledger should be forwarded to a p2p node. Usually, the -// decision to forward is made based on the required condition of the handler, -// or which ledger is specified. However, there are some codepaths which are not -// covered by the aforementioned logic (though they probably should), so this -// error is thrown in case a codepath falls through the cracks. -class ReportingShouldProxy : public std::runtime_error -{ -public: - ReportingShouldProxy() - : std::runtime_error( - "Reporting mode has no open or closed ledger. Proxy this " - "request") - { - } -}; - // Tracks the current ledger and any ledgers in the process of closing // Tracks ledger history // Tracks held transactions @@ -97,10 +79,6 @@ class LedgerMaster : public AbstractFetchPackContainer std::shared_ptr getClosedLedger() { - if (app_.config().reporting()) - { - Throw(); - } return mClosedLedger.get(); } diff --git a/src/xrpld/app/ledger/detail/LedgerMaster.cpp b/src/xrpld/app/ledger/detail/LedgerMaster.cpp index dab8f838249..d1eeabeb619 100644 --- a/src/xrpld/app/ledger/detail/LedgerMaster.cpp +++ b/src/xrpld/app/ledger/detail/LedgerMaster.cpp @@ -34,10 +34,9 @@ #include #include #include -#include +#include #include #include -#include #include #include #include @@ -274,12 +273,6 @@ LedgerMaster::getValidatedLedgerAge() { using namespace std::chrono_literals; -#ifdef RIPPLED_REPORTING - if (app_.config().reporting()) - return static_cast(&app_.getRelationalDatabase()) - ->getValidatedLedgerAge(); -#endif - std::chrono::seconds valClose{mValidLedgerSign.load()}; if (valClose == 0s) { @@ -305,12 +298,6 @@ LedgerMaster::isCaughtUp(std::string& reason) { using namespace std::chrono_literals; -#ifdef RIPPLED_REPORTING - if (app_.config().reporting()) - return static_cast(&app_.getRelationalDatabase()) - ->isCaughtUp(reason); -#endif - if (getPublishedLedgerAge() > 3min) { reason = "No recently-published ledger"; @@ -600,9 +587,6 @@ LedgerMaster::clearLedger(std::uint32_t seq) bool LedgerMaster::isValidated(ReadView const& ledger) { - if (app_.config().reporting()) - return true; // Reporting mode only supports validated ledger - if (ledger.open()) return false; @@ -676,32 +660,6 @@ LedgerMaster::getFullValidatedRange( bool LedgerMaster::getValidatedRange(std::uint32_t& minVal, std::uint32_t& maxVal) { - if (app_.config().reporting()) - { - std::string res = getCompleteLedgers(); - try - { - if (res == "empty" || res == "error" || res.empty()) - return false; - else if (size_t delim = res.find('-'); delim != std::string::npos) - { - minVal = std::stol(res.substr(0, delim)); - maxVal = std::stol(res.substr(delim + 1)); - } - else - { - minVal = maxVal = std::stol(res); - } - return true; - } - catch (std::exception const& e) - { - JLOG(m_journal.error()) << "LedgerMaster::getValidatedRange: " - "exception parsing complete ledgers: " - << e.what(); - return false; - } - } if (!getFullValidatedRange(minVal, maxVal)) return false; @@ -1679,25 +1637,12 @@ LedgerMaster::peekMutex() std::shared_ptr LedgerMaster::getCurrentLedger() { - if (app_.config().reporting()) - { - Throw(); - } return app_.openLedger().current(); } std::shared_ptr LedgerMaster::getValidatedLedger() { -#ifdef RIPPLED_REPORTING - if (app_.config().reporting()) - { - auto seq = app_.getRelationalDatabase().getMaxLedgerSeq(); - if (!seq) - return {}; - return getLedgerBySeq(*seq); - } -#endif return mValidLedger.get(); } @@ -1726,11 +1671,6 @@ LedgerMaster::getPublishedLedger() std::string LedgerMaster::getCompleteLedgers() { -#ifdef RIPPLED_REPORTING - if (app_.config().reporting()) - return static_cast(&app_.getRelationalDatabase()) - ->getCompleteLedgers(); -#endif std::lock_guard sl(mCompleteLock); return to_string(mCompleteLedgers); } diff --git a/src/xrpld/app/ledger/detail/LedgerToJson.cpp b/src/xrpld/app/ledger/detail/LedgerToJson.cpp index 95b572e9736..9824b31d794 100644 --- a/src/xrpld/app/ledger/detail/LedgerToJson.cpp +++ b/src/xrpld/app/ledger/detail/LedgerToJson.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -232,14 +231,7 @@ fillJsonTx(Object& json, LedgerFill const& fill) } }; - if (fill.context && fill.context->app.config().reporting()) - { - appendAll(flatFetchTransactions(fill.ledger, fill.context->app)); - } - else - { - appendAll(fill.ledger.txs); - } + appendAll(fill.ledger.txs); } catch (std::exception const& ex) { diff --git a/src/xrpld/app/main/Application.cpp b/src/xrpld/app/main/Application.cpp index f3308a091dc..d234f539909 100644 --- a/src/xrpld/app/main/Application.cpp +++ b/src/xrpld/app/main/Application.cpp @@ -45,9 +45,8 @@ #include #include #include +#include #include -#include -#include #include #include #include @@ -236,7 +235,6 @@ class ApplicationImp : public Application, public BasicApp io_latency_sampler m_io_latency_sampler; std::unique_ptr grpcServer_; - std::unique_ptr reportingETL_; //-------------------------------------------------------------------------- @@ -296,8 +294,7 @@ class ApplicationImp : public Application, public BasicApp , m_jobQueue(std::make_unique( [](std::unique_ptr const& config) { - if (config->standalone() && !config->reporting() && - !config->FORCE_MULTI_THREAD) + if (config->standalone() && !config->FORCE_MULTI_THREAD) return 1; if (config->WORKERS) @@ -475,9 +472,6 @@ class ApplicationImp : public Application, public BasicApp std::chrono::milliseconds(100), get_io_service()) , grpcServer_(std::make_unique(*this)) - , reportingETL_( - config_->reporting() ? std::make_unique(*this) - : nullptr) { initAccountIdCache(config_->getValueFor(SizedItem::accountIdCacheSize)); @@ -786,16 +780,12 @@ class ApplicationImp : public Application, public BasicApp OpenLedger& openLedger() override { - if (config_->reporting()) - Throw(); return *openLedger_; } OpenLedger const& openLedger() const override { - if (config_->reporting()) - Throw(); return *openLedger_; } @@ -827,13 +817,6 @@ class ApplicationImp : public Application, public BasicApp return *mWalletDB; } - ReportingETL& - getReportingETL() override - { - assert(reportingETL_.get() != nullptr); - return *reportingETL_; - } - bool serverOkay(std::string& reason) override; @@ -1129,11 +1112,6 @@ class ApplicationImp : public Application, public BasicApp << "; size after: " << cachedSLEs_.size(); } -#ifdef RIPPLED_REPORTING - if (auto pg = dynamic_cast(&*mRelationalDatabase)) - pg->sweep(); -#endif - // Set timer to do another sweep later. setSweepTimer(); } @@ -1275,53 +1253,50 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) auto const startUp = config_->START_UP; JLOG(m_journal.debug()) << "startUp: " << startUp; - if (!config_->reporting()) + if (startUp == Config::FRESH) { - if (startUp == Config::FRESH) - { - JLOG(m_journal.info()) << "Starting new Ledger"; + JLOG(m_journal.info()) << "Starting new Ledger"; - startGenesisLedger(); - } - else if ( - startUp == Config::LOAD || startUp == Config::LOAD_FILE || - startUp == Config::REPLAY) - { - JLOG(m_journal.info()) << "Loading specified Ledger"; + startGenesisLedger(); + } + else if ( + startUp == Config::LOAD || startUp == Config::LOAD_FILE || + startUp == Config::REPLAY) + { + JLOG(m_journal.info()) << "Loading specified Ledger"; - if (!loadOldLedger( - config_->START_LEDGER, - startUp == Config::REPLAY, - startUp == Config::LOAD_FILE, - config_->TRAP_TX_HASH)) + if (!loadOldLedger( + config_->START_LEDGER, + startUp == Config::REPLAY, + startUp == Config::LOAD_FILE, + config_->TRAP_TX_HASH)) + { + JLOG(m_journal.error()) + << "The specified ledger could not be loaded."; + if (config_->FAST_LOAD) { - JLOG(m_journal.error()) - << "The specified ledger could not be loaded."; - if (config_->FAST_LOAD) - { - // Fall back to syncing from the network, such as - // when there's no existing data. - startGenesisLedger(); - } - else - { - return false; - } + // Fall back to syncing from the network, such as + // when there's no existing data. + startGenesisLedger(); + } + else + { + return false; } } - else if (startUp == Config::NETWORK) - { - // This should probably become the default once we have a stable - // network. - if (!config_->standalone()) - m_networkOPs->setNeedNetworkLedger(); + } + else if (startUp == Config::NETWORK) + { + // This should probably become the default once we have a stable + // network. + if (!config_->standalone()) + m_networkOPs->setNeedNetworkLedger(); - startGenesisLedger(); - } - else - { - startGenesisLedger(); - } + startGenesisLedger(); + } + else + { + startGenesisLedger(); } if (auto const& forcedRange = config().FORCED_LEDGER_RANGE_PRESENT) @@ -1330,8 +1305,7 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) forcedRange->first, forcedRange->second); } - if (!config().reporting()) - m_orderBookDB.setup(getLedgerMaster().getCurrentLedger()); + m_orderBookDB.setup(getLedgerMaster().getCurrentLedger()); nodeIdentity_ = getNodeIdentity(*this, cmdline); @@ -1341,60 +1315,55 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) return false; } - if (!config().reporting()) { - { - if (validatorKeys_.configInvalid()) - return false; - - if (!validatorManifests_->load( - getWalletDB(), - "ValidatorManifests", - validatorKeys_.manifest, - config() - .section(SECTION_VALIDATOR_KEY_REVOCATION) - .values())) - { - JLOG(m_journal.fatal()) - << "Invalid configured validator manifest."; - return false; - } + if (validatorKeys_.configInvalid()) + return false; - publisherManifests_->load(getWalletDB(), "PublisherManifests"); + if (!validatorManifests_->load( + getWalletDB(), + "ValidatorManifests", + validatorKeys_.manifest, + config().section(SECTION_VALIDATOR_KEY_REVOCATION).values())) + { + JLOG(m_journal.fatal()) << "Invalid configured validator manifest."; + return false; + } - // It is possible to have a valid ValidatorKeys object without - // setting the signingKey or masterKey. This occurs if the - // configuration file does not have either - // SECTION_VALIDATOR_TOKEN or SECTION_VALIDATION_SEED section. + publisherManifests_->load(getWalletDB(), "PublisherManifests"); - // masterKey for the configuration-file specified validator keys - std::optional localSigningKey; - if (validatorKeys_.keys) - localSigningKey = validatorKeys_.keys->publicKey; + // It is possible to have a valid ValidatorKeys object without + // setting the signingKey or masterKey. This occurs if the + // configuration file does not have either + // SECTION_VALIDATOR_TOKEN or SECTION_VALIDATION_SEED section. - // Setup trusted validators - if (!validators_->load( - localSigningKey, - config().section(SECTION_VALIDATORS).values(), - config().section(SECTION_VALIDATOR_LIST_KEYS).values())) - { - JLOG(m_journal.fatal()) - << "Invalid entry in validator configuration."; - return false; - } - } + // masterKey for the configuration-file specified validator keys + std::optional localSigningKey; + if (validatorKeys_.keys) + localSigningKey = validatorKeys_.keys->publicKey; - if (!validatorSites_->load( - config().section(SECTION_VALIDATOR_LIST_SITES).values())) + // Setup trusted validators + if (!validators_->load( + localSigningKey, + config().section(SECTION_VALIDATORS).values(), + config().section(SECTION_VALIDATOR_LIST_KEYS).values())) { JLOG(m_journal.fatal()) - << "Invalid entry in [" << SECTION_VALIDATOR_LIST_SITES << "]"; + << "Invalid entry in validator configuration."; return false; } + } - // Tell the AmendmentTable who the trusted validators are. - m_amendmentTable->trustChanged(validators_->getQuorumKeys().second); + if (!validatorSites_->load( + config().section(SECTION_VALIDATOR_LIST_SITES).values())) + { + JLOG(m_journal.fatal()) + << "Invalid entry in [" << SECTION_VALIDATOR_LIST_SITES << "]"; + return false; } + + // Tell the AmendmentTable who the trusted validators are. + m_amendmentTable->trustChanged(validators_->getQuorumKeys().second); + //---------------------------------------------------------------------- // // Server @@ -1406,23 +1375,19 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) // move the instantiation inside a conditional: // // if (!config_.standalone()) - if (!config_->reporting()) - { - overlay_ = make_Overlay( - *this, - setup_Overlay(*config_), - *serverHandler_, - *m_resourceManager, - *m_resolver, - get_io_service(), - *config_, - m_collectorManager->collector()); - add(*overlay_); // add to PropertyStream - } + overlay_ = make_Overlay( + *this, + setup_Overlay(*config_), + *serverHandler_, + *m_resourceManager, + *m_resolver, + get_io_service(), + *config_, + m_collectorManager->collector()); + add(*overlay_); // add to PropertyStream // start first consensus round - if (!config_->reporting() && - !m_networkOPs->beginConsensus( + if (!m_networkOPs->beginConsensus( m_ledgerMaster->getClosedLedger()->info().hash)) { JLOG(m_journal.fatal()) << "Unable to start consensus"; @@ -1536,9 +1501,6 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) validatorSites_->start(); - if (reportingETL_) - reportingETL_->start(); - return true; } @@ -1654,10 +1616,6 @@ ApplicationImp::run() m_inboundTransactions->stop(); m_inboundLedgers->stop(); ledgerCleaner_->stop(); - if (reportingETL_) - reportingETL_->stop(); - if (auto pg = dynamic_cast(&*mRelationalDatabase)) - pg->stop(); m_nodeStore->stop(); perfLog_->stop(); diff --git a/src/xrpld/app/main/Application.h b/src/xrpld/app/main/Application.h index d4871317e73..8f2dd606ded 100644 --- a/src/xrpld/app/main/Application.h +++ b/src/xrpld/app/main/Application.h @@ -100,8 +100,6 @@ class RelationalDatabase; class DatabaseCon; class SHAMapStore; -class ReportingETL; - using NodeCache = TaggedCache; template @@ -253,9 +251,6 @@ class Application : public beast::PropertyStream::Source virtual std::chrono::milliseconds getIOLatency() = 0; - virtual ReportingETL& - getReportingETL() = 0; - virtual bool serverOkay(std::string& reason) = 0; diff --git a/src/xrpld/app/main/GRPCServer.cpp b/src/xrpld/app/main/GRPCServer.cpp index 5d5a79db393..89c3d813caa 100644 --- a/src/xrpld/app/main/GRPCServer.cpp +++ b/src/xrpld/app/main/GRPCServer.cpp @@ -18,7 +18,6 @@ //============================================================================== #include -#include #include #include @@ -187,11 +186,6 @@ GRPCServerImpl::CallData::process( InfoSub::pointer(), apiVersion}, request_}; - if (shouldForwardToP2p(context, requiredCondition_)) - { - forwardToP2p(context); - return; - } // Make sure we can currently handle the rpc error_code_i conditionMetRes = @@ -207,18 +201,9 @@ GRPCServerImpl::CallData::process( } else { - try - { - std::pair result = - handler_(context); - setIsUnlimited(result.first, isUnlimited); - responder_.Finish(result.first, result.second, this); - } - catch (ReportingShouldProxy&) - { - forwardToP2p(context); - return; - } + std::pair result = handler_(context); + setIsUnlimited(result.first, isUnlimited); + responder_.Finish(result.first, result.second, this); } } } @@ -229,46 +214,6 @@ GRPCServerImpl::CallData::process( } } -template -void -GRPCServerImpl::CallData::forwardToP2p( - RPC::GRPCContext& context) -{ - if (auto descriptor = - Request::GetDescriptor()->FindFieldByName("client_ip")) - { - Request::GetReflection()->SetString(&request_, descriptor, ctx_.peer()); - JLOG(app_.journal("gRPCServer").debug()) - << "Set client_ip to " << ctx_.peer(); - } - else - { - assert(false); - Throw( - "Attempting to forward but no client_ip field in " - "protobuf message"); - } - auto stub = getP2pForwardingStub(context); - if (stub) - { - grpc::ClientContext clientContext; - Response response; - auto status = forward_(stub.get(), &clientContext, request_, &response); - responder_.Finish(response, status, this); - JLOG(app_.journal("gRPCServer").debug()) << "Forwarded request to tx"; - } - else - { - JLOG(app_.journal("gRPCServer").error()) - << "Failed to forward request to tx"; - grpc::Status status{ - grpc::StatusCode::INTERNAL, - "Attempted to act as proxy but failed " - "to create forwarding stub"}; - responder_.FinishWithError(status, this); - } -} - template bool GRPCServerImpl::CallData::isFinished() @@ -289,29 +234,10 @@ GRPCServerImpl::CallData::getRole(bool isUnlimited) { if (isUnlimited) return Role::IDENTIFIED; - else if (wasForwarded()) - return Role::PROXY; else return Role::USER; } -template -bool -GRPCServerImpl::CallData::wasForwarded() -{ - if (auto descriptor = - Request::GetDescriptor()->FindFieldByName("client_ip")) - { - std::string clientIp = - Request::GetReflection()->GetString(request_, descriptor); - if (!clientIp.empty()) - { - return true; - } - } - return false; -} - template std::optional GRPCServerImpl::CallData::getUser() @@ -338,35 +264,6 @@ GRPCServerImpl::CallData::getClientIpAddress() return {}; } -template -std::optional -GRPCServerImpl::CallData::getProxiedClientIpAddress() -{ - auto endpoint = getProxiedClientEndpoint(); - if (endpoint) - return endpoint->address(); - return {}; -} - -template -std::optional -GRPCServerImpl::CallData::getProxiedClientEndpoint() -{ - auto descriptor = Request::GetDescriptor()->FindFieldByName("client_ip"); - if (descriptor) - { - std::string clientIp = - Request::GetReflection()->GetString(request_, descriptor); - if (!clientIp.empty()) - { - JLOG(app_.journal("gRPCServer").debug()) - << "Got client_ip from request : " << clientIp; - return getEndpoint(clientIp); - } - } - return {}; -} - template std::optional GRPCServerImpl::CallData::getClientEndpoint() @@ -381,8 +278,7 @@ GRPCServerImpl::CallData::clientIsUnlimited() if (!getUser()) return false; auto clientIp = getClientIpAddress(); - auto proxiedIp = getProxiedClientIpAddress(); - if (clientIp && !proxiedIp) + if (clientIp) { for (auto& ip : secureGatewayIPs_) { @@ -414,11 +310,7 @@ Resource::Consumer GRPCServerImpl::CallData::getUsage() { auto endpoint = getClientEndpoint(); - auto proxiedEndpoint = getProxiedClientEndpoint(); - if (proxiedEndpoint) - return app_.getResourceManager().newInboundEndpoint( - beast::IP::from_asio(proxiedEndpoint.value())); - else if (endpoint) + if (endpoint) return app_.getResourceManager().newInboundEndpoint( beast::IP::from_asio(endpoint.value())); Throw("Failed to get client endpoint"); diff --git a/src/xrpld/app/main/Main.cpp b/src/xrpld/app/main/Main.cpp index 799911f63dd..154ac48763b 100644 --- a/src/xrpld/app/main/Main.cpp +++ b/src/xrpld/app/main/Main.cpp @@ -376,7 +376,6 @@ run(int argc, char** argv) "quorum", po::value(), "Override the minimum validation quorum.")( - "reportingReadOnly", "Run in read-only reporting mode")( "silent", "No output to the console after startup.")( "standalone,a", "Run with no peers.")("verbose,v", "Verbose logging.") @@ -401,9 +400,6 @@ run(int argc, char** argv) po::value(), "Trap a specific transaction during replay.")( "start", "Start from a fresh Ledger.")( - "startReporting", - po::value(), - "Start reporting from a fresh Ledger.")( "vacuum", "VACUUM the transaction db.")( "valid", "Consider the initial ledger a valid network ledger."); @@ -659,17 +655,6 @@ run(int argc, char** argv) config->START_UP = Config::FRESH; } - if (vm.count("startReporting")) - { - config->START_UP = Config::FRESH; - config->START_LEDGER = vm["startReporting"].as(); - } - - if (vm.count("reportingReadOnly")) - { - config->setReportingReadOnly(true); - } - if (vm.count("import")) config->doImport = true; diff --git a/src/xrpld/app/misc/NetworkOPs.cpp b/src/xrpld/app/misc/NetworkOPs.cpp index a7ee935f102..208aab05aa1 100644 --- a/src/xrpld/app/misc/NetworkOPs.cpp +++ b/src/xrpld/app/misc/NetworkOPs.cpp @@ -38,9 +38,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -455,15 +453,6 @@ class NetworkOPsImp final : public NetworkOPs void pubValidation(std::shared_ptr const& val) override; - void - forwardValidation(Json::Value const& jvObj) override; - void - forwardManifest(Json::Value const& jvObj) override; - void - forwardProposedTransaction(Json::Value const& jvObj) override; - void - forwardProposedAccountTransaction(Json::Value const& jvObj) override; - //-------------------------------------------------------------------------- // // InfoSub::Source. @@ -2489,8 +2478,7 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) if (fp != 0) info[jss::fetch_pack] = Json::UInt(fp); - if (!app_.config().reporting()) - info[jss::peers] = Json::UInt(app_.overlay().size()); + info[jss::peers] = Json::UInt(app_.overlay().size()); Json::Value lastClose = Json::objectValue; lastClose[jss::proposers] = Json::UInt(mConsensus.prevProposers()); @@ -2513,85 +2501,80 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) if (admin) info[jss::load] = m_job_queue.getJson(); - if (!app_.config().reporting()) + if (auto const netid = app_.overlay().networkID()) + info[jss::network_id] = static_cast(*netid); + + auto const escalationMetrics = + app_.getTxQ().getMetrics(*app_.openLedger().current()); + + auto const loadFactorServer = app_.getFeeTrack().getLoadFactor(); + auto const loadBaseServer = app_.getFeeTrack().getLoadBase(); + /* Scale the escalated fee level to unitless "load factor". + In practice, this just strips the units, but it will continue + to work correctly if either base value ever changes. */ + auto const loadFactorFeeEscalation = + mulDiv( + escalationMetrics.openLedgerFeeLevel, + loadBaseServer, + escalationMetrics.referenceFeeLevel) + .value_or(ripple::muldiv_max); + + auto const loadFactor = std::max( + safe_cast(loadFactorServer), loadFactorFeeEscalation); + + if (!human) + { + info[jss::load_base] = loadBaseServer; + info[jss::load_factor] = trunc32(loadFactor); + info[jss::load_factor_server] = loadFactorServer; + + /* Json::Value doesn't support uint64, so clamp to max + uint32 value. This is mostly theoretical, since there + probably isn't enough extant XRP to drive the factor + that high. + */ + info[jss::load_factor_fee_escalation] = + escalationMetrics.openLedgerFeeLevel.jsonClipped(); + info[jss::load_factor_fee_queue] = + escalationMetrics.minProcessingFeeLevel.jsonClipped(); + info[jss::load_factor_fee_reference] = + escalationMetrics.referenceFeeLevel.jsonClipped(); + } + else { - if (auto const netid = app_.overlay().networkID()) - info[jss::network_id] = static_cast(*netid); - - auto const escalationMetrics = - app_.getTxQ().getMetrics(*app_.openLedger().current()); - - auto const loadFactorServer = app_.getFeeTrack().getLoadFactor(); - auto const loadBaseServer = app_.getFeeTrack().getLoadBase(); - /* Scale the escalated fee level to unitless "load factor". - In practice, this just strips the units, but it will continue - to work correctly if either base value ever changes. */ - auto const loadFactorFeeEscalation = - mulDiv( - escalationMetrics.openLedgerFeeLevel, - loadBaseServer, - escalationMetrics.referenceFeeLevel) - .value_or(ripple::muldiv_max); - - auto const loadFactor = std::max( - safe_cast(loadFactorServer), - loadFactorFeeEscalation); + info[jss::load_factor] = + static_cast(loadFactor) / loadBaseServer; - if (!human) + if (loadFactorServer != loadFactor) + info[jss::load_factor_server] = + static_cast(loadFactorServer) / loadBaseServer; + + if (admin) { - info[jss::load_base] = loadBaseServer; - info[jss::load_factor] = trunc32(loadFactor); - info[jss::load_factor_server] = loadFactorServer; - - /* Json::Value doesn't support uint64, so clamp to max - uint32 value. This is mostly theoretical, since there - probably isn't enough extant XRP to drive the factor - that high. - */ + std::uint32_t fee = app_.getFeeTrack().getLocalFee(); + if (fee != loadBaseServer) + info[jss::load_factor_local] = + static_cast(fee) / loadBaseServer; + fee = app_.getFeeTrack().getRemoteFee(); + if (fee != loadBaseServer) + info[jss::load_factor_net] = + static_cast(fee) / loadBaseServer; + fee = app_.getFeeTrack().getClusterFee(); + if (fee != loadBaseServer) + info[jss::load_factor_cluster] = + static_cast(fee) / loadBaseServer; + } + if (escalationMetrics.openLedgerFeeLevel != + escalationMetrics.referenceFeeLevel && + (admin || loadFactorFeeEscalation != loadFactor)) info[jss::load_factor_fee_escalation] = - escalationMetrics.openLedgerFeeLevel.jsonClipped(); + escalationMetrics.openLedgerFeeLevel.decimalFromReference( + escalationMetrics.referenceFeeLevel); + if (escalationMetrics.minProcessingFeeLevel != + escalationMetrics.referenceFeeLevel) info[jss::load_factor_fee_queue] = - escalationMetrics.minProcessingFeeLevel.jsonClipped(); - info[jss::load_factor_fee_reference] = - escalationMetrics.referenceFeeLevel.jsonClipped(); - } - else - { - info[jss::load_factor] = - static_cast(loadFactor) / loadBaseServer; - - if (loadFactorServer != loadFactor) - info[jss::load_factor_server] = - static_cast(loadFactorServer) / loadBaseServer; - - if (admin) - { - std::uint32_t fee = app_.getFeeTrack().getLocalFee(); - if (fee != loadBaseServer) - info[jss::load_factor_local] = - static_cast(fee) / loadBaseServer; - fee = app_.getFeeTrack().getRemoteFee(); - if (fee != loadBaseServer) - info[jss::load_factor_net] = - static_cast(fee) / loadBaseServer; - fee = app_.getFeeTrack().getClusterFee(); - if (fee != loadBaseServer) - info[jss::load_factor_cluster] = - static_cast(fee) / loadBaseServer; - } - if (escalationMetrics.openLedgerFeeLevel != - escalationMetrics.referenceFeeLevel && - (admin || loadFactorFeeEscalation != loadFactor)) - info[jss::load_factor_fee_escalation] = - escalationMetrics.openLedgerFeeLevel.decimalFromReference( - escalationMetrics.referenceFeeLevel); - if (escalationMetrics.minProcessingFeeLevel != - escalationMetrics.referenceFeeLevel) - info[jss::load_factor_fee_queue] = - escalationMetrics.minProcessingFeeLevel - .decimalFromReference( - escalationMetrics.referenceFeeLevel); - } + escalationMetrics.minProcessingFeeLevel.decimalFromReference( + escalationMetrics.referenceFeeLevel); } bool valid = false; @@ -2599,7 +2582,7 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) if (lpClosed) valid = true; - else if (!app_.config().reporting()) + else lpClosed = m_ledgerMaster.getClosedLedger(); if (lpClosed) @@ -2630,11 +2613,6 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) l[jss::close_time_offset] = static_cast(closeOffset.count()); -#if RIPPLED_REPORTING - std::int64_t const dbAge = - std::max(m_ledgerMaster.getValidatedLedgerAge().count(), 0L); - l[jss::age] = Json::UInt(dbAge); -#else constexpr std::chrono::seconds highAgeThreshold{1000000}; if (m_ledgerMaster.haveValidated()) { @@ -2654,7 +2632,6 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) Json::UInt(age < highAgeThreshold ? age.count() : 0); } } -#endif } if (valid) @@ -2671,19 +2648,12 @@ NetworkOPsImp::getServerInfo(bool human, bool admin, bool counters) accounting_.json(info); info[jss::uptime] = UptimeClock::now().time_since_epoch().count(); - if (!app_.config().reporting()) - { - info[jss::jq_trans_overflow] = - std::to_string(app_.overlay().getJqTransOverflow()); - info[jss::peer_disconnects] = - std::to_string(app_.overlay().getPeerDisconnect()); - info[jss::peer_disconnects_resources] = - std::to_string(app_.overlay().getPeerDisconnectCharges()); - } - else - { - info["reporting"] = app_.getReportingETL().getInfo(); - } + info[jss::jq_trans_overflow] = + std::to_string(app_.overlay().getJqTransOverflow()); + info[jss::peer_disconnects] = + std::to_string(app_.overlay().getPeerDisconnect()); + info[jss::peer_disconnects_resources] = + std::to_string(app_.overlay().getPeerDisconnectCharges()); // This array must be sorted in increasing order. static constexpr std::array protocols{ @@ -2779,77 +2749,6 @@ NetworkOPsImp::pubProposedTransaction( pubProposedAccountTransaction(ledger, transaction, result); } -void -NetworkOPsImp::forwardProposedTransaction(Json::Value const& jvObj) -{ - // reporting does not forward validated transactions - // validated transactions will be published to the proper streams when the - // etl process writes a validated ledger - if (jvObj[jss::validated].asBool()) - return; - { - std::lock_guard sl(mSubLock); - - auto it = mStreamMaps[sRTTransactions].begin(); - while (it != mStreamMaps[sRTTransactions].end()) - { - InfoSub::pointer p = it->second.lock(); - - if (p) - { - p->send(jvObj, true); - ++it; - } - else - { - it = mStreamMaps[sRTTransactions].erase(it); - } - } - } - - forwardProposedAccountTransaction(jvObj); -} - -void -NetworkOPsImp::forwardValidation(Json::Value const& jvObj) -{ - std::lock_guard sl(mSubLock); - - for (auto i = mStreamMaps[sValidations].begin(); - i != mStreamMaps[sValidations].end();) - { - if (auto p = i->second.lock()) - { - p->send(jvObj, true); - ++i; - } - else - { - i = mStreamMaps[sValidations].erase(i); - } - } -} - -void -NetworkOPsImp::forwardManifest(Json::Value const& jvObj) -{ - std::lock_guard sl(mSubLock); - - for (auto i = mStreamMaps[sManifests].begin(); - i != mStreamMaps[sManifests].end();) - { - if (auto p = i->second.lock()) - { - p->send(jvObj, true); - ++i; - } - else - { - i = mStreamMaps[sManifests].erase(i); - } - } -} - static void getAccounts(Json::Value const& jvObj, std::vector& accounts) { @@ -2868,74 +2767,6 @@ getAccounts(Json::Value const& jvObj, std::vector& accounts) } } -void -NetworkOPsImp::forwardProposedAccountTransaction(Json::Value const& jvObj) -{ - hash_set notify; - int iProposed = 0; - // check if there are any subscribers before attempting to parse the JSON - { - std::lock_guard sl(mSubLock); - - if (mSubRTAccount.empty()) - return; - } - - // parse the JSON outside of the lock - std::vector accounts; - if (jvObj.isMember(jss::transaction)) - { - try - { - getAccounts(jvObj[jss::transaction], accounts); - } - catch (...) - { - JLOG(m_journal.debug()) - << __func__ << " : " - << "error parsing json for accounts affected"; - return; - } - } - { - std::lock_guard sl(mSubLock); - - if (!mSubRTAccount.empty()) - { - for (auto const& affectedAccount : accounts) - { - auto simiIt = mSubRTAccount.find(affectedAccount); - if (simiIt != mSubRTAccount.end()) - { - auto it = simiIt->second.begin(); - - while (it != simiIt->second.end()) - { - InfoSub::pointer p = it->second.lock(); - - if (p) - { - notify.insert(p); - ++it; - ++iProposed; - } - else - it = simiIt->second.erase(it); - } - } - } - } - } - JLOG(m_journal.trace()) << "forwardProposedAccountTransaction:" - << " iProposed=" << iProposed; - - if (!notify.empty()) - { - for (InfoSub::ref isrListener : notify) - isrListener->send(jvObj, true); - } -} - void NetworkOPsImp::pubLedger(std::shared_ptr const& lpAccepted) { @@ -3052,8 +2883,6 @@ NetworkOPsImp::pubLedger(std::shared_ptr const& lpAccepted) void NetworkOPsImp::reportFeeChange() { - if (app_.config().reporting()) - return; ServerFeeSummary f{ app_.openLedger().current()->fees().base, app_.getTxQ().getMetrics(*app_.openLedger().current()), @@ -3533,30 +3362,8 @@ NetworkOPsImp::unsubAccountInternal( void NetworkOPsImp::addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo) { - enum DatabaseType { Postgres, Sqlite, None }; + enum DatabaseType { Sqlite, None }; static const auto databaseType = [&]() -> DatabaseType { -#ifdef RIPPLED_REPORTING - if (app_.config().reporting()) - { - // Use a dynamic_cast to return DatabaseType::None - // on failure. - if (dynamic_cast(&app_.getRelationalDatabase())) - { - return DatabaseType::Postgres; - } - return DatabaseType::None; - } - else - { - // Use a dynamic_cast to return DatabaseType::None - // on failure. - if (dynamic_cast(&app_.getRelationalDatabase())) - { - return DatabaseType::Sqlite; - } - return DatabaseType::None; - } -#else // Use a dynamic_cast to return DatabaseType::None // on failure. if (dynamic_cast(&app_.getRelationalDatabase())) @@ -3564,7 +3371,6 @@ NetworkOPsImp::addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo) return DatabaseType::Sqlite; } return DatabaseType::None; -#endif }(); if (databaseType == DatabaseType::None) @@ -3667,40 +3473,6 @@ NetworkOPsImp::addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo) std::optional>> { switch (dbType) { - case Postgres: { - auto db = static_cast( - &app_.getRelationalDatabase()); - RelationalDatabase::AccountTxArgs args; - args.account = accountId; - LedgerRange range{minLedger, maxLedger}; - args.ledger = range; - args.marker = marker; - auto [txResult, status] = db->getAccountTx(args); - if (status != rpcSUCCESS) - { - JLOG(m_journal.debug()) - << "AccountHistory job for account " - << toBase58(accountId) - << " getAccountTx failed"; - return {}; - } - - if (auto txns = - std::get_if( - &txResult.transactions); - txns) - { - return std::make_pair(*txns, txResult.marker); - } - else - { - JLOG(m_journal.debug()) - << "AccountHistory job for account " - << toBase58(accountId) - << " getAccountTx wrong data"; - return {}; - } - } case Sqlite: { auto db = static_cast( &app_.getRelationalDatabase()); diff --git a/src/xrpld/app/misc/NetworkOPs.h b/src/xrpld/app/misc/NetworkOPs.h index d5f43a42972..166b9e9e11f 100644 --- a/src/xrpld/app/misc/NetworkOPs.h +++ b/src/xrpld/app/misc/NetworkOPs.h @@ -261,15 +261,6 @@ class NetworkOPs : public InfoSub::Source virtual void pubValidation(std::shared_ptr const& val) = 0; - virtual void - forwardValidation(Json::Value const& jvObj) = 0; - virtual void - forwardManifest(Json::Value const& jvObj) = 0; - virtual void - forwardProposedTransaction(Json::Value const& jvObj) = 0; - virtual void - forwardProposedAccountTransaction(Json::Value const& jvObj) = 0; - virtual void stateAccounting(Json::Value& obj) = 0; }; diff --git a/src/xrpld/app/misc/SHAMapStoreImp.cpp b/src/xrpld/app/misc/SHAMapStoreImp.cpp index 9344463295b..1ce862b095f 100644 --- a/src/xrpld/app/misc/SHAMapStoreImp.cpp +++ b/src/xrpld/app/misc/SHAMapStoreImp.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -120,13 +119,6 @@ SHAMapStoreImp::SHAMapStoreImp( if (deleteInterval_) { - if (app_.config().reporting()) - { - Throw( - "Reporting does not support online_delete. Remove " - "online_delete info from config"); - } - // Configuration that affects the behavior of online delete get_if_exists(section, "delete_batch", deleteBatch_); std::uint32_t temp; @@ -188,12 +180,6 @@ SHAMapStoreImp::makeNodeStore(int readThreads) if (deleteInterval_) { - if (app_.config().reporting()) - { - Throw( - "Reporting does not support online_delete. Remove " - "online_delete info from config"); - } SavedState state = state_db_.getState(); auto writableBackend = makeBackendRotating(state.writableDb); auto archiveBackend = makeBackendRotating(state.archiveDb); @@ -279,13 +265,6 @@ SHAMapStoreImp::copyNode(std::uint64_t& nodeCount, SHAMapTreeNode const& node) void SHAMapStoreImp::run() { - if (app_.config().reporting()) - { - assert(false); - Throw( - "Reporting does not support online_delete. Remove " - "online_delete info from config"); - } beast::setCurrentThreadName("SHAMapStore"); LedgerIndex lastRotated = state_db_.getState().lastRotated; netOPs_ = &app_.getOPs(); @@ -597,13 +576,6 @@ SHAMapStoreImp::freshenCaches() void SHAMapStoreImp::clearPrior(LedgerIndex lastRotated) { - if (app_.config().reporting()) - { - assert(false); - Throw( - "Reporting does not support online_delete. Remove " - "online_delete info from config"); - } // Do not allow ledgers to be acquired from the network // that are about to be deleted. minimumOnline_ = lastRotated + 1; diff --git a/src/xrpld/app/misc/detail/Transaction.cpp b/src/xrpld/app/misc/detail/Transaction.cpp index e0c3f260fe5..c8f9df232e0 100644 --- a/src/xrpld/app/misc/detail/Transaction.cpp +++ b/src/xrpld/app/misc/detail/Transaction.cpp @@ -21,11 +21,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -130,20 +128,6 @@ Transaction::load( return load(id, app, op{range}, ec); } -Transaction::Locator -Transaction::locate(uint256 const& id, Application& app) -{ - auto const db = - dynamic_cast(&app.getRelationalDatabase()); - - if (!db) - { - Throw("Failed to get relational database"); - } - - return db->locateTransaction(id); -} - std::variant< std::pair, std::shared_ptr>, TxSearched> diff --git a/src/xrpld/app/rdb/README.md b/src/xrpld/app/rdb/README.md index f4cb5f203a4..81aaa32f2cf 100644 --- a/src/xrpld/app/rdb/README.md +++ b/src/xrpld/app/rdb/README.md @@ -28,9 +28,7 @@ src/xrpld/app/rdb/ │   ├── detail │   │   ├── Node.cpp │   │   ├── Node.h -│   │   ├── PostgresDatabase.cpp │   │   └── SQLiteDatabase.cpp -│   ├── PostgresDatabase.h │   └── SQLiteDatabase.h ├── detail │   ├── PeerFinder.cpp @@ -50,7 +48,6 @@ src/xrpld/app/rdb/ | File | Contents | | ----------- | ----------- | | `Node.[h\|cpp]` | Defines/Implements methods used by `SQLiteDatabase` for interacting with SQLite node databases| -| `PostgresDatabase.[h\|cpp]` | Defines/Implements the class `PostgresDatabase`/`PostgresDatabaseImp` which inherits from `RelationalDatabase` and is used to operate on the main stores | |`SQLiteDatabase.[h\|cpp]`| Defines/Implements the class `SQLiteDatabase`/`SQLiteDatabaseImp` which inherits from `RelationalDatabase` and is used to operate on the main stores | | `PeerFinder.[h\|cpp]` | Defines/Implements methods for interacting with the PeerFinder SQLite database | |`RelationalDatabase.cpp`| Implements the static method `RelationalDatabase::init` which is used to initialize an instance of `RelationalDatabase` | diff --git a/src/xrpld/app/rdb/RelationalDatabase.h b/src/xrpld/app/rdb/RelationalDatabase.h index b30c94153f7..00e236f20db 100644 --- a/src/xrpld/app/rdb/RelationalDatabase.h +++ b/src/xrpld/app/rdb/RelationalDatabase.h @@ -111,29 +111,6 @@ class RelationalDatabase std::optional marker; }; - /// Struct used to keep track of what to write to transactions and - /// account_transactions tables in Postgres - struct AccountTransactionsData - { - boost::container::flat_set accounts; - uint32_t ledgerSequence; - uint32_t transactionIndex; - uint256 txHash; - uint256 nodestoreHash; - - AccountTransactionsData( - TxMeta const& meta, - uint256 const& nodestoreHash, - beast::Journal j) - : accounts(meta.getAffectedAccounts()) - , ledgerSequence(meta.getLgrSeq()) - , transactionIndex(meta.getIndex()) - , txHash(meta.getTxID()) - , nodestoreHash(nodestoreHash) - { - } - }; - /** * @brief init Creates and returns an appropriate RelationalDatabase * instance based on configuration. diff --git a/src/xrpld/app/rdb/backend/PostgresDatabase.h b/src/xrpld/app/rdb/backend/PostgresDatabase.h deleted file mode 100644 index c2841cefd8c..00000000000 --- a/src/xrpld/app/rdb/backend/PostgresDatabase.h +++ /dev/null @@ -1,113 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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_APP_RDB_BACKEND_POSTGRESDATABASE_H_INCLUDED -#define RIPPLE_APP_RDB_BACKEND_POSTGRESDATABASE_H_INCLUDED - -#include - -namespace ripple { - -class PostgresDatabase : public RelationalDatabase -{ -public: - virtual void - stop() = 0; - - /** - * @brief sweep Sweeps the database. - */ - virtual void - sweep() = 0; - - /** - * @brief getCompleteLedgers Returns a string which contains a list of - * completed ledgers. - * @return String with completed ledger sequences - */ - virtual std::string - getCompleteLedgers() = 0; - - /** - * @brief getValidatedLedgerAge Returns the age of the last validated - * ledger. - * @return Age of the last validated ledger in seconds - */ - virtual std::chrono::seconds - getValidatedLedgerAge() = 0; - - /** - * @brief writeLedgerAndTransactions Writes new ledger and transaction data - * into the database. - * @param info Ledger info to write. - * @param accountTxData Transaction data to write - * @return True on success, false on failure. - */ - virtual bool - writeLedgerAndTransactions( - LedgerInfo const& info, - std::vector const& accountTxData) = 0; - - /** - * @brief getTxHashes Returns a vector of the hashes of transactions - * belonging to the ledger with the provided sequence. - * @param seq Ledger sequence - * @return Vector of transaction hashes - */ - virtual std::vector - getTxHashes(LedgerIndex seq) = 0; - - /** - * @brief getAccountTx Get the last account transactions specified by the - * AccountTxArgs struct. - * @param args Arguments which specify the account and which transactions to - * return. - * @return Vector of account transactions and the RPC status response. - */ - virtual std::pair - getAccountTx(AccountTxArgs const& args) = 0; - - /** - * @brief locateTransaction Returns information used to locate - * a transaction. - * @param id Hash of the transaction. - * @return Information used to locate a transaction. Contains a nodestore - * hash and a ledger sequence pair if the transaction was found. - * Otherwise, contains the range of ledgers present in the database - * at the time of search. - */ - virtual Transaction::Locator - locateTransaction(uint256 const& id) = 0; - - /** - * @brief isCaughtUp returns whether the database is caught up with the - * network - * @param[out] reason if the database is not caught up, reason contains a - * helpful message describing why - * @return false if the most recently written ledger has a close time - * over 3 minutes ago, or if there are no ledgers in the - * database. true otherwise - */ - virtual bool - isCaughtUp(std::string& reason) = 0; -}; - -} // namespace ripple - -#endif diff --git a/src/xrpld/app/rdb/backend/detail/PostgresDatabase.cpp b/src/xrpld/app/rdb/backend/detail/PostgresDatabase.cpp deleted file mode 100644 index ac1a9813c2b..00000000000 --- a/src/xrpld/app/rdb/backend/detail/PostgresDatabase.cpp +++ /dev/null @@ -1,1072 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { - -class PgPool; - -using AccountTxResult = RelationalDatabase::AccountTxResult; -using TxnsData = RelationalDatabase::AccountTxs; -using TxnsDataBinary = RelationalDatabase::MetaTxsList; - -class PostgresDatabaseImp final : public PostgresDatabase -{ -public: - PostgresDatabaseImp( - Application& app, - Config const& config, - JobQueue& jobQueue) - : app_(app) - , j_(app_.journal("PgPool")) - , pgPool_( -#ifdef RIPPLED_REPORTING - make_PgPool(config.section("ledger_tx_tables"), j_) -#endif - ) - { - assert(config.reporting()); -#ifdef RIPPLED_REPORTING - if (config.reporting() && !config.reportingReadOnly()) // use pg - { - initSchema(pgPool_); - } -#endif - } - - void - stop() override - { -#ifdef RIPPLED_REPORTING - pgPool_->stop(); -#endif - } - - void - sweep() override; - - std::optional - getMinLedgerSeq() override; - - std::optional - getMaxLedgerSeq() override; - - std::string - getCompleteLedgers() override; - - std::chrono::seconds - getValidatedLedgerAge() override; - - bool - writeLedgerAndTransactions( - LedgerInfo const& info, - std::vector const& accountTxData) override; - - std::optional - getLedgerInfoByIndex(LedgerIndex ledgerSeq) override; - - std::optional - getNewestLedgerInfo() override; - - std::optional - getLedgerInfoByHash(uint256 const& ledgerHash) override; - - uint256 - getHashByIndex(LedgerIndex ledgerIndex) override; - - std::optional - getHashesByIndex(LedgerIndex ledgerIndex) override; - - std::map - getHashesByIndex(LedgerIndex minSeq, LedgerIndex maxSeq) override; - - std::vector - getTxHashes(LedgerIndex seq) override; - - std::vector> - getTxHistory(LedgerIndex startIndex) override; - - std::pair - getAccountTx(AccountTxArgs const& args) override; - - Transaction::Locator - locateTransaction(uint256 const& id) override; - - bool - ledgerDbHasSpace(Config const& config) override; - - bool - transactionDbHasSpace(Config const& config) override; - - bool - isCaughtUp(std::string& reason) override; - -private: - Application& app_; - beast::Journal j_; - std::shared_ptr pgPool_; - - bool - dbHasSpace(Config const& config); -}; - -/** - * @brief loadLedgerInfos Loads the ledger info for the specified - * ledger/s from the database - * @param pgPool Link to postgres database - * @param whichLedger Specifies the ledger to load via ledger sequence, - * ledger hash, a range of ledgers, or std::monostate - * (which loads the most recent) - * @param app Application - * @return Vector of LedgerInfos - */ -static std::vector -loadLedgerInfos( - std::shared_ptr const& pgPool, - std::variant< - std::monostate, - uint256, - uint32_t, - std::pair> const& whichLedger, - Application& app) -{ - std::vector infos; -#ifdef RIPPLED_REPORTING - auto log = app.journal("Ledger"); - assert(app.config().reporting()); - std::stringstream sql; - sql << "SELECT ledger_hash, prev_hash, account_set_hash, trans_set_hash, " - "total_coins, closing_time, prev_closing_time, close_time_res, " - "close_flags, ledger_seq FROM ledgers "; - - if (auto ledgerSeq = std::get_if(&whichLedger)) - { - sql << "WHERE ledger_seq = " + std::to_string(*ledgerSeq); - } - else if (auto ledgerHash = std::get_if(&whichLedger)) - { - sql << ("WHERE ledger_hash = \'\\x" + strHex(*ledgerHash) + "\'"); - } - else if ( - auto minAndMax = - std::get_if>(&whichLedger)) - { - sql - << ("WHERE ledger_seq >= " + std::to_string(minAndMax->first) + - " AND ledger_seq <= " + std::to_string(minAndMax->second)); - } - else - { - sql << ("ORDER BY ledger_seq desc LIMIT 1"); - } - sql << ";"; - - JLOG(log.trace()) << __func__ << " : sql = " << sql.str(); - - auto res = PgQuery(pgPool)(sql.str().data()); - if (!res) - { - JLOG(log.error()) << __func__ << " : Postgres response is null - sql = " - << sql.str(); - assert(false); - return {}; - } - else if (res.status() != PGRES_TUPLES_OK) - { - JLOG(log.error()) << __func__ - << " : Postgres response should have been " - "PGRES_TUPLES_OK but instead was " - << res.status() << " - msg = " << res.msg() - << " - sql = " << sql.str(); - assert(false); - return {}; - } - - JLOG(log.trace()) << __func__ << " Postgres result msg : " << res.msg(); - - if (res.isNull() || res.ntuples() == 0) - { - JLOG(log.debug()) << __func__ - << " : Ledger not found. sql = " << sql.str(); - return {}; - } - else if (res.ntuples() > 0) - { - if (res.nfields() != 10) - { - JLOG(log.error()) << __func__ - << " : Wrong number of fields in Postgres " - "response. Expected 10, but got " - << res.nfields() << " . sql = " << sql.str(); - assert(false); - return {}; - } - } - - for (size_t i = 0; i < res.ntuples(); ++i) - { - char const* hash = res.c_str(i, 0); - char const* prevHash = res.c_str(i, 1); - char const* accountHash = res.c_str(i, 2); - char const* txHash = res.c_str(i, 3); - std::int64_t totalCoins = res.asBigInt(i, 4); - std::int64_t closeTime = res.asBigInt(i, 5); - std::int64_t parentCloseTime = res.asBigInt(i, 6); - std::int64_t closeTimeRes = res.asBigInt(i, 7); - std::int64_t closeFlags = res.asBigInt(i, 8); - std::int64_t ledgerSeq = res.asBigInt(i, 9); - - JLOG(log.trace()) << __func__ << " - Postgres response = " << hash - << " , " << prevHash << " , " << accountHash << " , " - << txHash << " , " << totalCoins << ", " << closeTime - << ", " << parentCloseTime << ", " << closeTimeRes - << ", " << closeFlags << ", " << ledgerSeq - << " - sql = " << sql.str(); - JLOG(log.debug()) << __func__ - << " - Successfully fetched ledger with sequence = " - << ledgerSeq << " from Postgres"; - - using time_point = NetClock::time_point; - using duration = NetClock::duration; - - LedgerInfo info; - if (!info.parentHash.parseHex(prevHash + 2)) - assert(false); - if (!info.txHash.parseHex(txHash + 2)) - assert(false); - if (!info.accountHash.parseHex(accountHash + 2)) - assert(false); - info.drops = totalCoins; - info.closeTime = time_point{duration{closeTime}}; - info.parentCloseTime = time_point{duration{parentCloseTime}}; - info.closeFlags = closeFlags; - info.closeTimeResolution = duration{closeTimeRes}; - info.seq = ledgerSeq; - if (!info.hash.parseHex(hash + 2)) - assert(false); - info.validated = true; - infos.push_back(info); - } - -#endif - return infos; -} - -/** - * @brief loadLedgerHelper Load a ledger info from Postgres - * @param pgPool Link to postgres database - * @param whichLedger Specifies sequence or hash of ledger. Passing - * std::monostate loads the most recent ledger - * @param app The Application - * @return Ledger info - */ -static std::optional -loadLedgerHelper( - std::shared_ptr const& pgPool, - std::variant const& whichLedger, - Application& app) -{ - std::vector infos; - std::visit( - [&infos, &app, &pgPool](auto&& arg) { - infos = loadLedgerInfos(pgPool, arg, app); - }, - whichLedger); - assert(infos.size() <= 1); - if (!infos.size()) - return {}; - return infos[0]; -} - -#ifdef RIPPLED_REPORTING -static bool -writeToLedgersDB(LedgerInfo const& info, PgQuery& pgQuery, beast::Journal& j) -{ - JLOG(j.debug()) << __func__; - auto cmd = boost::format( - R"(INSERT INTO ledgers - VALUES (%u,'\x%s', '\x%s',%u,%u,%u,%u,%u,'\x%s','\x%s'))"); - - auto ledgerInsert = boost::str( - cmd % info.seq % strHex(info.hash) % strHex(info.parentHash) % - info.drops.drops() % info.closeTime.time_since_epoch().count() % - info.parentCloseTime.time_since_epoch().count() % - info.closeTimeResolution.count() % info.closeFlags % - strHex(info.accountHash) % strHex(info.txHash)); - JLOG(j.trace()) << __func__ << " : " - << " : " - << "query string = " << ledgerInsert; - - auto res = pgQuery(ledgerInsert.data()); - - return res; -} - -enum class DataFormat { binary, expanded }; -static std::variant -flatFetchTransactions( - Application& app, - std::vector& nodestoreHashes, - std::vector& ledgerSequences, - DataFormat format) -{ - std::variant ret; - if (format == DataFormat::binary) - ret = TxnsDataBinary(); - else - ret = TxnsData(); - - std::vector< - std::pair, std::shared_ptr>> - txns = flatFetchTransactions(app, nodestoreHashes); - for (size_t i = 0; i < txns.size(); ++i) - { - auto& [txn, meta] = txns[i]; - if (format == DataFormat::binary) - { - auto& transactions = std::get(ret); - Serializer txnSer = txn->getSerializer(); - Serializer metaSer = meta->getSerializer(); - // SerialIter it(item->slice()); - Blob txnBlob = txnSer.getData(); - Blob metaBlob = metaSer.getData(); - transactions.push_back( - std::make_tuple(txnBlob, metaBlob, ledgerSequences[i])); - } - else - { - auto& transactions = std::get(ret); - std::string reason; - auto txnRet = std::make_shared(txn, reason, app); - txnRet->setLedger(ledgerSequences[i]); - txnRet->setStatus(COMMITTED); - auto txMeta = std::make_shared( - txnRet->getID(), ledgerSequences[i], *meta); - transactions.push_back(std::make_pair(txnRet, txMeta)); - } - } - return ret; -} - -static std::pair -processAccountTxStoredProcedureResult( - RelationalDatabase::AccountTxArgs const& args, - Json::Value& result, - Application& app, - beast::Journal j) -{ - AccountTxResult ret; - ret.limit = args.limit; - - try - { - if (result.isMember("transactions")) - { - std::vector nodestoreHashes; - std::vector ledgerSequences; - for (auto& t : result["transactions"]) - { - if (t.isMember("ledger_seq") && t.isMember("nodestore_hash")) - { - uint32_t ledgerSequence = t["ledger_seq"].asUInt(); - std::string nodestoreHashHex = - t["nodestore_hash"].asString(); - nodestoreHashHex.erase(0, 2); - uint256 nodestoreHash; - if (!nodestoreHash.parseHex(nodestoreHashHex)) - assert(false); - - if (nodestoreHash.isNonZero()) - { - ledgerSequences.push_back(ledgerSequence); - nodestoreHashes.push_back(nodestoreHash); - } - else - { - assert(false); - return {ret, {rpcINTERNAL, "nodestoreHash is zero"}}; - } - } - else - { - assert(false); - return {ret, {rpcINTERNAL, "missing postgres fields"}}; - } - } - - assert(nodestoreHashes.size() == ledgerSequences.size()); - ret.transactions = flatFetchTransactions( - app, - nodestoreHashes, - ledgerSequences, - args.binary ? DataFormat::binary : DataFormat::expanded); - - JLOG(j.trace()) << __func__ << " : processed db results"; - - if (result.isMember("marker")) - { - auto& marker = result["marker"]; - assert(marker.isMember("ledger")); - assert(marker.isMember("seq")); - ret.marker = { - marker["ledger"].asUInt(), marker["seq"].asUInt()}; - } - assert(result.isMember("ledger_index_min")); - assert(result.isMember("ledger_index_max")); - ret.ledgerRange = { - result["ledger_index_min"].asUInt(), - result["ledger_index_max"].asUInt()}; - return {ret, rpcSUCCESS}; - } - else if (result.isMember("error")) - { - JLOG(j.debug()) - << __func__ << " : error = " << result["error"].asString(); - return { - ret, - RPC::Status{rpcINVALID_PARAMS, result["error"].asString()}}; - } - else - { - return {ret, {rpcINTERNAL, "unexpected Postgres response"}}; - } - } - catch (std::exception& e) - { - JLOG(j.debug()) << __func__ << " : " - << "Caught exception : " << e.what(); - return {ret, {rpcINTERNAL, e.what()}}; - } -} -#endif - -void -PostgresDatabaseImp::sweep() -{ -#ifdef RIPPLED_REPORTING - pgPool_->idleSweeper(); -#endif -} - -std::optional -PostgresDatabaseImp::getMinLedgerSeq() -{ -#ifdef RIPPLED_REPORTING - auto seq = PgQuery(pgPool_)("SELECT min_ledger()"); - if (!seq) - { - JLOG(j_.error()) << "Error querying minimum ledger sequence."; - } - else if (!seq.isNull()) - return seq.asInt(); -#endif - return {}; -} - -std::optional -PostgresDatabaseImp::getMaxLedgerSeq() -{ -#ifdef RIPPLED_REPORTING - auto seq = PgQuery(pgPool_)("SELECT max_ledger()"); - if (seq && !seq.isNull()) - return seq.asBigInt(); -#endif - return {}; -} - -std::string -PostgresDatabaseImp::getCompleteLedgers() -{ -#ifdef RIPPLED_REPORTING - auto range = PgQuery(pgPool_)("SELECT complete_ledgers()"); - if (range) - return range.c_str(); -#endif - return "error"; -} - -std::chrono::seconds -PostgresDatabaseImp::getValidatedLedgerAge() -{ - using namespace std::chrono_literals; -#ifdef RIPPLED_REPORTING - auto age = PgQuery(pgPool_)("SELECT age()"); - if (!age || age.isNull()) - JLOG(j_.debug()) << "No ledgers in database"; - else - return std::chrono::seconds{age.asInt()}; -#endif - return weeks{2}; -} - -bool -PostgresDatabaseImp::writeLedgerAndTransactions( - LedgerInfo const& info, - std::vector const& accountTxData) -{ -#ifdef RIPPLED_REPORTING - JLOG(j_.debug()) << __func__ << " : " - << "Beginning write to Postgres"; - - try - { - // Create a PgQuery object to run multiple commands over the same - // connection in a single transaction block. - PgQuery pg(pgPool_); - auto res = pg("BEGIN"); - if (!res || res.status() != PGRES_COMMAND_OK) - { - std::stringstream msg; - msg << "bulkWriteToTable : Postgres insert error: " << res.msg(); - Throw(msg.str()); - } - - // Writing to the ledgers db fails if the ledger already exists in the - // db. In this situation, the ETL process has detected there is another - // writer, and falls back to only publishing - if (!writeToLedgersDB(info, pg, j_)) - { - JLOG(j_.warn()) << __func__ << " : " - << "Failed to write to ledgers database."; - return false; - } - - std::stringstream transactionsCopyBuffer; - std::stringstream accountTransactionsCopyBuffer; - for (auto const& data : accountTxData) - { - std::string txHash = strHex(data.txHash); - std::string nodestoreHash = strHex(data.nodestoreHash); - auto idx = data.transactionIndex; - auto ledgerSeq = data.ledgerSequence; - - transactionsCopyBuffer << std::to_string(ledgerSeq) << '\t' - << std::to_string(idx) << '\t' << "\\\\x" - << txHash << '\t' << "\\\\x" << nodestoreHash - << '\n'; - - for (auto const& a : data.accounts) - { - std::string acct = strHex(a); - accountTransactionsCopyBuffer - << "\\\\x" << acct << '\t' << std::to_string(ledgerSeq) - << '\t' << std::to_string(idx) << '\n'; - } - } - - pg.bulkInsert("transactions", transactionsCopyBuffer.str()); - pg.bulkInsert( - "account_transactions", accountTransactionsCopyBuffer.str()); - - res = pg("COMMIT"); - if (!res || res.status() != PGRES_COMMAND_OK) - { - std::stringstream msg; - msg << "bulkWriteToTable : Postgres insert error: " << res.msg(); - assert(false); - Throw(msg.str()); - } - - JLOG(j_.info()) << __func__ << " : " - << "Successfully wrote to Postgres"; - return true; - } - catch (std::exception& e) - { - JLOG(j_.error()) << __func__ - << "Caught exception writing to Postgres : " - << e.what(); - assert(false); - return false; - } -#else - return false; -#endif -} - -std::optional -PostgresDatabaseImp::getLedgerInfoByIndex(LedgerIndex ledgerSeq) -{ - return loadLedgerHelper(pgPool_, ledgerSeq, app_); -} - -std::optional -PostgresDatabaseImp::getNewestLedgerInfo() -{ - return loadLedgerHelper(pgPool_, {}, app_); -} - -std::optional -PostgresDatabaseImp::getLedgerInfoByHash(uint256 const& ledgerHash) -{ - return loadLedgerHelper(pgPool_, ledgerHash, app_); -} - -uint256 -PostgresDatabaseImp::getHashByIndex(LedgerIndex ledgerIndex) -{ - auto infos = loadLedgerInfos(pgPool_, ledgerIndex, app_); - assert(infos.size() <= 1); - if (infos.size()) - return infos[0].hash; - return {}; -} - -std::optional -PostgresDatabaseImp::getHashesByIndex(LedgerIndex ledgerIndex) -{ - LedgerHashPair p; - auto infos = loadLedgerInfos(pgPool_, ledgerIndex, app_); - assert(infos.size() <= 1); - if (infos.size()) - { - p.ledgerHash = infos[0].hash; - p.parentHash = infos[0].parentHash; - return p; - } - return {}; -} - -std::map -PostgresDatabaseImp::getHashesByIndex(LedgerIndex minSeq, LedgerIndex maxSeq) -{ - std::map ret; - auto infos = loadLedgerInfos(pgPool_, std::make_pair(minSeq, maxSeq), app_); - for (auto& info : infos) - { - ret[info.seq] = {info.hash, info.parentHash}; - } - return ret; -} - -std::vector -PostgresDatabaseImp::getTxHashes(LedgerIndex seq) -{ - std::vector nodestoreHashes; - -#ifdef RIPPLED_REPORTING - auto log = app_.journal("Ledger"); - - std::string query = - "SELECT nodestore_hash" - " FROM transactions " - " WHERE ledger_seq = " + - std::to_string(seq); - auto res = PgQuery(pgPool_)(query.c_str()); - - if (!res) - { - JLOG(log.error()) << __func__ - << " : Postgres response is null - query = " << query; - assert(false); - return {}; - } - else if (res.status() != PGRES_TUPLES_OK) - { - JLOG(log.error()) << __func__ - << " : Postgres response should have been " - "PGRES_TUPLES_OK but instead was " - << res.status() << " - msg = " << res.msg() - << " - query = " << query; - assert(false); - return {}; - } - - JLOG(log.trace()) << __func__ << " Postgres result msg : " << res.msg(); - - if (res.isNull() || res.ntuples() == 0) - { - JLOG(log.debug()) << __func__ - << " : Ledger not found. query = " << query; - return {}; - } - else if (res.ntuples() > 0) - { - if (res.nfields() != 1) - { - JLOG(log.error()) << __func__ - << " : Wrong number of fields in Postgres " - "response. Expected 1, but got " - << res.nfields() << " . query = " << query; - assert(false); - return {}; - } - } - - JLOG(log.trace()) << __func__ << " : result = " << res.c_str() - << " : query = " << query; - for (size_t i = 0; i < res.ntuples(); ++i) - { - char const* nodestoreHash = res.c_str(i, 0); - uint256 hash; - if (!hash.parseHex(nodestoreHash + 2)) - assert(false); - - nodestoreHashes.push_back(hash); - } -#endif - - return nodestoreHashes; -} - -std::vector> -PostgresDatabaseImp::getTxHistory(LedgerIndex startIndex) -{ - std::vector> ret; - -#ifdef RIPPLED_REPORTING - if (!app_.config().reporting()) - { - assert(false); - Throw( - "called getTxHistory but not in reporting mode"); - } - - std::string sql = boost::str( - boost::format("SELECT nodestore_hash, ledger_seq " - " FROM transactions" - " ORDER BY ledger_seq DESC LIMIT 20 " - "OFFSET %u;") % - startIndex); - - auto res = PgQuery(pgPool_)(sql.data()); - - if (!res) - { - JLOG(j_.error()) << __func__ - << " : Postgres response is null - sql = " << sql; - assert(false); - return {}; - } - else if (res.status() != PGRES_TUPLES_OK) - { - JLOG(j_.error()) << __func__ - << " : Postgres response should have been " - "PGRES_TUPLES_OK but instead was " - << res.status() << " - msg = " << res.msg() - << " - sql = " << sql; - assert(false); - return {}; - } - - JLOG(j_.trace()) << __func__ << " Postgres result msg : " << res.msg(); - - if (res.isNull() || res.ntuples() == 0) - { - JLOG(j_.debug()) << __func__ << " : Empty postgres response"; - assert(false); - return {}; - } - else if (res.ntuples() > 0) - { - if (res.nfields() != 2) - { - JLOG(j_.error()) << __func__ - << " : Wrong number of fields in Postgres " - "response. Expected 1, but got " - << res.nfields() << " . sql = " << sql; - assert(false); - return {}; - } - } - - JLOG(j_.trace()) << __func__ << " : Postgres result = " << res.c_str(); - - std::vector nodestoreHashes; - std::vector ledgerSequences; - for (size_t i = 0; i < res.ntuples(); ++i) - { - uint256 hash; - if (!hash.parseHex(res.c_str(i, 0) + 2)) - assert(false); - nodestoreHashes.push_back(hash); - ledgerSequences.push_back(res.asBigInt(i, 1)); - } - - auto txns = flatFetchTransactions(app_, nodestoreHashes); - for (size_t i = 0; i < txns.size(); ++i) - { - auto const& [sttx, meta] = txns[i]; - assert(sttx); - - std::string reason; - auto txn = std::make_shared(sttx, reason, app_); - txn->setLedger(ledgerSequences[i]); - txn->setStatus(COMMITTED); - ret.push_back(txn); - } - -#endif - return ret; -} - -std::pair -PostgresDatabaseImp::getAccountTx(AccountTxArgs const& args) -{ -#ifdef RIPPLED_REPORTING - pg_params dbParams; - - char const*& command = dbParams.first; - std::vector>& values = dbParams.second; - command = - "SELECT account_tx($1::bytea, $2::bool, " - "$3::bigint, $4::bigint, $5::bigint, $6::bytea, " - "$7::bigint, $8::bool, $9::bigint, $10::bigint)"; - values.resize(10); - values[0] = "\\x" + strHex(args.account); - values[1] = args.forward ? "true" : "false"; - - static std::uint32_t const page_length(200); - if (args.limit == 0 || args.limit > page_length) - values[2] = std::to_string(page_length); - else - values[2] = std::to_string(args.limit); - - if (args.ledger) - { - if (auto range = std::get_if(&args.ledger.value())) - { - values[3] = std::to_string(range->min); - values[4] = std::to_string(range->max); - } - else if (auto hash = std::get_if(&args.ledger.value())) - { - values[5] = ("\\x" + strHex(*hash)); - } - else if ( - auto sequence = std::get_if(&args.ledger.value())) - { - values[6] = std::to_string(*sequence); - } - else if (std::get_if(&args.ledger.value())) - { - // current, closed and validated are all treated as validated - values[7] = "true"; - } - else - { - JLOG(j_.error()) << "doAccountTxStoredProcedure - " - << "Error parsing ledger args"; - return {}; - } - } - - if (args.marker) - { - values[8] = std::to_string(args.marker->ledgerSeq); - values[9] = std::to_string(args.marker->txnSeq); - } - for (size_t i = 0; i < values.size(); ++i) - { - JLOG(j_.trace()) << "value " << std::to_string(i) << " = " - << (values[i] ? values[i].value() : "null"); - } - - auto res = PgQuery(pgPool_)(dbParams); - if (!res) - { - JLOG(j_.error()) << __func__ - << " : Postgres response is null - account = " - << strHex(args.account); - assert(false); - return {{}, {rpcINTERNAL, "Postgres error"}}; - } - else if (res.status() != PGRES_TUPLES_OK) - { - JLOG(j_.error()) << __func__ - << " : Postgres response should have been " - "PGRES_TUPLES_OK but instead was " - << res.status() << " - msg = " << res.msg() - << " - account = " << strHex(args.account); - assert(false); - return {{}, {rpcINTERNAL, "Postgres error"}}; - } - - JLOG(j_.trace()) << __func__ << " Postgres result msg : " << res.msg(); - if (res.isNull() || res.ntuples() == 0) - { - JLOG(j_.debug()) << __func__ - << " : No data returned from Postgres : account = " - << strHex(args.account); - - assert(false); - return {{}, {rpcINTERNAL, "Postgres error"}}; - } - - char const* resultStr = res.c_str(); - JLOG(j_.trace()) << __func__ << " : " - << "postgres result = " << resultStr - << " : account = " << strHex(args.account); - - Json::Value v; - Json::Reader reader; - bool success = reader.parse(resultStr, resultStr + strlen(resultStr), v); - if (success) - { - return processAccountTxStoredProcedureResult(args, v, app_, j_); - } -#endif - // This shouldn't happen. Postgres should return a parseable error - assert(false); - return {{}, {rpcINTERNAL, "Failed to deserialize Postgres result"}}; -} - -Transaction::Locator -PostgresDatabaseImp::locateTransaction(uint256 const& id) -{ -#ifdef RIPPLED_REPORTING - auto baseCmd = boost::format(R"(SELECT tx('%s');)"); - - std::string txHash = "\\x" + strHex(id); - std::string sql = boost::str(baseCmd % txHash); - - auto res = PgQuery(pgPool_)(sql.data()); - - if (!res) - { - JLOG(app_.journal("Transaction").error()) - << __func__ - << " : Postgres response is null - tx ID = " << strHex(id); - assert(false); - return {}; - } - else if (res.status() != PGRES_TUPLES_OK) - { - JLOG(app_.journal("Transaction").error()) - << __func__ - << " : Postgres response should have been " - "PGRES_TUPLES_OK but instead was " - << res.status() << " - msg = " << res.msg() - << " - tx ID = " << strHex(id); - assert(false); - return {}; - } - - JLOG(app_.journal("Transaction").trace()) - << __func__ << " Postgres result msg : " << res.msg(); - if (res.isNull() || res.ntuples() == 0) - { - JLOG(app_.journal("Transaction").debug()) - << __func__ - << " : No data returned from Postgres : tx ID = " << strHex(id); - // This shouldn't happen - assert(false); - return {}; - } - - char const* resultStr = res.c_str(); - JLOG(app_.journal("Transaction").debug()) - << "postgres result = " << resultStr; - - Json::Value v; - Json::Reader reader; - bool success = reader.parse(resultStr, resultStr + strlen(resultStr), v); - if (success) - { - if (v.isMember("nodestore_hash") && v.isMember("ledger_seq")) - { - uint256 nodestoreHash; - if (!nodestoreHash.parseHex( - v["nodestore_hash"].asString().substr(2))) - assert(false); - uint32_t ledgerSeq = v["ledger_seq"].asUInt(); - if (nodestoreHash.isNonZero()) - return {std::make_pair(nodestoreHash, ledgerSeq)}; - } - if (v.isMember("min_seq") && v.isMember("max_seq")) - { - return {ClosedInterval( - v["min_seq"].asUInt(), v["max_seq"].asUInt())}; - } - } -#endif - // Shouldn' happen. Postgres should return the ledger range searched if - // the transaction was not found - assert(false); - Throw( - "Transaction::Locate - Invalid Postgres response"); - return {}; -} - -bool -PostgresDatabaseImp::dbHasSpace(Config const& config) -{ - /* Postgres server could be running on a different machine. */ - - return true; -} - -bool -PostgresDatabaseImp::ledgerDbHasSpace(Config const& config) -{ - return dbHasSpace(config); -} - -bool -PostgresDatabaseImp::transactionDbHasSpace(Config const& config) -{ - return dbHasSpace(config); -} - -std::unique_ptr -getPostgresDatabase(Application& app, Config const& config, JobQueue& jobQueue) -{ - return std::make_unique(app, config, jobQueue); -} - -bool -PostgresDatabaseImp::isCaughtUp(std::string& reason) -{ -#ifdef RIPPLED_REPORTING - using namespace std::chrono_literals; - auto age = PgQuery(pgPool_)("SELECT age()"); - if (!age || age.isNull()) - { - reason = "No ledgers in database"; - return false; - } - if (std::chrono::seconds{age.asInt()} > 3min) - { - reason = "No recently-published ledger"; - return false; - } -#endif - return true; -} - -} // namespace ripple diff --git a/src/xrpld/app/rdb/detail/RelationalDatabase.cpp b/src/xrpld/app/rdb/detail/RelationalDatabase.cpp index 07dc27fd1d3..4a95134d705 100644 --- a/src/xrpld/app/rdb/detail/RelationalDatabase.cpp +++ b/src/xrpld/app/rdb/detail/RelationalDatabase.cpp @@ -26,9 +26,6 @@ namespace ripple { extern std::unique_ptr getSQLiteDatabase(Application& app, Config const& config, JobQueue& jobQueue); -extern std::unique_ptr -getPostgresDatabase(Application& app, Config const& config, JobQueue& jobQueue); - std::unique_ptr RelationalDatabase::init( Application& app, @@ -36,42 +33,30 @@ RelationalDatabase::init( JobQueue& jobQueue) { bool use_sqlite = false; - bool use_postgres = false; - if (config.reporting()) - { - use_postgres = true; - } - else + const Section& rdb_section{config.section(SECTION_RELATIONAL_DB)}; + if (!rdb_section.empty()) { - const Section& rdb_section{config.section(SECTION_RELATIONAL_DB)}; - if (!rdb_section.empty()) + if (boost::iequals(get(rdb_section, "backend"), "sqlite")) { - if (boost::iequals(get(rdb_section, "backend"), "sqlite")) - { - use_sqlite = true; - } - else - { - Throw( - "Invalid rdb_section backend value: " + - get(rdb_section, "backend")); - } + use_sqlite = true; } else { - use_sqlite = true; + Throw( + "Invalid rdb_section backend value: " + + get(rdb_section, "backend")); } } + else + { + use_sqlite = true; + } if (use_sqlite) { return getSQLiteDatabase(app, config, jobQueue); } - else if (use_postgres) - { - return getPostgresDatabase(app, config, jobQueue); - } return std::unique_ptr(); } diff --git a/src/xrpld/app/reporting/ETLHelpers.h b/src/xrpld/app/reporting/ETLHelpers.h deleted file mode 100644 index b11d2c4aa18..00000000000 --- a/src/xrpld/app/reporting/ETLHelpers.h +++ /dev/null @@ -1,195 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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_APP_REPORTING_ETLHELPERS_H_INCLUDED -#define RIPPLE_APP_REPORTING_ETLHELPERS_H_INCLUDED -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { - -/// This datastructure is used to keep track of the sequence of the most recent -/// ledger validated by the network. There are two methods that will wait until -/// certain conditions are met. This datastructure is able to be "stopped". When -/// the datastructure is stopped, any threads currently waiting are unblocked. -/// Any later calls to methods of this datastructure will not wait. Once the -/// datastructure is stopped, the datastructure remains stopped for the rest of -/// its lifetime. -class NetworkValidatedLedgers -{ - // max sequence validated by network - std::optional max_; - - mutable std::mutex m_; - - mutable std::condition_variable cv_; - - bool stopping_ = false; - -public: - /// Notify the datastructure that idx has been validated by the network - /// @param idx sequence validated by network - void - push(uint32_t idx) - { - std::lock_guard lck(m_); - if (!max_ || idx > *max_) - max_ = idx; - cv_.notify_all(); - } - - /// Get most recently validated sequence. If no ledgers are known to have - /// been validated, this function waits until the next ledger is validated - /// @return sequence of most recently validated ledger. empty optional if - /// the datastructure has been stopped - std::optional - getMostRecent() const - { - std::unique_lock lck(m_); - cv_.wait(lck, [this]() { return max_ || stopping_; }); - return max_; - } - - /// Get most recently validated sequence. - /// @return sequence of most recently validated ledger, or empty optional - /// if no ledgers are known to have been validated. - std::optional - tryGetMostRecent() const - { - std::unique_lock lk(m_); - return max_; - } - - /// Waits for the sequence to be validated by the network - /// @param sequence to wait for - /// @return true if sequence was validated, false otherwise - /// a return value of false means the datastructure has been stopped - bool - waitUntilValidatedByNetwork(uint32_t sequence) - { - std::unique_lock lck(m_); - cv_.wait(lck, [sequence, this]() { - return (max_ && sequence <= *max_) || stopping_; - }); - return !stopping_; - } - - /// Puts the datastructure in the stopped state - /// Future calls to this datastructure will not block - /// This operation cannot be reversed - void - stop() - { - std::lock_guard lck(m_); - stopping_ = true; - cv_.notify_all(); - } -}; - -/// Generic thread-safe queue with an optional maximum size -/// Note, we can't use a lockfree queue here, since we need the ability to wait -/// for an element to be added or removed from the queue. These waits are -/// blocking calls. -template -class ThreadSafeQueue -{ - std::queue queue_; - - mutable std::mutex m_; - std::condition_variable cv_; - std::optional maxSize_; - -public: - /// @param maxSize maximum size of the queue. Calls that would cause the - /// queue to exceed this size will block until free space is available - explicit ThreadSafeQueue(uint32_t maxSize) : maxSize_(maxSize) - { - } - - /// Create a queue with no maximum size - ThreadSafeQueue() = default; - - /// @param elt element to push onto queue - /// if maxSize is set, this method will block until free space is available - void - push(T const& elt) - { - std::unique_lock lck(m_); - // if queue has a max size, wait until not full - if (maxSize_) - cv_.wait(lck, [this]() { return queue_.size() <= *maxSize_; }); - queue_.push(elt); - cv_.notify_all(); - } - - /// @param elt element to push onto queue. elt is moved from - /// if maxSize is set, this method will block until free space is available - void - push(T&& elt) - { - std::unique_lock lck(m_); - // if queue has a max size, wait until not full - if (maxSize_) - cv_.wait(lck, [this]() { return queue_.size() <= *maxSize_; }); - queue_.push(std::move(elt)); - cv_.notify_all(); - } - - /// @return element popped from queue. Will block until queue is non-empty - T - pop() - { - std::unique_lock lck(m_); - cv_.wait(lck, [this]() { return !queue_.empty(); }); - T ret = std::move(queue_.front()); - queue_.pop(); - // if queue has a max size, unblock any possible pushers - if (maxSize_) - cv_.notify_all(); - return ret; - } -}; - -/// Parititions the uint256 keyspace into numMarkers partitions, each of equal -/// size. -inline std::vector -getMarkers(size_t numMarkers) -{ - assert(numMarkers <= 256); - - unsigned char incr = 256 / numMarkers; - - std::vector markers; - markers.reserve(numMarkers); - uint256 base{0}; - for (size_t i = 0; i < numMarkers; ++i) - { - markers.push_back(base); - base.data()[0] += incr; - } - return markers; -} - -} // namespace ripple -#endif diff --git a/src/xrpld/app/reporting/ETLSource.cpp b/src/xrpld/app/reporting/ETLSource.cpp deleted file mode 100644 index 8a181c62b1d..00000000000 --- a/src/xrpld/app/reporting/ETLSource.cpp +++ /dev/null @@ -1,982 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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 -#include -#include -#include -#include - -namespace ripple { - -// Create ETL source without grpc endpoint -// Fetch ledger and load initial ledger will fail for this source -// Primarily used in read-only mode, to monitor when ledgers are validated -ETLSource::ETLSource(std::string ip, std::string wsPort, ReportingETL& etl) - : ip_(ip) - , wsPort_(wsPort) - , etl_(etl) - , ioc_(etl.getApplication().getIOService()) - , ws_(std::make_unique< - boost::beast::websocket::stream>( - boost::asio::make_strand(ioc_))) - , resolver_(boost::asio::make_strand(ioc_)) - , networkValidatedLedgers_(etl_.getNetworkValidatedLedgers()) - , journal_(etl_.getApplication().journal("ReportingETL::ETLSource")) - , app_(etl_.getApplication()) - , timer_(ioc_) -{ -} - -ETLSource::ETLSource( - std::string ip, - std::string wsPort, - std::string grpcPort, - ReportingETL& etl) - : ip_(ip) - , wsPort_(wsPort) - , grpcPort_(grpcPort) - , etl_(etl) - , ioc_(etl.getApplication().getIOService()) - , ws_(std::make_unique< - boost::beast::websocket::stream>( - boost::asio::make_strand(ioc_))) - , resolver_(boost::asio::make_strand(ioc_)) - , networkValidatedLedgers_(etl_.getNetworkValidatedLedgers()) - , journal_(etl_.getApplication().journal("ReportingETL::ETLSource")) - , app_(etl_.getApplication()) - , timer_(ioc_) -{ - std::string connectionString; - try - { - connectionString = - beast::IP::Endpoint( - boost::asio::ip::make_address(ip_), std::stoi(grpcPort_)) - .to_string(); - - JLOG(journal_.info()) - << "Using IP to connect to ETL source: " << connectionString; - } - catch (std::exception const&) - { - connectionString = "dns:" + ip_ + ":" + grpcPort_; - JLOG(journal_.info()) - << "Using DNS to connect to ETL source: " << connectionString; - } - try - { - stub_ = org::xrpl::rpc::v1::XRPLedgerAPIService::NewStub( - grpc::CreateChannel( - connectionString, grpc::InsecureChannelCredentials())); - JLOG(journal_.info()) << "Made stub for remote = " << toString(); - } - catch (std::exception const& e) - { - JLOG(journal_.error()) << "Exception while creating stub = " << e.what() - << " . Remote = " << toString(); - } -} - -void -ETLSource::reconnect(boost::beast::error_code ec) -{ - connected_ = false; - // These are somewhat normal errors. operation_aborted occurs on shutdown, - // when the timer is cancelled. connection_refused will occur repeatedly - // if we cannot connect to the transaction processing process - if (ec != boost::asio::error::operation_aborted && - ec != boost::asio::error::connection_refused) - { - JLOG(journal_.error()) << __func__ << " : " - << "error code = " << ec << " - " << toString(); - } - else - { - JLOG(journal_.warn()) << __func__ << " : " - << "error code = " << ec << " - " << toString(); - } - - if (etl_.isStopping()) - { - JLOG(journal_.debug()) << __func__ << " : " << toString() - << " - etl is stopping. aborting reconnect"; - return; - } - - // exponentially increasing timeouts, with a max of 30 seconds - size_t waitTime = std::min(pow(2, numFailures_), 30.0); - numFailures_++; - timer_.expires_after(boost::asio::chrono::seconds(waitTime)); - timer_.async_wait([this, fname = __func__](auto ec) { - bool startAgain = (ec != boost::asio::error::operation_aborted); - JLOG(journal_.trace()) << fname << " async_wait : ec = " << ec; - close(startAgain); - }); -} - -void -ETLSource::close(bool startAgain) -{ - timer_.cancel(); - ioc_.post([this, startAgain]() { - if (closing_) - return; - - if (ws_->is_open()) - { - // onStop() also calls close(). If the async_close is called twice, - // an assertion fails. Using closing_ makes sure async_close is only - // called once - closing_ = true; - ws_->async_close( - boost::beast::websocket::close_code::normal, - [this, startAgain, fname = __func__](auto ec) { - if (ec) - { - JLOG(journal_.error()) - << fname << " async_close : " - << "error code = " << ec << " - " << toString(); - } - closing_ = false; - if (startAgain) - start(); - }); - } - else if (startAgain) - { - start(); - } - }); -} - -void -ETLSource::start() -{ - JLOG(journal_.trace()) << __func__ << " : " << toString(); - - auto const host = ip_; - auto const port = wsPort_; - - resolver_.async_resolve( - host, port, [this](auto ec, auto results) { onResolve(ec, results); }); -} - -void -ETLSource::onResolve( - boost::beast::error_code ec, - boost::asio::ip::tcp::resolver::results_type results) -{ - JLOG(journal_.trace()) << __func__ << " : ec = " << ec << " - " - << toString(); - if (ec) - { - // try again - reconnect(ec); - } - else - { - boost::beast::get_lowest_layer(*ws_).expires_after( - std::chrono::seconds(30)); - boost::beast::get_lowest_layer(*ws_).async_connect( - results, [this](auto ec, auto ep) { onConnect(ec, ep); }); - } -} - -void -ETLSource::onConnect( - boost::beast::error_code ec, - boost::asio::ip::tcp::resolver::results_type::endpoint_type endpoint) -{ - JLOG(journal_.trace()) << __func__ << " : ec = " << ec << " - " - << toString(); - if (ec) - { - // start over - reconnect(ec); - } - else - { - numFailures_ = 0; - // Turn off timeout on the tcp stream, because websocket stream has it's - // own timeout system - boost::beast::get_lowest_layer(*ws_).expires_never(); - - // Set suggested timeout settings for the websocket - ws_->set_option( - boost::beast::websocket::stream_base::timeout::suggested( - boost::beast::role_type::client)); - - // Set a decorator to change the User-Agent of the handshake - ws_->set_option(boost::beast::websocket::stream_base::decorator( - [](boost::beast::websocket::request_type& req) { - req.set( - boost::beast::http::field::user_agent, - std::string(BOOST_BEAST_VERSION_STRING) + - " websocket-client-async"); - })); - - // Update the host_ string. This will provide the value of the - // Host HTTP header during the WebSocket handshake. - // See https://tools.ietf.org/html/rfc7230#section-5.4 - auto host = ip_ + ':' + std::to_string(endpoint.port()); - // Perform the websocket handshake - ws_->async_handshake(host, "/", [this](auto ec) { onHandshake(ec); }); - } -} - -void -ETLSource::onHandshake(boost::beast::error_code ec) -{ - JLOG(journal_.trace()) << __func__ << " : ec = " << ec << " - " - << toString(); - if (ec) - { - // start over - reconnect(ec); - } - else - { - Json::Value jv; - jv["command"] = "subscribe"; - - jv["streams"] = Json::arrayValue; - Json::Value ledgerStream("ledger"); - jv["streams"].append(ledgerStream); - Json::Value txnStream("transactions_proposed"); - jv["streams"].append(txnStream); - Json::Value validationStream("validations"); - jv["streams"].append(validationStream); - Json::Value manifestStream("manifests"); - jv["streams"].append(manifestStream); - Json::FastWriter fastWriter; - - JLOG(journal_.trace()) << "Sending subscribe stream message"; - // Send the message - ws_->async_write( - boost::asio::buffer(fastWriter.write(jv)), - [this](auto ec, size_t size) { onWrite(ec, size); }); - } -} - -void -ETLSource::onWrite(boost::beast::error_code ec, size_t bytesWritten) -{ - JLOG(journal_.trace()) << __func__ << " : ec = " << ec << " - " - << toString(); - if (ec) - { - // start over - reconnect(ec); - } - else - { - ws_->async_read( - readBuffer_, [this](auto ec, size_t size) { onRead(ec, size); }); - } -} - -void -ETLSource::onRead(boost::beast::error_code ec, size_t size) -{ - JLOG(journal_.trace()) << __func__ << " : ec = " << ec << " - " - << toString(); - // if error or error reading message, start over - if (ec) - { - reconnect(ec); - } - else - { - handleMessage(); - boost::beast::flat_buffer buffer; - swap(readBuffer_, buffer); - - JLOG(journal_.trace()) - << __func__ << " : calling async_read - " << toString(); - ws_->async_read( - readBuffer_, [this](auto ec, size_t size) { onRead(ec, size); }); - } -} - -bool -ETLSource::handleMessage() -{ - JLOG(journal_.trace()) << __func__ << " : " << toString(); - - setLastMsgTime(); - connected_ = true; - try - { - Json::Value response; - Json::Reader reader; - if (!reader.parse( - static_cast(readBuffer_.data().data()), response)) - { - JLOG(journal_.error()) - << __func__ << " : " - << "Error parsing stream message." - << " Message = " << readBuffer_.data().data(); - return false; - } - - uint32_t ledgerIndex = 0; - if (response.isMember("result")) - { - if (response["result"].isMember(jss::ledger_index)) - { - ledgerIndex = response["result"][jss::ledger_index].asUInt(); - } - if (response[jss::result].isMember(jss::validated_ledgers)) - { - setValidatedRange( - response[jss::result][jss::validated_ledgers].asString()); - } - JLOG(journal_.debug()) - << __func__ << " : " - << "Received a message on ledger " - << " subscription stream. Message : " - << response.toStyledString() << " - " << toString(); - } - else - { - if (etl_.getETLLoadBalancer().shouldPropagateStream(this)) - { - if (response.isMember(jss::transaction)) - { - etl_.getApplication().getOPs().forwardProposedTransaction( - response); - } - else if ( - response.isMember("type") && - response["type"] == "validationReceived") - { - etl_.getApplication().getOPs().forwardValidation(response); - } - else if ( - response.isMember("type") && - response["type"] == "manifestReceived") - { - etl_.getApplication().getOPs().forwardManifest(response); - } - } - - if (response.isMember("type") && response["type"] == "ledgerClosed") - { - JLOG(journal_.debug()) - << __func__ << " : " - << "Received a message on ledger " - << " subscription stream. Message : " - << response.toStyledString() << " - " << toString(); - if (response.isMember(jss::ledger_index)) - { - ledgerIndex = response[jss::ledger_index].asUInt(); - } - if (response.isMember(jss::validated_ledgers)) - { - setValidatedRange( - response[jss::validated_ledgers].asString()); - } - } - } - - if (ledgerIndex != 0) - { - JLOG(journal_.trace()) - << __func__ << " : " - << "Pushing ledger sequence = " << ledgerIndex << " - " - << toString(); - networkValidatedLedgers_.push(ledgerIndex); - } - return true; - } - catch (std::exception const& e) - { - JLOG(journal_.error()) << "Exception in handleMessage : " << e.what(); - return false; - } -} - -class AsyncCallData -{ - std::unique_ptr cur_; - std::unique_ptr next_; - - org::xrpl::rpc::v1::GetLedgerDataRequest request_; - std::unique_ptr context_; - - grpc::Status status_; - - unsigned char nextPrefix_; - - beast::Journal journal_; - -public: - AsyncCallData( - uint256& marker, - std::optional nextMarker, - uint32_t seq, - beast::Journal& j) - : journal_(j) - { - request_.mutable_ledger()->set_sequence(seq); - if (marker.isNonZero()) - { - request_.set_marker(marker.data(), marker.size()); - } - request_.set_user("ETL"); - nextPrefix_ = 0x00; - if (nextMarker) - nextPrefix_ = nextMarker->data()[0]; - - unsigned char prefix = marker.data()[0]; - - JLOG(journal_.debug()) - << "Setting up AsyncCallData. marker = " << strHex(marker) - << " . prefix = " << strHex(std::string(1, prefix)) - << " . nextPrefix_ = " << strHex(std::string(1, nextPrefix_)); - - assert(nextPrefix_ > prefix || nextPrefix_ == 0x00); - - cur_ = std::make_unique(); - - next_ = std::make_unique(); - - context_ = std::make_unique(); - } - - enum class CallStatus { MORE, DONE, ERRORED }; - CallStatus - process( - std::unique_ptr& stub, - grpc::CompletionQueue& cq, - ThreadSafeQueue>& queue, - bool abort = false) - { - JLOG(journal_.debug()) << "Processing calldata"; - if (abort) - { - JLOG(journal_.error()) << "AsyncCallData aborted"; - return CallStatus::ERRORED; - } - if (!status_.ok()) - { - JLOG(journal_.debug()) << "AsyncCallData status_ not ok: " - << " code = " << status_.error_code() - << " message = " << status_.error_message(); - return CallStatus::ERRORED; - } - if (!next_->is_unlimited()) - { - JLOG(journal_.warn()) - << "AsyncCallData is_unlimited is false. Make sure " - "secure_gateway is set correctly at the ETL source"; - assert(false); - } - - std::swap(cur_, next_); - - bool more = true; - - // if no marker returned, we are done - if (cur_->marker().size() == 0) - more = false; - - // if returned marker is greater than our end, we are done - unsigned char prefix = cur_->marker()[0]; - if (nextPrefix_ != 0x00 && prefix >= nextPrefix_) - more = false; - - // if we are not done, make the next async call - if (more) - { - request_.set_marker(std::move(cur_->marker())); - call(stub, cq); - } - - for (auto& obj : cur_->ledger_objects().objects()) - { - auto key = uint256::fromVoidChecked(obj.key()); - if (!key) - throw std::runtime_error("Received malformed object ID"); - - auto& data = obj.data(); - - SerialIter it{data.data(), data.size()}; - std::shared_ptr sle = std::make_shared(it, *key); - - queue.push(sle); - } - - return more ? CallStatus::MORE : CallStatus::DONE; - } - - void - call( - std::unique_ptr& stub, - grpc::CompletionQueue& cq) - { - context_ = std::make_unique(); - - std::unique_ptr> - rpc(stub->PrepareAsyncGetLedgerData(context_.get(), request_, &cq)); - - rpc->StartCall(); - - rpc->Finish(next_.get(), &status_, this); - } - - std::string - getMarkerPrefix() - { - if (next_->marker().size() == 0) - return ""; - else - return strHex(std::string{next_->marker().data()[0]}); - } -}; - -bool -ETLSource::loadInitialLedger( - uint32_t sequence, - ThreadSafeQueue>& writeQueue) -{ - if (!stub_) - return false; - - grpc::CompletionQueue cq; - - void* tag; - - bool ok = false; - - std::vector calls; - std::vector markers{getMarkers(etl_.getNumMarkers())}; - - for (size_t i = 0; i < markers.size(); ++i) - { - std::optional nextMarker; - if (i + 1 < markers.size()) - nextMarker = markers[i + 1]; - calls.emplace_back(markers[i], nextMarker, sequence, journal_); - } - - JLOG(journal_.debug()) << "Starting data download for ledger " << sequence - << ". Using source = " << toString(); - - for (auto& c : calls) - c.call(stub_, cq); - - size_t numFinished = 0; - bool abort = false; - while (numFinished < calls.size() && !etl_.isStopping() && - cq.Next(&tag, &ok)) - { - assert(tag); - - auto ptr = static_cast(tag); - - if (!ok) - { - JLOG(journal_.error()) << "loadInitialLedger - ok is false"; - return false; - // handle cancelled - } - else - { - JLOG(journal_.debug()) - << "Marker prefix = " << ptr->getMarkerPrefix(); - auto result = ptr->process(stub_, cq, writeQueue, abort); - if (result != AsyncCallData::CallStatus::MORE) - { - numFinished++; - JLOG(journal_.debug()) - << "Finished a marker. " - << "Current number of finished = " << numFinished; - } - if (result == AsyncCallData::CallStatus::ERRORED) - { - abort = true; - } - } - } - return !abort; -} - -std::pair -ETLSource::fetchLedger(uint32_t ledgerSequence, bool getObjects) -{ - org::xrpl::rpc::v1::GetLedgerResponse response; - if (!stub_) - return {{grpc::StatusCode::INTERNAL, "No Stub"}, response}; - - // ledger header with txns and metadata - org::xrpl::rpc::v1::GetLedgerRequest request; - grpc::ClientContext context; - request.mutable_ledger()->set_sequence(ledgerSequence); - request.set_transactions(true); - request.set_expand(true); - request.set_get_objects(getObjects); - request.set_user("ETL"); - grpc::Status status = stub_->GetLedger(&context, request, &response); - if (status.ok() && !response.is_unlimited()) - { - JLOG(journal_.warn()) << "ETLSource::fetchLedger - is_unlimited is " - "false. Make sure secure_gateway is set " - "correctly on the ETL source. source = " - << toString(); - assert(false); - } - return {status, std::move(response)}; -} - -ETLLoadBalancer::ETLLoadBalancer(ReportingETL& etl) - : etl_(etl) - , journal_(etl_.getApplication().journal("ReportingETL::LoadBalancer")) -{ -} - -void -ETLLoadBalancer::add( - std::string& host, - std::string& websocketPort, - std::string& grpcPort) -{ - std::unique_ptr ptr = - std::make_unique(host, websocketPort, grpcPort, etl_); - sources_.push_back(std::move(ptr)); - JLOG(journal_.info()) << __func__ << " : added etl source - " - << sources_.back()->toString(); -} - -void -ETLLoadBalancer::add(std::string& host, std::string& websocketPort) -{ - std::unique_ptr ptr = - std::make_unique(host, websocketPort, etl_); - sources_.push_back(std::move(ptr)); - JLOG(journal_.info()) << __func__ << " : added etl source - " - << sources_.back()->toString(); -} - -void -ETLLoadBalancer::loadInitialLedger( - uint32_t sequence, - ThreadSafeQueue>& writeQueue) -{ - execute( - [this, &sequence, &writeQueue](auto& source) { - bool res = source->loadInitialLedger(sequence, writeQueue); - if (!res) - { - JLOG(journal_.error()) << "Failed to download initial ledger. " - << " Sequence = " << sequence - << " source = " << source->toString(); - } - return res; - }, - sequence); -} - -std::optional -ETLLoadBalancer::fetchLedger(uint32_t ledgerSequence, bool getObjects) -{ - org::xrpl::rpc::v1::GetLedgerResponse response; - bool success = execute( - [&response, ledgerSequence, getObjects, this](auto& source) { - auto [status, data] = - source->fetchLedger(ledgerSequence, getObjects); - response = std::move(data); - if (status.ok() && response.validated()) - { - JLOG(journal_.info()) - << "Successfully fetched ledger = " << ledgerSequence - << " from source = " << source->toString(); - return true; - } - else - { - JLOG(journal_.warn()) - << "Error getting ledger = " << ledgerSequence - << " Reply : " << response.DebugString() - << " error_code : " << status.error_code() - << " error_msg : " << status.error_message() - << " source = " << source->toString(); - return false; - } - }, - ledgerSequence); - if (success) - return response; - else - return {}; -} - -std::unique_ptr -ETLLoadBalancer::getP2pForwardingStub() const -{ - if (sources_.size() == 0) - return nullptr; - srand((unsigned)time(0)); - auto sourceIdx = rand() % sources_.size(); - auto numAttempts = 0; - while (numAttempts < sources_.size()) - { - auto stub = sources_[sourceIdx]->getP2pForwardingStub(); - if (!stub) - { - sourceIdx = (sourceIdx + 1) % sources_.size(); - ++numAttempts; - continue; - } - return stub; - } - return nullptr; -} - -Json::Value -ETLLoadBalancer::forwardToP2p(RPC::JsonContext& context) const -{ - Json::Value res; - if (sources_.size() == 0) - return res; - srand((unsigned)time(0)); - auto sourceIdx = rand() % sources_.size(); - auto numAttempts = 0; - - auto mostRecent = etl_.getNetworkValidatedLedgers().tryGetMostRecent(); - while (numAttempts < sources_.size()) - { - auto increment = [&]() { - sourceIdx = (sourceIdx + 1) % sources_.size(); - ++numAttempts; - }; - auto& src = sources_[sourceIdx]; - if (mostRecent && !src->hasLedger(*mostRecent)) - { - increment(); - continue; - } - res = src->forwardToP2p(context); - if (!res.isMember("forwarded") || res["forwarded"] != true) - { - increment(); - continue; - } - return res; - } - RPC::Status err = {rpcFAILED_TO_FORWARD}; - err.inject(res); - return res; -} - -std::unique_ptr -ETLSource::getP2pForwardingStub() const -{ - if (!connected_) - return nullptr; - try - { - return org::xrpl::rpc::v1::XRPLedgerAPIService::NewStub( - grpc::CreateChannel( - beast::IP::Endpoint( - boost::asio::ip::make_address(ip_), std::stoi(grpcPort_)) - .to_string(), - grpc::InsecureChannelCredentials())); - } - catch (std::exception const&) - { - JLOG(journal_.error()) << "Failed to create grpc stub"; - return nullptr; - } -} - -Json::Value -ETLSource::forwardToP2p(RPC::JsonContext& context) const -{ - JLOG(journal_.debug()) << "Attempting to forward request to tx. " - << "request = " << context.params.toStyledString(); - - Json::Value response; - if (!connected_) - { - JLOG(journal_.error()) - << "Attempted to proxy but failed to connect to tx"; - return response; - } - namespace beast = boost::beast; // from - namespace http = beast::http; // from - namespace websocket = beast::websocket; // from - namespace net = boost::asio; // from - using tcp = boost::asio::ip::tcp; // from - Json::Value& request = context.params; - try - { - // The io_context is required for all I/O - net::io_context ioc; - - // These objects perform our I/O - tcp::resolver resolver{ioc}; - - JLOG(journal_.debug()) << "Creating websocket"; - auto ws = std::make_unique>(ioc); - - // Look up the domain name - auto const results = resolver.resolve(ip_, wsPort_); - - JLOG(journal_.debug()) << "Connecting websocket"; - // Make the connection on the IP address we get from a lookup - net::connect(ws->next_layer(), results.begin(), results.end()); - - // Set a decorator to change the User-Agent of the handshake - // and to tell rippled to charge the client IP for RPC - // resources. See "secure_gateway" in - // https://github.com/ripple/rippled/blob/develop/cfg/rippled-example.cfg - ws->set_option(websocket::stream_base::decorator( - [&context](websocket::request_type& req) { - req.set( - http::field::user_agent, - std::string(BOOST_BEAST_VERSION_STRING) + - " websocket-client-coro"); - req.set( - http::field::forwarded, - "for=" + context.consumer.to_string()); - })); - JLOG(journal_.debug()) << "client ip: " << context.consumer.to_string(); - - JLOG(journal_.debug()) << "Performing websocket handshake"; - // Perform the websocket handshake - ws->handshake(ip_, "/"); - - Json::FastWriter fastWriter; - - JLOG(journal_.debug()) << "Sending request"; - // Send the message - ws->write(net::buffer(fastWriter.write(request))); - - beast::flat_buffer buffer; - ws->read(buffer); - - Json::Reader reader; - if (!reader.parse( - static_cast(buffer.data().data()), response)) - { - JLOG(journal_.error()) << "Error parsing response"; - response[jss::error] = "Error parsing response from tx"; - } - JLOG(journal_.debug()) << "Successfully forward request"; - - response["forwarded"] = true; - return response; - } - catch (std::exception const& e) - { - JLOG(journal_.error()) << "Encountered exception : " << e.what(); - return response; - } -} - -template -bool -ETLLoadBalancer::execute(Func f, uint32_t ledgerSequence) -{ - srand((unsigned)time(0)); - auto sourceIdx = rand() % sources_.size(); - auto numAttempts = 0; - - while (!etl_.isStopping()) - { - auto& source = sources_[sourceIdx]; - - JLOG(journal_.debug()) - << __func__ << " : " - << "Attempting to execute func. ledger sequence = " - << ledgerSequence << " - source = " << source->toString(); - if (source->hasLedger(ledgerSequence)) - { - bool res = f(source); - if (res) - { - JLOG(journal_.debug()) - << __func__ << " : " - << "Successfully executed func at source = " - << source->toString() - << " - ledger sequence = " << ledgerSequence; - break; - } - else - { - JLOG(journal_.warn()) - << __func__ << " : " - << "Failed to execute func at source = " - << source->toString() - << " - ledger sequence = " << ledgerSequence; - } - } - else - { - JLOG(journal_.warn()) - << __func__ << " : " - << "Ledger not present at source = " << source->toString() - << " - ledger sequence = " << ledgerSequence; - } - sourceIdx = (sourceIdx + 1) % sources_.size(); - numAttempts++; - if (numAttempts % sources_.size() == 0) - { - // If another process loaded the ledger into the database, we can - // abort trying to fetch the ledger from a transaction processing - // process - if (etl_.getApplication().getLedgerMaster().getLedgerBySeq( - ledgerSequence)) - { - JLOG(journal_.warn()) - << __func__ << " : " - << "Error executing function. " - << " Tried all sources, but ledger was found in db." - << " Sequence = " << ledgerSequence; - return false; - } - JLOG(journal_.error()) - << __func__ << " : " - << "Error executing function " - << " - ledger sequence = " << ledgerSequence - << " - Tried all sources. Sleeping and trying again"; - std::this_thread::sleep_for(std::chrono::seconds(2)); - } - } - return !etl_.isStopping(); -} - -void -ETLLoadBalancer::start() -{ - for (auto& source : sources_) - source->start(); -} - -void -ETLLoadBalancer::stop() -{ - for (auto& source : sources_) - source->stop(); -} - -} // namespace ripple diff --git a/src/xrpld/app/reporting/ETLSource.h b/src/xrpld/app/reporting/ETLSource.h deleted file mode 100644 index 633b72afac1..00000000000 --- a/src/xrpld/app/reporting/ETLSource.h +++ /dev/null @@ -1,435 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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_APP_REPORTING_ETLSOURCE_H_INCLUDED -#define RIPPLE_APP_REPORTING_ETLSOURCE_H_INCLUDED -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -namespace ripple { - -class ReportingETL; - -/// This class manages a connection to a single ETL source. This is almost -/// always a p2p node, but really could be another reporting node. This class -/// subscribes to the ledgers and transactions_proposed streams of the -/// associated p2p node, and keeps track of which ledgers the p2p node has. This -/// class also has methods for extracting said ledgers. Lastly this class -/// forwards transactions received on the transactions_proposed streams to any -/// subscribers. -class ETLSource -{ - std::string ip_; - - std::string wsPort_; - - std::string grpcPort_; - - ReportingETL& etl_; - - // a reference to the applications io_service - boost::asio::io_context& ioc_; - - std::unique_ptr stub_; - - std::unique_ptr> - ws_; - boost::asio::ip::tcp::resolver resolver_; - - boost::beast::flat_buffer readBuffer_; - - std::vector> validatedLedgers_; - - std::string validatedLedgersRaw_; - - NetworkValidatedLedgers& networkValidatedLedgers_; - - beast::Journal journal_; - - Application& app_; - - mutable std::mutex mtx_; - - size_t numFailures_ = 0; - - std::atomic_bool closing_ = false; - - std::atomic_bool connected_ = false; - - // true if this ETL source is forwarding transactions received on the - // transactions_proposed stream. There are usually multiple ETL sources, - // so to avoid forwarding the same transaction multiple times, we only - // forward from one particular ETL source at a time. - std::atomic_bool forwardingStream_ = false; - - // The last time a message was received on the ledgers stream - std::chrono::system_clock::time_point lastMsgTime_; - mutable std::mutex lastMsgTimeMtx_; - - // used for retrying connections - boost::asio::steady_timer timer_; - -public: - bool - isConnected() const - { - return connected_; - } - - std::chrono::system_clock::time_point - getLastMsgTime() const - { - std::lock_guard lck(lastMsgTimeMtx_); - return lastMsgTime_; - } - - void - setLastMsgTime() - { - std::lock_guard lck(lastMsgTimeMtx_); - lastMsgTime_ = std::chrono::system_clock::now(); - } - - /// Create ETL source without gRPC endpoint - /// Fetch ledger and load initial ledger will fail for this source - /// Primarly used in read-only mode, to monitor when ledgers are validated - ETLSource(std::string ip, std::string wsPort, ReportingETL& etl); - - /// Create ETL source with gRPC endpoint - ETLSource( - std::string ip, - std::string wsPort, - std::string grpcPort, - ReportingETL& etl); - - /// @param sequence ledger sequence to check for - /// @return true if this source has the desired ledger - bool - hasLedger(uint32_t sequence) const - { - std::lock_guard lck(mtx_); - for (auto& pair : validatedLedgers_) - { - if (sequence >= pair.first && sequence <= pair.second) - { - return true; - } - else if (sequence < pair.first) - { - // validatedLedgers_ is a sorted list of disjoint ranges - // if the sequence comes before this range, the sequence will - // come before all subsequent ranges - return false; - } - } - return false; - } - - /// process the validated range received on the ledgers stream. set the - /// appropriate member variable - /// @param range validated range received on ledgers stream - void - setValidatedRange(std::string const& range) - { - std::vector> pairs; - std::vector ranges; - boost::split(ranges, range, boost::is_any_of(",")); - for (auto& pair : ranges) - { - std::vector minAndMax; - - boost::split(minAndMax, pair, boost::is_any_of("-")); - - if (minAndMax.size() == 1) - { - uint32_t sequence = std::stoll(minAndMax[0]); - pairs.push_back(std::make_pair(sequence, sequence)); - } - else - { - assert(minAndMax.size() == 2); - uint32_t min = std::stoll(minAndMax[0]); - uint32_t max = std::stoll(minAndMax[1]); - pairs.push_back(std::make_pair(min, max)); - } - } - std::sort(pairs.begin(), pairs.end(), [](auto left, auto right) { - return left.first < right.first; - }); - - // we only hold the lock here, to avoid blocking while string processing - std::lock_guard lck(mtx_); - validatedLedgers_ = std::move(pairs); - validatedLedgersRaw_ = range; - } - - /// @return the validated range of this source - /// @note this is only used by server_info - std::string - getValidatedRange() const - { - std::lock_guard lck(mtx_); - - return validatedLedgersRaw_; - } - - /// Close the underlying websocket - void - stop() - { - JLOG(journal_.debug()) << __func__ << " : " - << "Closing websocket"; - - assert(ws_); - close(false); - } - - /// Fetch the specified ledger - /// @param ledgerSequence sequence of the ledger to fetch - /// @getObjects whether to get the account state diff between this ledger - /// and the prior one - /// @return the extracted data and the result status - std::pair - fetchLedger(uint32_t ledgerSequence, bool getObjects = true); - - std::string - toString() const - { - return "{ validated_ledger : " + getValidatedRange() + - " , ip : " + ip_ + " , web socket port : " + wsPort_ + - ", grpc port : " + grpcPort_ + " }"; - } - - Json::Value - toJson() const - { - Json::Value result(Json::objectValue); - result["connected"] = connected_.load(); - result["validated_ledgers_range"] = getValidatedRange(); - result["ip"] = ip_; - result["websocket_port"] = wsPort_; - result["grpc_port"] = grpcPort_; - auto last = getLastMsgTime(); - if (last.time_since_epoch().count() != 0) - result["last_message_arrival_time"] = - to_string(std::chrono::floor(last)); - return result; - } - - /// Download a ledger in full - /// @param ledgerSequence sequence of the ledger to download - /// @param writeQueue queue to push downloaded ledger objects - /// @return true if the download was successful - bool - loadInitialLedger( - uint32_t ledgerSequence, - ThreadSafeQueue>& writeQueue); - - /// Begin sequence of operations to connect to the ETL source and subscribe - /// to ledgers and transactions_proposed - void - start(); - - /// Attempt to reconnect to the ETL source - void - reconnect(boost::beast::error_code ec); - - /// Callback - void - onResolve( - boost::beast::error_code ec, - boost::asio::ip::tcp::resolver::results_type results); - - /// Callback - void - onConnect( - boost::beast::error_code ec, - boost::asio::ip::tcp::resolver::results_type::endpoint_type endpoint); - - /// Callback - void - onHandshake(boost::beast::error_code ec); - - /// Callback - void - onWrite(boost::beast::error_code ec, size_t size); - - /// Callback - void - onRead(boost::beast::error_code ec, size_t size); - - /// Handle the most recently received message - /// @return true if the message was handled successfully. false on error - bool - handleMessage(); - - /// Close the websocket - /// @param startAgain whether to reconnect - void - close(bool startAgain); - - /// Get grpc stub to forward requests to p2p node - /// @return stub to send requests to ETL source - std::unique_ptr - getP2pForwardingStub() const; - - /// Forward a JSON RPC request to a p2p node - /// @param context context of RPC request - /// @return response received from ETL source - Json::Value - forwardToP2p(RPC::JsonContext& context) const; -}; - -/// This class is used to manage connections to transaction processing processes -/// This class spawns a listener for each etl source, which listens to messages -/// on the ledgers stream (to keep track of which ledgers have been validated by -/// the network, and the range of ledgers each etl source has). This class also -/// allows requests for ledger data to be load balanced across all possible etl -/// sources. -class ETLLoadBalancer -{ -private: - ReportingETL& etl_; - - beast::Journal journal_; - - std::vector> sources_; - -public: - ETLLoadBalancer(ReportingETL& etl); - - /// Add an ETL source - /// @param host host or ip of ETL source - /// @param websocketPort port where ETL source accepts websocket connections - /// @param grpcPort port where ETL source accepts gRPC requests - void - add(std::string& host, std::string& websocketPort, std::string& grpcPort); - - /// Add an ETL source without gRPC support. This source will send messages - /// on the ledgers and transactions_proposed streams, but will not be able - /// to handle the gRPC requests that are used for ETL - /// @param host host or ip of ETL source - /// @param websocketPort port where ETL source accepts websocket connections - void - add(std::string& host, std::string& websocketPort); - - /// Load the initial ledger, writing data to the queue - /// @param sequence sequence of ledger to download - /// @param writeQueue queue to push downloaded data to - void - loadInitialLedger( - uint32_t sequence, - ThreadSafeQueue>& writeQueue); - - /// Fetch data for a specific ledger. This function will continuously try - /// to fetch data for the specified ledger until the fetch succeeds, the - /// ledger is found in the database, or the server is shutting down. - /// @param ledgerSequence sequence of ledger to fetch data for - /// @param getObjects if true, fetch diff between specified ledger and - /// previous - /// @return the extracted data, if extraction was successful. If the ledger - /// was found in the database or the server is shutting down, the optional - /// will be empty - std::optional - fetchLedger(uint32_t ledgerSequence, bool getObjects); - - /// Setup all of the ETL sources and subscribe to the necessary streams - void - start(); - - void - stop(); - - /// Determine whether messages received on the transactions_proposed stream - /// should be forwarded to subscribing clients. The server subscribes to - /// transactions_proposed, validations, and manifests on multiple - /// ETLSources, yet only forwards messages from one source at any given time - /// (to avoid sending duplicate messages to clients). - /// @param in ETLSource in question - /// @return true if messages should be forwarded - bool - shouldPropagateStream(ETLSource* in) const - { - for (auto& src : sources_) - { - assert(src); - // We pick the first ETLSource encountered that is connected - if (src->isConnected()) - { - if (src.get() == in) - return true; - else - return false; - } - } - - // If no sources connected, then this stream has not been forwarded. - return true; - } - - Json::Value - toJson() const - { - Json::Value ret(Json::arrayValue); - for (auto& src : sources_) - { - ret.append(src->toJson()); - } - return ret; - } - - /// Randomly select a p2p node to forward a gRPC request to - /// @return gRPC stub to forward requests to p2p node - std::unique_ptr - getP2pForwardingStub() const; - - /// Forward a JSON RPC request to a randomly selected p2p node - /// @param context context of the request - /// @return response received from p2p node - Json::Value - forwardToP2p(RPC::JsonContext& context) const; - -private: - /// f is a function that takes an ETLSource as an argument and returns a - /// bool. Attempt to execute f for one randomly chosen ETLSource that has - /// the specified ledger. If f returns false, another randomly chosen - /// ETLSource is used. The process repeats until f returns true. - /// @param f function to execute. This function takes the ETL source as an - /// argument, and returns a bool. - /// @param ledgerSequence f is executed for each ETLSource that has this - /// ledger - /// @return true if f was eventually executed successfully. false if the - /// ledger was found in the database or the server is shutting down - template - bool - execute(Func f, uint32_t ledgerSequence); -}; - -} // namespace ripple -#endif diff --git a/src/xrpld/app/reporting/P2pProxy.cpp b/src/xrpld/app/reporting/P2pProxy.cpp deleted file mode 100644 index df699f4faf0..00000000000 --- a/src/xrpld/app/reporting/P2pProxy.cpp +++ /dev/null @@ -1,84 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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 -#include -#include -#include - -namespace ripple { - -Json::Value -forwardToP2p(RPC::JsonContext& context) -{ - return context.app.getReportingETL().getETLLoadBalancer().forwardToP2p( - context); -} - -std::unique_ptr -getP2pForwardingStub(RPC::Context& context) -{ - return context.app.getReportingETL() - .getETLLoadBalancer() - .getP2pForwardingStub(); -} - -// We only forward requests where ledger_index is "current" or "closed" -// otherwise, attempt to handle here -bool -shouldForwardToP2p(RPC::JsonContext& context) -{ - if (!context.app.config().reporting()) - return false; - - Json::Value& params = context.params; - std::string strCommand = params.isMember(jss::command) - ? params[jss::command].asString() - : params[jss::method].asString(); - - JLOG(context.j.trace()) << "COMMAND:" << strCommand; - JLOG(context.j.trace()) << "REQUEST:" << params; - auto handler = RPC::getHandler( - context.apiVersion, context.app.config().BETA_RPC_API, strCommand); - if (!handler) - { - JLOG(context.j.error()) - << "Error getting handler. command = " << strCommand; - return false; - } - - if (handler->condition_ == RPC::NEEDS_CURRENT_LEDGER || - handler->condition_ == RPC::NEEDS_CLOSED_LEDGER) - { - return true; - } - - if (params.isMember(jss::ledger_index)) - { - auto indexValue = params[jss::ledger_index]; - if (indexValue.isString()) - { - auto index = indexValue.asString(); - return index == "current" || index == "closed"; - } - } - return false; -} - -} // namespace ripple diff --git a/src/xrpld/app/reporting/P2pProxy.h b/src/xrpld/app/reporting/P2pProxy.h deleted file mode 100644 index d49389f42d3..00000000000 --- a/src/xrpld/app/reporting/P2pProxy.h +++ /dev/null @@ -1,113 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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_APP_REPORTING_P2PPROXY_H_INCLUDED -#define RIPPLE_APP_REPORTING_P2PPROXY_H_INCLUDED - -#include -#include -#include -#include - -#include -#include - -namespace ripple { -/// Forward a JSON request to a p2p node and return the response -/// @param context context of the request -/// @return response from p2p node -Json::Value -forwardToP2p(RPC::JsonContext& context); - -/// Whether a request should be forwarded, based on request parameters -/// @param context context of the request -/// @return true if should be forwarded -bool -shouldForwardToP2p(RPC::JsonContext& context); - -template -bool -needCurrentOrClosed(Request& request) -{ - // These are the only gRPC requests that specify a ledger - if constexpr ( - std::is_same::value || - std::is_same:: - value || - std::is_same::value) - { - if (request.ledger().ledger_case() == - org::xrpl::rpc::v1::LedgerSpecifier::LedgerCase::kShortcut) - { - if (request.ledger().shortcut() != - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED && - request.ledger().shortcut() != - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_UNSPECIFIED) - return true; - } - } - // GetLedgerDiff specifies two ledgers - else if constexpr (std::is_same< - Request, - org::xrpl::rpc::v1::GetLedgerDiffRequest>::value) - { - auto help = [](auto specifier) { - if (specifier.ledger_case() == - org::xrpl::rpc::v1::LedgerSpecifier::LedgerCase::kShortcut) - { - if (specifier.shortcut() != - org::xrpl::rpc::v1::LedgerSpecifier:: - SHORTCUT_VALIDATED && - specifier.shortcut() != - org::xrpl::rpc::v1::LedgerSpecifier:: - SHORTCUT_UNSPECIFIED) - return true; - } - return false; - }; - return help(request.base_ledger()) || help(request.desired_ledger()); - } - return false; -} - -/// Whether a request should be forwarded, based on request parameters -/// @param context context of the request -/// @condition required condition for the request -/// @return true if should be forwarded -template -bool -shouldForwardToP2p(RPC::GRPCContext& context, RPC::Condition condition) -{ - if (!context.app.config().reporting()) - return false; - if (condition == RPC::NEEDS_CURRENT_LEDGER || - condition == RPC::NEEDS_CLOSED_LEDGER) - return true; - - return needCurrentOrClosed(context.params); -} - -/// Get stub used to forward gRPC requests to a p2p node -/// @param context context of the request -/// @return stub to forward requests -std::unique_ptr -getP2pForwardingStub(RPC::Context& context); - -} // namespace ripple -#endif diff --git a/src/xrpld/app/reporting/README.md b/src/xrpld/app/reporting/README.md deleted file mode 100644 index f55b2d8d60d..00000000000 --- a/src/xrpld/app/reporting/README.md +++ /dev/null @@ -1,110 +0,0 @@ -# Reporting mode - -Reporting mode is a special operating mode of rippled, designed to handle RPCs -for validated data. A server running in reporting mode does not connect to the -p2p network, but rather extracts validated data from a node that is connected -to the p2p network. To run rippled in reporting mode, you must also run a -separate rippled node in p2p mode, to use as an ETL source. Multiple reporting -nodes can share access to the same network accessible databases (Postgres and -Cassandra); at any given time, only one reporting node will be performing ETL -and writing to the databases, while the others simply read from the databases. -A server running in reporting mode will forward any requests that require access -to the p2p network to a p2p node. - -# Reporting ETL -A single reporting node has one or more ETL sources, specified in the config -file. A reporting node will subscribe to the "ledgers" stream of each of the ETL -sources. This stream sends a message whenever a new ledger is validated. Upon -receiving a message on the stream, reporting will then fetch the data associated -with the newly validated ledger from one of the ETL sources. The fetch is -performed via a gRPC request ("GetLedger"). This request returns the ledger -header, transactions+metadata blobs, and every ledger object -added/modified/deleted as part of this ledger. ETL then writes all of this data -to the databases, and moves on to the next ledger. ETL does not apply -transactions, but rather extracts the already computed results of those -transactions (all of the added/modified/deleted SHAMap leaf nodes of the state -tree). The new SHAMap inner nodes are computed by the ETL writer; this computation mainly -involves manipulating child pointers and recomputing hashes, logic which is -buried inside of SHAMap. - -If the database is entirely empty, ETL must download an entire ledger in full -(as opposed to just the diff, as described above). This download is done via the -"GetLedgerData" gRPC request. "GetLedgerData" allows clients to page through an -entire ledger over several RPC calls. ETL will page through an entire ledger, -and write each object to the database. - -If the database is not empty, the reporting node will first come up in a "soft" -read-only mode. In read-only mode, the server does not perform ETL and simply -publishes new ledgers as they are written to the database. -If the database is not updated within a certain time period -(currently hard coded at 20 seconds), the reporting node will begin the ETL -process and start writing to the database. Postgres will report an error when -trying to write a record with a key that already exists. ETL uses this error to -determine that another process is writing to the database, and subsequently -falls back to a soft read-only mode. Reporting nodes can also operate in strict -read-only mode, in which case they will never write to the database. - -# Database Nuances -The database schema for reporting mode does not allow any history gaps. -Attempting to write a ledger to a non-empty database where the previous ledger -does not exist will return an error. - -The databases must be set up prior to running reporting mode. This requires -creating the Postgres database, and setting up the Cassandra keyspace. Reporting -mode will create the objects table in Cassandra if the table does not yet exist. - -Creating the Postgres database: -``` -$ psql -h [host] -U [user] -postgres=# create database [database]; -``` -Creating the keyspace: -``` -$ cqlsh [host] [port] -> CREATE KEYSPACE rippled WITH REPLICATION = - {'class' : 'SimpleStrategy', 'replication_factor' : 3 }; -``` -A replication factor of 3 is recommended. However, when running locally, only a -replication factor of 1 is supported. - -Online delete is not supported by reporting mode and must be done manually. The -easiest way to do this would be to setup a second Cassandra keyspace and -Postgres database, bring up a single reporting mode instance that uses those -databases, and start ETL at a ledger of your choosing (via --startReporting on -the command line). Once this node is caught up, the other databases can be -deleted. - -To delete: -``` -$ psql -h [host] -U [user] -d [database] -reporting=$ truncate table ledgers cascade; -``` -``` -$ cqlsh [host] [port] -> truncate table objects; -``` -# Proxy -RPCs that require access to the p2p network and/or the open ledger are forwarded -from the reporting node to one of the ETL sources. The request is not processed -prior to forwarding, and the response is delivered as-is to the client. -Reporting will forward any requests that always require p2p/open ledger access -(fee and submit, for instance). In addition, any request that explicitly -requests data from the open or closed ledger (via setting -"ledger_index":"current" or "ledger_index":"closed"), will be forwarded to a -p2p node. - -For the stream "transactions_proposed" (AKA "rt_transactions"), reporting -subscribes to the "transactions_proposed" streams of each ETL source, and then -forwards those messages to any clients subscribed to the same stream on the -reporting node. A reporting node will subscribe to the stream on each ETL -source, but will only forward the messages from one of the streams at any given -time (to avoid sending the same message more than once to the same client). - -# API changes -A reporting node defaults to only returning validated data. If a ledger is not -specified, the most recently validated ledger is used. This is in contrast to -the normal rippled behavior, where the open ledger is used by default. - -Reporting will reject all subscribe requests for streams "server", "manifests", -"validations", "peer_status" and "consensus". - diff --git a/src/xrpld/app/reporting/ReportingETL.cpp b/src/xrpld/app/reporting/ReportingETL.cpp deleted file mode 100644 index 2f6411b0808..00000000000 --- a/src/xrpld/app/reporting/ReportingETL.cpp +++ /dev/null @@ -1,960 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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 -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { - -namespace detail { -/// Convenience function for printing out basic ledger info -std::string -toString(LedgerInfo const& info) -{ - std::stringstream ss; - ss << "LedgerInfo { Sequence : " << info.seq - << " Hash : " << strHex(info.hash) << " TxHash : " << strHex(info.txHash) - << " AccountHash : " << strHex(info.accountHash) - << " ParentHash : " << strHex(info.parentHash) << " }"; - return ss.str(); -} -} // namespace detail - -void -ReportingETL::consumeLedgerData( - std::shared_ptr& ledger, - ThreadSafeQueue>& writeQueue) -{ - std::shared_ptr sle; - size_t num = 0; - while (!stopping_ && (sle = writeQueue.pop())) - { - assert(sle); - if (!ledger->exists(sle->key())) - ledger->rawInsert(sle); - - if (flushInterval_ != 0 && (num % flushInterval_) == 0) - { - JLOG(journal_.debug()) << "Flushing! key = " << strHex(sle->key()); - ledger->stateMap().flushDirty(hotACCOUNT_NODE); - } - ++num; - } -} - -std::vector -ReportingETL::insertTransactions( - std::shared_ptr& ledger, - org::xrpl::rpc::v1::GetLedgerResponse& data) -{ - std::vector accountTxData; - for (auto& txn : data.transactions_list().transactions()) - { - auto& raw = txn.transaction_blob(); - - SerialIter it{raw.data(), raw.size()}; - STTx sttx{it}; - - auto txSerializer = std::make_shared(sttx.getSerializer()); - - TxMeta txMeta{ - sttx.getTransactionID(), ledger->info().seq, txn.metadata_blob()}; - - auto metaSerializer = - std::make_shared(txMeta.getAsObject().getSerializer()); - - JLOG(journal_.trace()) - << __func__ << " : " - << "Inserting transaction = " << sttx.getTransactionID(); - uint256 nodestoreHash = ledger->rawTxInsertWithHash( - sttx.getTransactionID(), txSerializer, metaSerializer); - accountTxData.emplace_back(txMeta, std::move(nodestoreHash), journal_); - } - return accountTxData; -} - -std::shared_ptr -ReportingETL::loadInitialLedger(uint32_t startingSequence) -{ - // check that database is actually empty - auto ledger = std::const_pointer_cast( - app_.getLedgerMaster().getValidatedLedger()); - if (ledger) - { - JLOG(journal_.fatal()) << __func__ << " : " - << "Database is not empty"; - assert(false); - return {}; - } - - // fetch the ledger from the network. This function will not return until - // either the fetch is successful, or the server is being shutdown. This - // only fetches the ledger header and the transactions+metadata - std::optional ledgerData{ - fetchLedgerData(startingSequence)}; - if (!ledgerData) - return {}; - - LedgerInfo lgrInfo = - deserializeHeader(makeSlice(ledgerData->ledger_header()), true); - - JLOG(journal_.debug()) << __func__ << " : " - << "Deserialized ledger header. " - << detail::toString(lgrInfo); - - ledger = - std::make_shared(lgrInfo, app_.config(), app_.getNodeFamily()); - ledger->stateMap().clearSynching(); - ledger->txMap().clearSynching(); - -#ifdef RIPPLED_REPORTING - std::vector accountTxData = - insertTransactions(ledger, *ledgerData); -#endif - - auto start = std::chrono::system_clock::now(); - - ThreadSafeQueue> writeQueue; - std::thread asyncWriter{[this, &ledger, &writeQueue]() { - consumeLedgerData(ledger, writeQueue); - }}; - - // download the full account state map. This function downloads full ledger - // data and pushes the downloaded data into the writeQueue. asyncWriter - // consumes from the queue and inserts the data into the Ledger object. - // Once the below call returns, all data has been pushed into the queue - loadBalancer_.loadInitialLedger(startingSequence, writeQueue); - - // null is used to represent the end of the queue - std::shared_ptr null; - writeQueue.push(null); - // wait for the writer to finish - asyncWriter.join(); - - if (!stopping_) - { - flushLedger(ledger); - if (app_.config().reporting()) - { -#ifdef RIPPLED_REPORTING - dynamic_cast(&app_.getRelationalDatabase()) - ->writeLedgerAndTransactions(ledger->info(), accountTxData); -#endif - } - } - auto end = std::chrono::system_clock::now(); - JLOG(journal_.debug()) << "Time to download and store ledger = " - << ((end - start).count()) / 1000000000.0; - return ledger; -} - -void -ReportingETL::flushLedger(std::shared_ptr& ledger) -{ - JLOG(journal_.debug()) << __func__ << " : " - << "Flushing ledger. " - << detail::toString(ledger->info()); - // These are recomputed in setImmutable - auto& accountHash = ledger->info().accountHash; - auto& txHash = ledger->info().txHash; - auto& ledgerHash = ledger->info().hash; - - assert( - ledger->info().seq < XRP_LEDGER_EARLIEST_FEES || - ledger->read(keylet::fees())); - ledger->setImmutable(false); - auto start = std::chrono::system_clock::now(); - - auto numFlushed = ledger->stateMap().flushDirty(hotACCOUNT_NODE); - - auto numTxFlushed = ledger->txMap().flushDirty(hotTRANSACTION_NODE); - - { - Serializer s(128); - s.add32(HashPrefix::ledgerMaster); - addRaw(ledger->info(), s); - app_.getNodeStore().store( - hotLEDGER, - std::move(s.modData()), - ledger->info().hash, - ledger->info().seq); - } - - app_.getNodeStore().sync(); - - auto end = std::chrono::system_clock::now(); - - JLOG(journal_.debug()) << __func__ << " : " - << "Flushed " << numFlushed - << " nodes to nodestore from stateMap"; - JLOG(journal_.debug()) << __func__ << " : " - << "Flushed " << numTxFlushed - << " nodes to nodestore from txMap"; - - JLOG(journal_.debug()) << __func__ << " : " - << "Flush took " - << (end - start).count() / 1000000000.0 - << " seconds"; - - if (numFlushed == 0) - { - JLOG(journal_.fatal()) << __func__ << " : " - << "Flushed 0 nodes from state map"; - assert(false); - } - if (numTxFlushed == 0) - { - JLOG(journal_.warn()) << __func__ << " : " - << "Flushed 0 nodes from tx map"; - } - - // Make sure calculated hashes are correct - if (ledger->stateMap().getHash().as_uint256() != accountHash) - { - JLOG(journal_.fatal()) - << __func__ << " : " - << "State map hash does not match. " - << "Expected hash = " << strHex(accountHash) << "Actual hash = " - << strHex(ledger->stateMap().getHash().as_uint256()); - Throw("state map hash mismatch"); - } - - if (ledger->txMap().getHash().as_uint256() != txHash) - { - JLOG(journal_.fatal()) - << __func__ << " : " - << "Tx map hash does not match. " - << "Expected hash = " << strHex(txHash) << "Actual hash = " - << strHex(ledger->txMap().getHash().as_uint256()); - Throw("tx map hash mismatch"); - } - - if (ledger->info().hash != ledgerHash) - { - JLOG(journal_.fatal()) - << __func__ << " : " - << "Ledger hash does not match. " - << "Expected hash = " << strHex(ledgerHash) - << "Actual hash = " << strHex(ledger->info().hash); - Throw("ledger hash mismatch"); - } - - JLOG(journal_.info()) << __func__ << " : " - << "Successfully flushed ledger! " - << detail::toString(ledger->info()); -} - -void -ReportingETL::publishLedger(std::shared_ptr& ledger) -{ - app_.getOPs().pubLedger(ledger); - - setLastPublish(); -} - -bool -ReportingETL::publishLedger(uint32_t ledgerSequence, uint32_t maxAttempts) -{ - JLOG(journal_.info()) << __func__ << " : " - << "Attempting to publish ledger = " - << ledgerSequence; - size_t numAttempts = 0; - while (!stopping_) - { - auto ledger = app_.getLedgerMaster().getLedgerBySeq(ledgerSequence); - - if (!ledger) - { - JLOG(journal_.warn()) - << __func__ << " : " - << "Trying to publish. Could not find ledger with sequence = " - << ledgerSequence; - // We try maxAttempts times to publish the ledger, waiting one - // second in between each attempt. - // If the ledger is not present in the database after maxAttempts, - // we attempt to take over as the writer. If the takeover fails, - // doContinuousETL will return, and this node will go back to - // publishing. - // If the node is in strict read only mode, we simply - // skip publishing this ledger and return false indicating the - // publish failed - if (numAttempts >= maxAttempts) - { - JLOG(journal_.error()) << __func__ << " : " - << "Failed to publish ledger after " - << numAttempts << " attempts."; - if (!readOnly_) - { - JLOG(journal_.info()) << __func__ << " : " - << "Attempting to become ETL writer"; - return false; - } - else - { - JLOG(journal_.debug()) - << __func__ << " : " - << "In strict read-only mode. " - << "Skipping publishing this ledger. " - << "Beginning fast forward."; - return false; - } - } - else - { - std::this_thread::sleep_for(std::chrono::seconds(1)); - ++numAttempts; - } - continue; - } - - publishStrand_.post([this, ledger, fname = __func__]() { - app_.getOPs().pubLedger(ledger); - setLastPublish(); - JLOG(journal_.info()) - << fname << " : " - << "Published ledger. " << detail::toString(ledger->info()); - }); - return true; - } - return false; -} - -std::optional -ReportingETL::fetchLedgerData(uint32_t idx) -{ - JLOG(journal_.debug()) << __func__ << " : " - << "Attempting to fetch ledger with sequence = " - << idx; - - std::optional response = - loadBalancer_.fetchLedger(idx, false); - JLOG(journal_.trace()) << __func__ << " : " - << "GetLedger reply = " << response->DebugString(); - return response; -} - -std::optional -ReportingETL::fetchLedgerDataAndDiff(uint32_t idx) -{ - JLOG(journal_.debug()) << __func__ << " : " - << "Attempting to fetch ledger with sequence = " - << idx; - - std::optional response = - loadBalancer_.fetchLedger(idx, true); - JLOG(journal_.trace()) << __func__ << " : " - << "GetLedger reply = " << response->DebugString(); - return response; -} - -std::pair, std::vector> -ReportingETL::buildNextLedger( - std::shared_ptr& next, - org::xrpl::rpc::v1::GetLedgerResponse& rawData) -{ - JLOG(journal_.info()) << __func__ << " : " - << "Beginning ledger update"; - - LedgerInfo lgrInfo = - deserializeHeader(makeSlice(rawData.ledger_header()), true); - - JLOG(journal_.debug()) << __func__ << " : " - << "Deserialized ledger header. " - << detail::toString(lgrInfo); - - next->setLedgerInfo(lgrInfo); - - next->stateMap().clearSynching(); - next->txMap().clearSynching(); - - std::vector accountTxData{ - insertTransactions(next, rawData)}; - - JLOG(journal_.debug()) - << __func__ << " : " - << "Inserted all transactions. Number of transactions = " - << rawData.transactions_list().transactions_size(); - - for (auto& obj : rawData.ledger_objects().objects()) - { - auto key = uint256::fromVoidChecked(obj.key()); - if (!key) - throw std::runtime_error("Recevied malformed object ID"); - - auto& data = obj.data(); - - // indicates object was deleted - if (data.size() == 0) - { - JLOG(journal_.trace()) << __func__ << " : " - << "Erasing object = " << *key; - if (next->exists(*key)) - next->rawErase(*key); - } - else - { - SerialIter it{data.data(), data.size()}; - std::shared_ptr sle = std::make_shared(it, *key); - - if (next->exists(*key)) - { - JLOG(journal_.trace()) << __func__ << " : " - << "Replacing object = " << *key; - next->rawReplace(sle); - } - else - { - JLOG(journal_.trace()) << __func__ << " : " - << "Inserting object = " << *key; - next->rawInsert(sle); - } - } - } - JLOG(journal_.debug()) - << __func__ << " : " - << "Inserted/modified/deleted all objects. Number of objects = " - << rawData.ledger_objects().objects_size(); - - if (!rawData.skiplist_included()) - { - next->updateSkipList(); - JLOG(journal_.warn()) - << __func__ << " : " - << "tx process is not sending skiplist. This indicates that the tx " - "process is parsing metadata instead of doing a SHAMap diff. " - "Make sure tx process is running the same code as reporting to " - "use SHAMap diff instead of parsing metadata"; - } - - JLOG(journal_.debug()) << __func__ << " : " - << "Finished ledger update. " - << detail::toString(next->info()); - return {std::move(next), std::move(accountTxData)}; -} - -// Database must be populated when this starts -std::optional -ReportingETL::runETLPipeline(uint32_t startSequence) -{ - /* - * Behold, mortals! This function spawns three separate threads, which talk - * to each other via 2 different thread safe queues and 1 atomic variable. - * All threads and queues are function local. This function returns when all - * of the threads exit. There are two termination conditions: the first is - * if the load thread encounters a write conflict. In this case, the load - * thread sets writeConflict, an atomic bool, to true, which signals the - * other threads to stop. The second termination condition is when the - * entire server is shutting down, which is detected in one of three ways: - * 1. isStopping() returns true if the server is shutting down - * 2. networkValidatedLedgers_.waitUntilValidatedByNetwork returns - * false, signaling the wait was aborted. - * 3. fetchLedgerDataAndDiff returns an empty optional, signaling the fetch - * was aborted. - * In all cases, the extract thread detects this condition, - * and pushes an empty optional onto the transform queue. The transform - * thread, upon popping an empty optional, pushes an empty optional onto the - * load queue, and then returns. The load thread, upon popping an empty - * optional, returns. - */ - - JLOG(journal_.debug()) << __func__ << " : " - << "Starting etl pipeline"; - writing_ = true; - - std::shared_ptr parent = std::const_pointer_cast( - app_.getLedgerMaster().getLedgerBySeq(startSequence - 1)); - if (!parent) - { - assert(false); - Throw("runETLPipeline: parent ledger is null"); - } - - std::atomic_bool writeConflict = false; - std::optional lastPublishedSequence; - constexpr uint32_t maxQueueSize = 1000; - - ThreadSafeQueue> - transformQueue{maxQueueSize}; - - std::thread extracter{[this, - &startSequence, - &writeConflict, - &transformQueue]() { - beast::setCurrentThreadName("rippled: ReportingETL extract"); - uint32_t currentSequence = startSequence; - - // there are two stopping conditions here. - // First, if there is a write conflict in the load thread, the ETL - // mechanism should stop. - // The other stopping condition is if the entire server is shutting - // down. This can be detected in a variety of ways. See the comment - // at the top of the function - while (networkValidatedLedgers_.waitUntilValidatedByNetwork( - currentSequence) && - !writeConflict && !isStopping()) - { - auto start = std::chrono::system_clock::now(); - std::optional fetchResponse{ - fetchLedgerDataAndDiff(currentSequence)}; - // if the fetch is unsuccessful, stop. fetchLedger only returns - // false if the server is shutting down, or if the ledger was - // found in the database (which means another process already - // wrote the ledger that this process was trying to extract; - // this is a form of a write conflict). Otherwise, - // fetchLedgerDataAndDiff will keep trying to fetch the - // specified ledger until successful - if (!fetchResponse) - { - break; - } - auto end = std::chrono::system_clock::now(); - - auto time = ((end - start).count()) / 1000000000.0; - auto tps = - fetchResponse->transactions_list().transactions_size() / time; - - JLOG(journal_.debug()) << "Extract phase time = " << time - << " . Extract phase tps = " << tps; - - transformQueue.push(std::move(fetchResponse)); - ++currentSequence; - } - // empty optional tells the transformer to shut down - transformQueue.push({}); - }}; - - ThreadSafeQueue, - std::vector>>> - loadQueue{maxQueueSize}; - std::thread transformer{[this, - &parent, - &writeConflict, - &loadQueue, - &transformQueue]() { - beast::setCurrentThreadName("rippled: ReportingETL transform"); - - assert(parent); - parent = std::make_shared(*parent, NetClock::time_point{}); - while (!writeConflict) - { - std::optional fetchResponse{ - transformQueue.pop()}; - // if fetchResponse is an empty optional, the extracter thread has - // stopped and the transformer should stop as well - if (!fetchResponse) - { - break; - } - if (isStopping()) - continue; - - auto start = std::chrono::system_clock::now(); - auto [next, accountTxData] = - buildNextLedger(parent, *fetchResponse); - auto end = std::chrono::system_clock::now(); - - auto duration = ((end - start).count()) / 1000000000.0; - JLOG(journal_.debug()) << "transform time = " << duration; - // The below line needs to execute before pushing to the queue, in - // order to prevent this thread and the loader thread from accessing - // the same SHAMap concurrently - parent = std::make_shared(*next, NetClock::time_point{}); - loadQueue.push( - std::make_pair(std::move(next), std::move(accountTxData))); - } - // empty optional tells the loader to shutdown - loadQueue.push({}); - }}; - - std::thread loader{[this, - &lastPublishedSequence, - &loadQueue, - &writeConflict]() { - beast::setCurrentThreadName("rippled: ReportingETL load"); - size_t totalTransactions = 0; - double totalTime = 0; - while (!writeConflict) - { - std::optional, - std::vector>> - result{loadQueue.pop()}; - // if result is an empty optional, the transformer thread has - // stopped and the loader should stop as well - if (!result) - break; - if (isStopping()) - continue; - - auto& ledger = result->first; - auto& accountTxData = result->second; - - auto start = std::chrono::system_clock::now(); - // write to the key-value store - flushLedger(ledger); - - auto mid = std::chrono::system_clock::now(); - // write to RDBMS - // if there is a write conflict, some other process has already - // written this ledger and has taken over as the ETL writer -#ifdef RIPPLED_REPORTING - if (!dynamic_cast(&app_.getRelationalDatabase()) - ->writeLedgerAndTransactions( - ledger->info(), accountTxData)) - writeConflict = true; -#endif - auto end = std::chrono::system_clock::now(); - - if (!writeConflict) - { - publishLedger(ledger); - lastPublishedSequence = ledger->info().seq; - } - // print some performance numbers - auto kvTime = ((mid - start).count()) / 1000000000.0; - auto relationalTime = ((end - mid).count()) / 1000000000.0; - - size_t numTxns = accountTxData.size(); - totalTime += kvTime; - totalTransactions += numTxns; - JLOG(journal_.info()) - << "Load phase of etl : " - << "Successfully published ledger! Ledger info: " - << detail::toString(ledger->info()) - << ". txn count = " << numTxns - << ". key-value write time = " << kvTime - << ". relational write time = " << relationalTime - << ". key-value tps = " << numTxns / kvTime - << ". relational tps = " << numTxns / relationalTime - << ". total key-value tps = " << totalTransactions / totalTime; - } - }}; - - // wait for all of the threads to stop - loader.join(); - extracter.join(); - transformer.join(); - writing_ = false; - - JLOG(journal_.debug()) << __func__ << " : " - << "Stopping etl pipeline"; - - return lastPublishedSequence; -} - -// main loop. The software begins monitoring the ledgers that are validated -// by the nework. The member networkValidatedLedgers_ keeps track of the -// sequences of ledgers validated by the network. Whenever a ledger is validated -// by the network, the software looks for that ledger in the database. Once the -// ledger is found in the database, the software publishes that ledger to the -// ledgers stream. If a network validated ledger is not found in the database -// after a certain amount of time, then the software attempts to take over -// responsibility of the ETL process, where it writes new ledgers to the -// database. The software will relinquish control of the ETL process if it -// detects that another process has taken over ETL. -void -ReportingETL::monitor() -{ - auto ledger = std::const_pointer_cast( - app_.getLedgerMaster().getValidatedLedger()); - if (!ledger) - { - JLOG(journal_.info()) << __func__ << " : " - << "Database is empty. Will download a ledger " - "from the network."; - if (startSequence_) - { - JLOG(journal_.info()) - << __func__ << " : " - << "ledger sequence specified in config. " - << "Will begin ETL process starting with ledger " - << *startSequence_; - ledger = loadInitialLedger(*startSequence_); - } - else - { - JLOG(journal_.info()) - << __func__ << " : " - << "Waiting for next ledger to be validated by network..."; - std::optional mostRecentValidated = - networkValidatedLedgers_.getMostRecent(); - if (mostRecentValidated) - { - JLOG(journal_.info()) << __func__ << " : " - << "Ledger " << *mostRecentValidated - << " has been validated. " - << "Downloading..."; - ledger = loadInitialLedger(*mostRecentValidated); - } - else - { - JLOG(journal_.info()) << __func__ << " : " - << "The wait for the next validated " - << "ledger has been aborted. " - << "Exiting monitor loop"; - return; - } - } - } - else - { - if (startSequence_) - { - Throw( - "start sequence specified but db is already populated"); - } - JLOG(journal_.info()) - << __func__ << " : " - << "Database already populated. Picking up from the tip of history"; - } - if (!ledger) - { - JLOG(journal_.error()) - << __func__ << " : " - << "Failed to load initial ledger. Exiting monitor loop"; - return; - } - else - { - publishLedger(ledger); - } - uint32_t nextSequence = ledger->info().seq + 1; - - JLOG(journal_.debug()) << __func__ << " : " - << "Database is populated. " - << "Starting monitor loop. sequence = " - << nextSequence; - while (!stopping_ && - networkValidatedLedgers_.waitUntilValidatedByNetwork(nextSequence)) - { - JLOG(journal_.info()) << __func__ << " : " - << "Ledger with sequence = " << nextSequence - << " has been validated by the network. " - << "Attempting to find in database and publish"; - // Attempt to take over responsibility of ETL writer after 10 failed - // attempts to publish the ledger. publishLedger() fails if the - // ledger that has been validated by the network is not found in the - // database after the specified number of attempts. publishLedger() - // waits one second between each attempt to read the ledger from the - // database - // - // In strict read-only mode, when the software fails to find a - // ledger in the database that has been validated by the network, - // the software will only try to publish subsequent ledgers once, - // until one of those ledgers is found in the database. Once the - // software successfully publishes a ledger, the software will fall - // back to the normal behavior of trying several times to publish - // the ledger that has been validated by the network. In this - // manner, a reporting processing running in read-only mode does not - // need to restart if the database is wiped. - constexpr size_t timeoutSeconds = 10; - bool success = publishLedger(nextSequence, timeoutSeconds); - if (!success) - { - JLOG(journal_.warn()) - << __func__ << " : " - << "Failed to publish ledger with sequence = " << nextSequence - << " . Beginning ETL"; - // doContinousETLPipelined returns the most recent sequence - // published empty optional if no sequence was published - std::optional lastPublished = - runETLPipeline(nextSequence); - JLOG(journal_.info()) << __func__ << " : " - << "Aborting ETL. Falling back to publishing"; - // if no ledger was published, don't increment nextSequence - if (lastPublished) - nextSequence = *lastPublished + 1; - } - else - { - ++nextSequence; - } - } -} - -void -ReportingETL::monitorReadOnly() -{ - JLOG(journal_.debug()) << "Starting reporting in strict read only mode"; - std::optional mostRecent = - networkValidatedLedgers_.getMostRecent(); - if (!mostRecent) - return; - uint32_t sequence = *mostRecent; - bool success = true; - while (!stopping_ && - networkValidatedLedgers_.waitUntilValidatedByNetwork(sequence)) - { - success = publishLedger(sequence, success ? 30 : 1); - ++sequence; - } -} - -void -ReportingETL::doWork() -{ - worker_ = std::thread([this]() { - beast::setCurrentThreadName("rippled: ReportingETL worker"); - if (readOnly_) - monitorReadOnly(); - else - monitor(); - }); -} - -ReportingETL::ReportingETL(Application& app) - : app_(app) - , journal_(app.journal("ReportingETL")) - , publishStrand_(app_.getIOService()) - , loadBalancer_(*this) -{ - // if present, get endpoint from config - if (app_.config().exists("reporting")) - { -#ifndef RIPPLED_REPORTING - Throw( - "Config file specifies reporting, but software was not built with " - "-Dreporting=1. To use reporting, configure CMake with " - "-Dreporting=1"); -#endif - if (!app_.config().useTxTables()) - Throw( - "Reporting requires tx tables. Set use_tx_tables=1 in config " - "file, under [ledger_tx_tables] section"); - Section section = app_.config().section("reporting"); - - JLOG(journal_.debug()) << "Parsing config info"; - - auto& vals = section.values(); - for (auto& v : vals) - { - JLOG(journal_.debug()) << "val is " << v; - Section source = app_.config().section(v); - - auto optIp = source.get("source_ip"); - if (!optIp) - continue; - - auto optWsPort = source.get("source_ws_port"); - if (!optWsPort) - continue; - - auto optGrpcPort = source.get("source_grpc_port"); - if (!optGrpcPort) - { - // add source without grpc port - // used in read-only mode to detect when new ledgers have - // been validated. Used for publishing - if (app_.config().reportingReadOnly()) - loadBalancer_.add(*optIp, *optWsPort); - continue; - } - - loadBalancer_.add(*optIp, *optWsPort, *optGrpcPort); - } - - // this is true iff --reportingReadOnly was passed via command line - readOnly_ = app_.config().reportingReadOnly(); - - // if --reportingReadOnly was not passed via command line, check config - // file. Command line takes precedence - if (!readOnly_) - { - auto const optRO = section.get("read_only"); - if (optRO) - { - readOnly_ = (*optRO == "true" || *optRO == "1"); - app_.config().setReportingReadOnly(readOnly_); - } - } - - // lambda throws a useful message if string to integer conversion fails - auto asciiToIntThrows = - [](auto& dest, std::string const& src, char const* onError) { - char const* const srcEnd = src.data() + src.size(); - auto [ptr, err] = std::from_chars(src.data(), srcEnd, dest); - - if (err == std::errc()) - // skip whitespace at end of string - while (ptr != srcEnd && - std::isspace(static_cast(*ptr))) - ++ptr; - - // throw if - // o conversion error or - // o entire string is not consumed - if (err != std::errc() || ptr != srcEnd) - Throw(onError + src); - }; - - // handle command line arguments - if (app_.config().START_UP == Config::StartUpType::FRESH && !readOnly_) - { - asciiToIntThrows( - *startSequence_, - app_.config().START_LEDGER, - "Expected integral START_LEDGER command line argument. Got: "); - } - // if not passed via command line, check config for start sequence - if (!startSequence_) - { - auto const optStartSeq = section.get("start_sequence"); - if (optStartSeq) - { - // set a value so we can dereference - startSequence_ = 0; - asciiToIntThrows( - *startSequence_, - *optStartSeq, - "Expected integral start_sequence config entry. Got: "); - } - } - - auto const optFlushInterval = section.get("flush_interval"); - if (optFlushInterval) - asciiToIntThrows( - flushInterval_, - *optFlushInterval, - "Expected integral flush_interval config entry. Got: "); - - auto const optNumMarkers = section.get("num_markers"); - if (optNumMarkers) - asciiToIntThrows( - numMarkers_, - *optNumMarkers, - "Expected integral num_markers config entry. Got: "); - } -} - -} // namespace ripple diff --git a/src/xrpld/app/reporting/ReportingETL.h b/src/xrpld/app/reporting/ReportingETL.h deleted file mode 100644 index fc15f90b43b..00000000000 --- a/src/xrpld/app/reporting/ReportingETL.h +++ /dev/null @@ -1,367 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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_APP_REPORTING_REPORTINGETL_H_INCLUDED -#define RIPPLE_APP_REPORTING_REPORTINGETL_H_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -namespace ripple { - -using AccountTransactionsData = RelationalDatabase::AccountTransactionsData; - -/** - * This class is responsible for continuously extracting data from a - * p2p node, and writing that data to the databases. Usually, multiple different - * processes share access to the same network accessible databases, in which - * case only one such process is performing ETL and writing to the database. The - * other processes simply monitor the database for new ledgers, and publish - * those ledgers to the various subscription streams. If a monitoring process - * determines that the ETL writer has failed (no new ledgers written for some - * time), the process will attempt to become the ETL writer. If there are - * multiple monitoring processes that try to become the ETL writer at the same - * time, one will win out, and the others will fall back to - * monitoring/publishing. In this sense, this class dynamically transitions from - * monitoring to writing and from writing to monitoring, based on the activity - * of other processes running on different machines. - */ -class ReportingETL -{ -private: - Application& app_; - - beast::Journal journal_; - - std::thread worker_; - - /// Strand to ensure that ledgers are published in order. - /// If ETL is started far behind the network, ledgers will be written and - /// published very rapidly. Monitoring processes will publish ledgers as - /// they are written. However, to publish a ledger, the monitoring process - /// needs to read all of the transactions for that ledger from the database. - /// Reading the transactions from the database requires network calls, which - /// can be slow. It is imperative however that the monitoring processes keep - /// up with the writer, else the monitoring processes will not be able to - /// detect if the writer failed. Therefore, publishing each ledger (which - /// includes reading all of the transactions from the database) is done from - /// the application wide asio io_service, and a strand is used to ensure - /// ledgers are published in order - boost::asio::io_context::strand publishStrand_; - - /// Mechanism for communicating with ETL sources. ETLLoadBalancer wraps an - /// arbitrary number of ETL sources and load balances ETL requests across - /// those sources. - ETLLoadBalancer loadBalancer_; - - /// Mechanism for detecting when the network has validated a new ledger. - /// This class provides a way to wait for a specific ledger to be validated - NetworkValidatedLedgers networkValidatedLedgers_; - - /// Whether the software is stopping - std::atomic_bool stopping_ = false; - - /// Used to determine when to write to the database during the initial - /// ledger download. By default, the software downloads an entire ledger and - /// then writes to the database. If flushInterval_ is non-zero, the software - /// will write to the database as new ledger data (SHAMap leaf nodes) - /// arrives. It is not neccesarily more effient to write the data as it - /// arrives, as different SHAMap leaf nodes share the same SHAMap inner - /// nodes; flushing prematurely can result in the same SHAMap inner node - /// being written to the database more than once. It is recommended to use - /// the default value of 0 for this variable; however, different values can - /// be experimented with if better performance is desired. - size_t flushInterval_ = 0; - - /// This variable controls the number of GetLedgerData calls that will be - /// executed in parallel during the initial ledger download. GetLedgerData - /// allows clients to page through a ledger over many RPC calls. - /// GetLedgerData returns a marker that is used as an offset in a subsequent - /// call. If numMarkers_ is greater than 1, there will be multiple chains of - /// GetLedgerData calls iterating over different parts of the same ledger in - /// parallel. This can dramatically speed up the time to download the - /// initial ledger. However, a higher value for this member variable puts - /// more load on the ETL source. - size_t numMarkers_ = 2; - - /// Whether the process is in strict read-only mode. In strict read-only - /// mode, the process will never attempt to become the ETL writer, and will - /// only publish ledgers as they are written to the database. - bool readOnly_ = false; - - /// Whether the process is writing to the database. Used by server_info - std::atomic_bool writing_ = false; - - /// Ledger sequence to start ETL from. If this is empty, ETL will start from - /// the next ledger validated by the network. If this is set, and the - /// database is already populated, an error is thrown. - std::optional startSequence_; - - /// The time that the most recently published ledger was published. Used by - /// server_info - std::chrono::time_point lastPublish_; - - std::mutex publishTimeMtx_; - - std::chrono::time_point - getLastPublish() - { - std::unique_lock lck(publishTimeMtx_); - return lastPublish_; - } - - void - setLastPublish() - { - std::unique_lock lck(publishTimeMtx_); - lastPublish_ = std::chrono::system_clock::now(); - } - - /// Download a ledger with specified sequence in full, via GetLedgerData, - /// and write the data to the databases. This takes several minutes or - /// longer. - /// @param sequence the sequence of the ledger to download - /// @return The ledger downloaded, with a full transaction and account state - /// map - std::shared_ptr - loadInitialLedger(uint32_t sequence); - - /// Run ETL. Extracts ledgers and writes them to the database, until a write - /// conflict occurs (or the server shuts down). - /// @note database must already be populated when this function is called - /// @param startSequence the first ledger to extract - /// @return the last ledger written to the database, if any - std::optional - runETLPipeline(uint32_t startSequence); - - /// Monitor the network for newly validated ledgers. Also monitor the - /// database to see if any process is writing those ledgers. This function - /// is called when the application starts, and will only return when the - /// application is shutting down. If the software detects the database is - /// empty, this function will call loadInitialLedger(). If the software - /// detects ledgers are not being written, this function calls - /// runETLPipeline(). Otherwise, this function publishes ledgers as they are - /// written to the database. - void - monitor(); - - /// Monitor the database for newly written ledgers. - /// Similar to the monitor(), except this function will never call - /// runETLPipeline() or loadInitialLedger(). This function only publishes - /// ledgers as they are written to the database. - void - monitorReadOnly(); - - /// Extract data for a particular ledger from an ETL source. This function - /// continously tries to extract the specified ledger (using all available - /// ETL sources) until the extraction succeeds, or the server shuts down. - /// @param sequence sequence of the ledger to extract - /// @return ledger header and transaction+metadata blobs. Empty optional - /// if the server is shutting down - std::optional - fetchLedgerData(uint32_t sequence); - - /// Extract data for a particular ledger from an ETL source. This function - /// continously tries to extract the specified ledger (using all available - /// ETL sources) until the extraction succeeds, or the server shuts down. - /// @param sequence sequence of the ledger to extract - /// @return ledger header, transaction+metadata blobs, and all ledger - /// objects created, modified or deleted between this ledger and the parent. - /// Empty optional if the server is shutting down - std::optional - fetchLedgerDataAndDiff(uint32_t sequence); - - /// Insert all of the extracted transactions into the ledger - /// @param ledger ledger to insert transactions into - /// @param data data extracted from an ETL source - /// @return struct that contains the neccessary info to write to the - /// transctions and account_transactions tables in Postgres (mostly - /// transaction hashes, corresponding nodestore hashes and affected - /// accounts) - std::vector - insertTransactions( - std::shared_ptr& ledger, - org::xrpl::rpc::v1::GetLedgerResponse& data); - - /// Build the next ledger using the previous ledger and the extracted data. - /// This function calls insertTransactions() - /// @note rawData should be data that corresponds to the ledger immediately - /// following parent - /// @param parent the previous ledger - /// @param rawData data extracted from an ETL source - /// @return the newly built ledger and data to write to Postgres - std::pair, std::vector> - buildNextLedger( - std::shared_ptr& parent, - org::xrpl::rpc::v1::GetLedgerResponse& rawData); - - /// Write all new data to the key-value store - /// @param ledger ledger with new data to write - void - flushLedger(std::shared_ptr& ledger); - - /// Attempt to read the specified ledger from the database, and then publish - /// that ledger to the ledgers stream. - /// @param ledgerSequence the sequence of the ledger to publish - /// @param maxAttempts the number of times to attempt to read the ledger - /// from the database. 1 attempt per second - /// @return whether the ledger was found in the database and published - bool - publishLedger(uint32_t ledgerSequence, uint32_t maxAttempts = 10); - - /// Publish the passed in ledger - /// @param ledger the ledger to publish - void - publishLedger(std::shared_ptr& ledger); - - /// Consume data from a queue and insert that data into the ledger - /// This function will continue to pull from the queue until the queue - /// returns nullptr. This is used during the initial ledger download - /// @param ledger the ledger to insert data into - /// @param writeQueue the queue with extracted data - void - consumeLedgerData( - std::shared_ptr& ledger, - ThreadSafeQueue>& writeQueue); - -public: - explicit ReportingETL(Application& app); - - ~ReportingETL() - { - } - - NetworkValidatedLedgers& - getNetworkValidatedLedgers() - { - return networkValidatedLedgers_; - } - - bool - isStopping() const - { - return stopping_; - } - - /// Get the number of markers to use during the initial ledger download. - /// This is equivelent to the degree of parallelism during the initial - /// ledger download - /// @return the number of markers - uint32_t - getNumMarkers() - { - return numMarkers_; - } - - Application& - getApplication() - { - return app_; - } - - beast::Journal& - getJournal() - { - return journal_; - } - - Json::Value - getInfo() - { - Json::Value result(Json::objectValue); - - result["etl_sources"] = loadBalancer_.toJson(); - result["is_writer"] = writing_.load(); - auto last = getLastPublish(); - if (last.time_since_epoch().count() != 0) - result["last_publish_time"] = - to_string(std::chrono::floor( - getLastPublish())); - return result; - } - - /// start all of the necessary components and begin ETL - void - start() - { - JLOG(journal_.info()) << "Starting reporting etl"; - assert(app_.config().reporting()); - assert(app_.config().standalone()); - assert(app_.config().reportingReadOnly() == readOnly_); - - stopping_ = false; - - loadBalancer_.start(); - doWork(); - } - - void - stop() - { - JLOG(journal_.info()) << "onStop called"; - JLOG(journal_.debug()) << "Stopping Reporting ETL"; - stopping_ = true; - networkValidatedLedgers_.stop(); - loadBalancer_.stop(); - - JLOG(journal_.debug()) << "Stopped loadBalancer"; - if (worker_.joinable()) - worker_.join(); - - JLOG(journal_.debug()) << "Joined worker thread"; - } - - ETLLoadBalancer& - getETLLoadBalancer() - { - return loadBalancer_; - } - -private: - void - doWork(); -}; - -} // namespace ripple -#endif diff --git a/src/xrpld/core/Config.h b/src/xrpld/core/Config.h index e63e6d2f356..2d8340e0747 100644 --- a/src/xrpld/core/Config.h +++ b/src/xrpld/core/Config.h @@ -127,10 +127,6 @@ class Config : public BasicConfig */ bool RUN_STANDALONE = false; - bool RUN_REPORTING = false; - - bool REPORTING_READ_ONLY = false; - bool USE_TX_TABLES = true; /** Determines if the server will sign a tx, given an account's secret seed. @@ -347,11 +343,6 @@ class Config : public BasicConfig { return RUN_STANDALONE; } - bool - reporting() const - { - return RUN_REPORTING; - } bool useTxTables() const @@ -359,18 +350,6 @@ class Config : public BasicConfig return USE_TX_TABLES; } - bool - reportingReadOnly() const - { - return REPORTING_READ_ONLY; - } - - void - setReportingReadOnly(bool b) - { - REPORTING_READ_ONLY = b; - } - bool canSign() const { diff --git a/src/xrpld/core/DatabaseCon.h b/src/xrpld/core/DatabaseCon.h index d2f6b0a4f05..0ded37b1739 100644 --- a/src/xrpld/core/DatabaseCon.h +++ b/src/xrpld/core/DatabaseCon.h @@ -87,7 +87,6 @@ class DatabaseCon Config::StartUpType startUp = Config::NORMAL; bool standAlone = false; - bool reporting = false; boost::filesystem::path dataDir; // Indicates whether or not to return the `globalPragma` // from commonPragma() @@ -118,8 +117,7 @@ class DatabaseCon std::array const& initSQL) // Use temporary files or regular DB files? : DatabaseCon( - setup.standAlone && !setup.reporting && - setup.startUp != Config::LOAD && + setup.standAlone && setup.startUp != Config::LOAD && setup.startUp != Config::LOAD_FILE && setup.startUp != Config::REPLAY ? "" diff --git a/src/xrpld/core/Pg.cpp b/src/xrpld/core/Pg.cpp deleted file mode 100644 index 829e17658c1..00000000000 --- a/src/xrpld/core/Pg.cpp +++ /dev/null @@ -1,1415 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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. -*/ -//============================================================================== - -#ifdef RIPPLED_REPORTING -// Need raw socket manipulation to determine if postgres socket IPv4 or 6. -#if defined(_WIN32) -#include -#include -#else -#include -#include -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { - -static void -noticeReceiver(void* arg, PGresult const* res) -{ - beast::Journal& j = *static_cast(arg); - JLOG(j.info()) << "server message: " << PQresultErrorMessage(res); -} - -//----------------------------------------------------------------------------- - -std::string -PgResult::msg() const -{ - if (error_.has_value()) - { - std::stringstream ss; - ss << error_->first << ": " << error_->second; - return ss.str(); - } - if (result_) - return "ok"; - - // Must be stopping. - return "stopping"; -} - -//----------------------------------------------------------------------------- - -/* - Connecting described in: - https://www.postgresql.org/docs/10/libpq-connect.html - */ -void -Pg::connect() -{ - if (conn_) - { - // Nothing to do if we already have a good connection. - if (PQstatus(conn_.get()) == CONNECTION_OK) - return; - /* Try resetting connection. */ - PQreset(conn_.get()); - } - else // Make new connection. - { - conn_.reset(PQconnectdbParams( - reinterpret_cast(&config_.keywordsIdx[0]), - reinterpret_cast(&config_.valuesIdx[0]), - 0)); - if (!conn_) - Throw("No db connection struct"); - } - - /** Results from a synchronous connection attempt can only be either - * CONNECTION_OK or CONNECTION_BAD. */ - if (PQstatus(conn_.get()) == CONNECTION_BAD) - { - std::stringstream ss; - ss << "DB connection status " << PQstatus(conn_.get()) << ": " - << PQerrorMessage(conn_.get()); - Throw(ss.str()); - } - - // Log server session console messages. - PQsetNoticeReceiver( - conn_.get(), noticeReceiver, const_cast(&j_)); -} - -PgResult -Pg::query(char const* command, std::size_t nParams, char const* const* values) -{ - // The result object must be freed using the libpq API PQclear() call. - pg_result_type ret{nullptr, [](PGresult* result) { PQclear(result); }}; - // Connect then submit query. - while (true) - { - { - std::lock_guard lock(mutex_); - if (stop_) - return PgResult(); - } - try - { - connect(); - if (nParams) - { - // PQexecParams can process only a single command. - ret.reset(PQexecParams( - conn_.get(), - command, - nParams, - nullptr, - values, - nullptr, - nullptr, - 0)); - } - else - { - // PQexec can process multiple commands separated by - // semi-colons. Returns the response from the last - // command processed. - ret.reset(PQexec(conn_.get(), command)); - } - if (!ret) - Throw("no result structure returned"); - break; - } - catch (std::exception const& e) - { - // Sever connection and retry until successful. - disconnect(); - JLOG(j_.error()) << "database error, retrying: " << e.what(); - std::this_thread::sleep_for(std::chrono::seconds(1)); - } - } - - // Ensure proper query execution. - switch (PQresultStatus(ret.get())) - { - case PGRES_TUPLES_OK: - case PGRES_COMMAND_OK: - case PGRES_COPY_IN: - case PGRES_COPY_OUT: - case PGRES_COPY_BOTH: - break; - default: { - std::stringstream ss; - ss << "bad query result: " << PQresStatus(PQresultStatus(ret.get())) - << " error message: " << PQerrorMessage(conn_.get()) - << ", number of tuples: " << PQntuples(ret.get()) - << ", number of fields: " << PQnfields(ret.get()); - JLOG(j_.error()) << ss.str(); - PgResult retRes(ret.get(), conn_.get()); - disconnect(); - return retRes; - } - } - - return PgResult(std::move(ret)); -} - -static pg_formatted_params -formatParams(pg_params const& dbParams, beast::Journal const& j) -{ - std::vector> const& values = dbParams.second; - /* Convert vector to C-style array of C-strings for postgres API. - std::nullopt is a proxy for NULL since an empty std::string is - 0 length but not NULL. */ - std::vector valuesIdx; - valuesIdx.reserve(values.size()); - std::stringstream ss; - bool first = true; - for (auto const& value : values) - { - if (value) - { - valuesIdx.push_back(value->c_str()); - ss << value->c_str(); - } - else - { - valuesIdx.push_back(nullptr); - ss << "(null)"; - } - if (first) - first = false; - else - ss << ','; - } - - JLOG(j.trace()) << "query: " << dbParams.first << ". params: " << ss.str(); - return valuesIdx; -} - -PgResult -Pg::query(pg_params const& dbParams) -{ - char const* const& command = dbParams.first; - auto const formattedParams = formatParams(dbParams, j_); - return query( - command, - formattedParams.size(), - formattedParams.size() - ? reinterpret_cast(&formattedParams[0]) - : nullptr); -} - -void -Pg::bulkInsert(char const* table, std::string const& records) -{ - // https://www.postgresql.org/docs/12/libpq-copy.html#LIBPQ-COPY-SEND - assert(conn_.get()); - static auto copyCmd = boost::format(R"(COPY %s FROM stdin)"); - auto res = query(boost::str(copyCmd % table).c_str()); - if (!res || res.status() != PGRES_COPY_IN) - { - std::stringstream ss; - ss << "bulkInsert to " << table - << ". Postgres insert error: " << res.msg(); - if (res) - ss << ". Query status not PGRES_COPY_IN: " << res.status(); - Throw(ss.str()); - } - - if (PQputCopyData(conn_.get(), records.c_str(), records.size()) == -1) - { - std::stringstream ss; - ss << "bulkInsert to " << table - << ". PQputCopyData error: " << PQerrorMessage(conn_.get()); - disconnect(); - Throw(ss.str()); - } - - if (PQputCopyEnd(conn_.get(), nullptr) == -1) - { - std::stringstream ss; - ss << "bulkInsert to " << table - << ". PQputCopyEnd error: " << PQerrorMessage(conn_.get()); - disconnect(); - Throw(ss.str()); - } - - // The result object must be freed using the libpq API PQclear() call. - pg_result_type copyEndResult{ - nullptr, [](PGresult* result) { PQclear(result); }}; - copyEndResult.reset(PQgetResult(conn_.get())); - ExecStatusType status = PQresultStatus(copyEndResult.get()); - if (status != PGRES_COMMAND_OK) - { - std::stringstream ss; - ss << "bulkInsert to " << table - << ". PQputCopyEnd status not PGRES_COMMAND_OK: " << status; - disconnect(); - Throw(ss.str()); - } -} - -bool -Pg::clear() -{ - if (!conn_) - return false; - - // The result object must be freed using the libpq API PQclear() call. - pg_result_type res{nullptr, [](PGresult* result) { PQclear(result); }}; - - // Consume results until no more, or until the connection is severed. - do - { - res.reset(PQgetResult(conn_.get())); - if (!res) - break; - - // Pending bulk copy operations may leave the connection in such a - // state that it must be disconnected. - switch (PQresultStatus(res.get())) - { - case PGRES_COPY_IN: - if (PQputCopyEnd(conn_.get(), nullptr) != -1) - break; - [[fallthrough]]; // avoids compiler warning - case PGRES_COPY_OUT: - case PGRES_COPY_BOTH: - conn_.reset(); - default:; - } - } while (res && conn_); - - return conn_ != nullptr; -} - -//----------------------------------------------------------------------------- - -PgPool::PgPool(Section const& pgConfig, beast::Journal j) : j_(j) -{ - // Make sure that boost::asio initializes the SSL library. - { - static boost::asio::ssl::detail::openssl_init initSsl; - } - // Don't have postgres client initialize SSL. - PQinitOpenSSL(0, 0); - - /* - Connect to postgres to create low level connection parameters - with optional caching of network address info for subsequent connections. - See https://www.postgresql.org/docs/10/libpq-connect.html - - For bounds checking of postgres connection data received from - the network: the largest size for any connection field in - PG source code is 64 bytes as of 5/2019. There are 29 fields. - */ - constexpr std::size_t maxFieldSize = 1024; - constexpr std::size_t maxFields = 1000; - - // The connection object must be freed using the libpq API PQfinish() call. - pg_connection_type conn( - PQconnectdb(get(pgConfig, "conninfo").c_str()), - [](PGconn* conn) { PQfinish(conn); }); - if (!conn) - Throw("Can't create DB connection."); - if (PQstatus(conn.get()) != CONNECTION_OK) - { - std::stringstream ss; - ss << "Initial DB connection failed: " << PQerrorMessage(conn.get()); - Throw(ss.str()); - } - - int const sockfd = PQsocket(conn.get()); - if (sockfd == -1) - Throw("No DB socket is open."); - struct sockaddr_storage addr; - socklen_t len = sizeof(addr); - if (getpeername(sockfd, reinterpret_cast(&addr), &len) == - -1) - { - Throw( - errno, std::generic_category(), "Can't get server address info."); - } - - // Set "port" and "hostaddr" if we're caching it. - bool const remember_ip = get(pgConfig, "remember_ip", true); - - if (remember_ip) - { - config_.keywords.push_back("port"); - config_.keywords.push_back("hostaddr"); - std::string port; - std::string hostaddr; - - if (addr.ss_family == AF_INET) - { - hostaddr.assign(INET_ADDRSTRLEN, '\0'); - struct sockaddr_in const& ainfo = - reinterpret_cast(addr); - port = std::to_string(ntohs(ainfo.sin_port)); - if (!inet_ntop( - AF_INET, &ainfo.sin_addr, &hostaddr[0], hostaddr.size())) - { - Throw( - errno, - std::generic_category(), - "Can't get IPv4 address string."); - } - } - else if (addr.ss_family == AF_INET6) - { - hostaddr.assign(INET6_ADDRSTRLEN, '\0'); - struct sockaddr_in6 const& ainfo = - reinterpret_cast(addr); - port = std::to_string(ntohs(ainfo.sin6_port)); - if (!inet_ntop( - AF_INET6, &ainfo.sin6_addr, &hostaddr[0], hostaddr.size())) - { - Throw( - errno, - std::generic_category(), - "Can't get IPv6 address string."); - } - } - - config_.values.push_back(port.c_str()); - config_.values.push_back(hostaddr.c_str()); - } - std::unique_ptr connOptions( - PQconninfo(conn.get()), - [](PQconninfoOption* opts) { PQconninfoFree(opts); }); - if (!connOptions) - Throw("Can't get DB connection options."); - - std::size_t nfields = 0; - for (PQconninfoOption* option = connOptions.get(); - option->keyword != nullptr; - ++option) - { - if (++nfields > maxFields) - { - std::stringstream ss; - ss << "DB returned connection options with > " << maxFields - << " fields."; - Throw(ss.str()); - } - - if (!option->val || - (remember_ip && - (!strcmp(option->keyword, "hostaddr") || - !strcmp(option->keyword, "port")))) - { - continue; - } - - if (strlen(option->keyword) > maxFieldSize || - strlen(option->val) > maxFieldSize) - { - std::stringstream ss; - ss << "DB returned a connection option name or value with\n"; - ss << "excessive size (>" << maxFieldSize << " bytes).\n"; - ss << "option (possibly truncated): " - << std::string_view( - option->keyword, - std::min(strlen(option->keyword), maxFieldSize)) - << '\n'; - ss << " value (possibly truncated): " - << std::string_view( - option->val, std::min(strlen(option->val), maxFieldSize)); - Throw(ss.str()); - } - config_.keywords.push_back(option->keyword); - config_.values.push_back(option->val); - } - - config_.keywordsIdx.reserve(config_.keywords.size() + 1); - config_.valuesIdx.reserve(config_.values.size() + 1); - for (std::size_t n = 0; n < config_.keywords.size(); ++n) - { - config_.keywordsIdx.push_back(config_.keywords[n].c_str()); - config_.valuesIdx.push_back(config_.values[n].c_str()); - } - config_.keywordsIdx.push_back(nullptr); - config_.valuesIdx.push_back(nullptr); - - get_if_exists(pgConfig, "max_connections", config_.max_connections); - std::size_t timeout; - if (get_if_exists(pgConfig, "timeout", timeout)) - config_.timeout = std::chrono::seconds(timeout); -} - -void -PgPool::setup() -{ - { - std::stringstream ss; - ss << "max_connections: " << config_.max_connections << ", " - << "timeout: " << config_.timeout.count() << ", " - << "connection params: "; - bool first = true; - for (std::size_t i = 0; i < config_.keywords.size(); ++i) - { - if (first) - first = false; - else - ss << ", "; - ss << config_.keywords[i] << ": " - << (config_.keywords[i] == "password" ? "*" : config_.values[i]); - } - JLOG(j_.debug()) << ss.str(); - } -} - -void -PgPool::stop() -{ - std::lock_guard lock(mutex_); - stop_ = true; - cond_.notify_all(); - idle_.clear(); - JLOG(j_.info()) << "stopped"; -} - -void -PgPool::idleSweeper() -{ - std::size_t before, after; - { - std::lock_guard lock(mutex_); - before = idle_.size(); - if (config_.timeout != std::chrono::seconds(0)) - { - auto const found = - idle_.upper_bound(clock_type::now() - config_.timeout); - for (auto it = idle_.begin(); it != found;) - { - it = idle_.erase(it); - --connections_; - } - } - after = idle_.size(); - } - - JLOG(j_.info()) << "Idle sweeper. connections: " << connections_ - << ". checked out: " << connections_ - after - << ". idle before, after sweep: " << before << ", " - << after; -} - -std::unique_ptr -PgPool::checkout() -{ - std::unique_ptr ret; - std::unique_lock lock(mutex_); - do - { - if (stop_) - return {}; - - // If there is a connection in the pool, return the most recent. - if (idle_.size()) - { - auto entry = idle_.rbegin(); - ret = std::move(entry->second); - idle_.erase(std::next(entry).base()); - } - // Otherwise, return a new connection unless over threshold. - else if (connections_ < config_.max_connections) - { - ++connections_; - ret = std::make_unique(config_, j_, stop_, mutex_); - } - // Otherwise, wait until a connection becomes available or we stop. - else - { - JLOG(j_.error()) << "No database connections available."; - cond_.wait(lock); - } - } while (!ret && !stop_); - lock.unlock(); - - return ret; -} - -void -PgPool::checkin(std::unique_ptr& pg) -{ - if (pg) - { - std::lock_guard lock(mutex_); - if (!stop_ && pg->clear()) - { - idle_.emplace(clock_type::now(), std::move(pg)); - } - else - { - --connections_; - pg.reset(); - } - } - - cond_.notify_all(); -} - -//----------------------------------------------------------------------------- - -std::shared_ptr -make_PgPool(Section const& pgConfig, beast::Journal j) -{ - auto ret = std::make_shared(pgConfig, j); - ret->setup(); - return ret; -} - -//----------------------------------------------------------------------------- - -/** Postgres Schema Management - * - * The postgres schema has several properties to facilitate - * consistent deployments, including upgrades. It is not recommended to - * upgrade the schema concurrently. - * - * Initial deployment should be against a completely fresh database. The - * postgres user must have the CREATE TABLE privilege. - * - * With postgres configured, the first step is to apply the version_query - * schema and consume the results. This script returns the currently - * installed schema version, if configured, or 0 if not. It is idempotent. - * - * If the version installed on the database is equal to the - * LATEST_SCHEMA_VERSION, then no action should take place. - * - * If the version on the database is 0, then the entire latest schema - * should be deployed with the applySchema() function. - * Each version that is developed is fully - * represented in the full_schemata array with each version equal to the - * text in the array's index position. For example, index position 1 - * contains the full schema version 1. Position 2 contains schema version 2. - * Index 0 should never be referenced and its value only a placeholder. - * If a fresh installation is aborted, then subsequent fresh installations - * should install the same version previously attempted, even if there - * exists a newer version. The initSchema() function performs this task. - * Therefore, previous schema versions should remain in the array - * without modification as new versions are developed and placed after them. - * Once the schema is succesffuly deployed, applySchema() persists the - * schema version to the database. - * - * If the current version of the database is greater than 0, then it means - * that a previous schema version is already present. In this case, the database - * schema needs to be updated incrementally for each subsequent version. - * Again, applySchema() is used to upgrade the schema. Schema upgrades are - * in the upgrade_schemata array. Each entry by index position represents - * the database schema version from which the upgrade begins. Each upgrade - * sets the database to the next version. Schema upgrades can only safely - * happen from one version to the next. To upgrade several versions of schema, - * upgrade incrementally for each version that separates the current from the - * latest. For example, to upgrade from version 5 to version 6 of the schema, - * use upgrade_schemata[5]. To upgrade from version 1 to version 4, use - * upgrade_schemata[1], upgrade_schemata[2], and upgrade_schemata[3] in - * sequence. - * - * To upgrade the schema past version 1, the following variables must be - * updated: - * 1) LATEST_SCHEMA_VERSION must be set to the new version. - * 2) A new entry must be placed at the end of the full_schemata array. This - * entry should have the entire schema so that fresh installations can - * be performed with it. The index position must be equal to the - * LATEST_SCHEMA_VERSION. - * 3) A new entry must be placed at the end of the upgrade_schemata array. - * This entry should only contain commands to upgrade the schema from - * the immediately previous version to the new version. - * - * It is up to the developer to ensure that all schema commands are idempotent. - * This protects against 2 things: - * 1) Resuming schema installation after a problem. - * 2) Concurrent schema updates from multiple processes. - * - * There are several things that must considered for upgrading existing - * schemata to avoid stability and performance problems. Some examples and - * suggestions follow. - * - Schema changes such as creating new columns and indices can consume - * a lot of time. Therefore, before such changes, a separate script should - * be executed by the user to perform the schema upgrade prior to restarting - * rippled. - * - Stored functions cannot be dropped while being accessed. Also, - * dropping stored functions can be ambiguous if multiple functions with - * the same name but different signatures exist. Further, stored function - * behavior from one schema version to the other would likely be handled - * differently by rippled. In this case, it is likely that the functions - * themselves should be versioned such as by appending a number to the - * end of the name (abcf becomes abcf_2, abcf_3, etc.) - * - * Essentially, each schema upgrade will have its own factors to impact - * service availability and function. - */ - -#define LATEST_SCHEMA_VERSION 1 - -char const* version_query = R"( -CREATE TABLE IF NOT EXISTS version (version int NOT NULL, - fresh_pending int NOT NULL); - --- Version 0 means that no schema has been fully deployed. -DO $$ -BEGIN - IF NOT EXISTS (SELECT 1 FROM version) THEN - INSERT INTO version VALUES (0, 0); -END IF; -END $$; - --- Function to set the schema version. _in_pending should only be set to --- non-zero prior to an attempt to initialize the schema from scratch. --- After successful initialization, this should set to 0. --- _in_version should be set to the version of schema that has been applied --- once successful application has occurred. -CREATE OR REPLACE FUNCTION set_schema_version ( - _in_version int, - _in_pending int -) RETURNS void AS $$ -DECLARE - _current_version int; -BEGIN - IF _in_version IS NULL OR _in_pending IS NULL THEN RETURN; END IF; - IF EXISTS (SELECT 1 FROM version) THEN DELETE FROM version; END IF; - INSERT INTO version VALUES (_in_version, _in_pending); - RETURN; -END; -$$ LANGUAGE plpgsql; - --- PQexec() returns the output of the last statement in its response. -SELECT * FROM version; -)"; - -std::array full_schemata = { - // version 0: - "There is no such thing as schema version 0." - - // version 1: - , - R"( --- Table to store ledger headers. -CREATE TABLE IF NOT EXISTS ledgers ( - ledger_seq bigint PRIMARY KEY, - ledger_hash bytea NOT NULL, - prev_hash bytea NOT NULL, - total_coins bigint NOT NULL, - closing_time bigint NOT NULL, - prev_closing_time bigint NOT NULL, - close_time_res bigint NOT NULL, - close_flags bigint NOT NULL, - account_set_hash bytea NOT NULL, - trans_set_hash bytea NOT NULL -); - --- Index for lookups by ledger hash. -CREATE INDEX IF NOT EXISTS ledgers_ledger_hash_idx ON ledgers - USING hash (ledger_hash); - --- Transactions table. Deletes from the ledger table --- cascade here based on ledger_seq. -CREATE TABLE IF NOT EXISTS transactions ( - ledger_seq bigint NOT NULL, - transaction_index bigint NOT NULL, - trans_id bytea NOT NULL, - nodestore_hash bytea NOT NULL, - constraint transactions_pkey PRIMARY KEY (ledger_seq, transaction_index), - constraint transactions_fkey FOREIGN KEY (ledger_seq) - REFERENCES ledgers (ledger_seq) ON DELETE CASCADE -); - --- Index for lookups by transaction hash. -CREATE INDEX IF NOT EXISTS transactions_trans_id_idx ON transactions - USING hash (trans_id); - --- Table that maps accounts to transactions affecting them. Deletes from the --- ledger table by way of transactions table cascade here based on ledger_seq. -CREATE TABLE IF NOT EXISTS account_transactions ( - account bytea NOT NULL, - ledger_seq bigint NOT NULL, - transaction_index bigint NOT NULL, - constraint account_transactions_pkey PRIMARY KEY (account, ledger_seq, - transaction_index), - constraint account_transactions_fkey FOREIGN KEY (ledger_seq, - transaction_index) REFERENCES transactions ( - ledger_seq, transaction_index) ON DELETE CASCADE -); - --- Index to allow for fast cascading deletions and referential integrity. -CREATE INDEX IF NOT EXISTS fki_account_transactions_idx ON - account_transactions USING btree (ledger_seq, transaction_index); - --- Avoid inadvertent administrative tampering with committed data. -CREATE OR REPLACE RULE ledgers_update_protect AS ON UPDATE TO - ledgers DO INSTEAD NOTHING; -CREATE OR REPLACE RULE transactions_update_protect AS ON UPDATE TO - transactions DO INSTEAD NOTHING; -CREATE OR REPLACE RULE account_transactions_update_protect AS ON UPDATE TO - account_transactions DO INSTEAD NOTHING; - --- Stored procedure to assist with the tx() RPC call. Takes transaction hash --- as input. If found, returns the ledger sequence in which it was applied. --- If not, returns the range of ledgers searched. -CREATE OR REPLACE FUNCTION tx ( - _in_trans_id bytea -) RETURNS jsonb AS $$ -DECLARE - _min_seq bigint := min_ledger(); - _max_seq bigint := max_ledger(); - _ledger_seq bigint; - _nodestore_hash bytea; -BEGIN - - IF _min_seq IS NULL THEN - RETURN jsonb_build_object('error', 'empty database'); - END IF; - IF length(_in_trans_id) != 32 THEN - RETURN jsonb_build_object('error', '_in_trans_id size: ' - || to_char(length(_in_trans_id), '999')); - END IF; - - EXECUTE 'SELECT nodestore_hash, ledger_seq - FROM transactions - WHERE trans_id = $1 - AND ledger_seq BETWEEN $2 AND $3 - ' INTO _nodestore_hash, _ledger_seq USING _in_trans_id, _min_seq, _max_seq; - IF _nodestore_hash IS NULL THEN - RETURN jsonb_build_object('min_seq', _min_seq, 'max_seq', _max_seq); - END IF; - RETURN jsonb_build_object('nodestore_hash', _nodestore_hash, 'ledger_seq', - _ledger_seq); -END; -$$ LANGUAGE plpgsql; - --- Return the earliest ledger sequence intended for range operations --- that protect the bottom of the range from deletion. Return NULL if empty. -CREATE OR REPLACE FUNCTION min_ledger () RETURNS bigint AS $$ -DECLARE - _min_seq bigint := (SELECT ledger_seq from min_seq); -BEGIN - IF _min_seq IS NULL THEN - RETURN (SELECT ledger_seq FROM ledgers ORDER BY ledger_seq ASC LIMIT 1); - ELSE - RETURN _min_seq; - END IF; -END; -$$ LANGUAGE plpgsql; - --- Return the latest ledger sequence in the database, or NULL if empty. -CREATE OR REPLACE FUNCTION max_ledger () RETURNS bigint AS $$ -BEGIN - RETURN (SELECT ledger_seq FROM ledgers ORDER BY ledger_seq DESC LIMIT 1); -END; -$$ LANGUAGE plpgsql; - --- account_tx() RPC helper. From the rippled reporting process, only the --- parameters without defaults are required. For the parameters with --- defaults, validation should be done by rippled, such as: --- _in_account_id should be a valid xrp base58 address. --- _in_forward either true or false according to the published api --- _in_limit should be validated and not simply passed through from --- client. --- --- For _in_ledger_index_min and _in_ledger_index_max, if passed in the --- request, verify that their type is int and pass through as is. --- For _ledger_hash, verify and convert from hex length 32 bytes and --- prepend with \x (\\x C++). --- --- For _in_ledger_index, if the input type is integer, then pass through --- as is. If the type is string and contents = validated, then do not --- set _in_ledger_index. Instead set _in_invalidated to TRUE. --- --- There is no need for rippled to do any type of lookup on max/min --- ledger range, lookup of hash, or the like. This functions does those --- things, including error responses if bad input. Only the above must --- be done to set the correct search range. --- --- If a marker is present in the request, verify the members 'ledger' --- and 'seq' are integers and they correspond to _in_marker_seq --- _in_marker_index. --- To reiterate: --- JSON input field 'ledger' corresponds to _in_marker_seq --- JSON input field 'seq' corresponds to _in_marker_index -CREATE OR REPLACE FUNCTION account_tx ( - _in_account_id bytea, - _in_forward bool, - _in_limit bigint, - _in_ledger_index_min bigint = NULL, - _in_ledger_index_max bigint = NULL, - _in_ledger_hash bytea = NULL, - _in_ledger_index bigint = NULL, - _in_validated bool = NULL, - _in_marker_seq bigint = NULL, - _in_marker_index bigint = NULL -) RETURNS jsonb AS $$ -DECLARE - _min bigint; - _max bigint; - _sort_order text := (SELECT CASE WHEN _in_forward IS TRUE THEN - 'ASC' ELSE 'DESC' END); - _marker bool; - _between_min bigint; - _between_max bigint; - _sql text; - _cursor refcursor; - _result jsonb; - _record record; - _tally bigint := 0; - _ret_marker jsonb; - _transactions jsonb[] := '{}'; -BEGIN - IF _in_ledger_index_min IS NOT NULL OR - _in_ledger_index_max IS NOT NULL THEN - _min := (SELECT CASE WHEN _in_ledger_index_min IS NULL - THEN min_ledger() ELSE greatest( - _in_ledger_index_min, min_ledger()) END); - _max := (SELECT CASE WHEN _in_ledger_index_max IS NULL OR - _in_ledger_index_max = -1 THEN max_ledger() ELSE - least(_in_ledger_index_max, max_ledger()) END); - - IF _max < _min THEN - RETURN jsonb_build_object('error', 'max is less than min ledger'); - END IF; - - ELSIF _in_ledger_hash IS NOT NULL OR _in_ledger_index IS NOT NULL - OR _in_validated IS TRUE THEN - IF _in_ledger_hash IS NOT NULL THEN - IF length(_in_ledger_hash) != 32 THEN - RETURN jsonb_build_object('error', '_in_ledger_hash size: ' - || to_char(length(_in_ledger_hash), '999')); - END IF; - EXECUTE 'SELECT ledger_seq - FROM ledgers - WHERE ledger_hash = $1' - INTO _min USING _in_ledger_hash::bytea; - ELSE - IF _in_ledger_index IS NOT NULL AND _in_validated IS TRUE THEN - RETURN jsonb_build_object('error', - '_in_ledger_index cannot be set and _in_validated true'); - END IF; - IF _in_validated IS TRUE THEN - _in_ledger_index := max_ledger(); - END IF; - _min := (SELECT ledger_seq - FROM ledgers - WHERE ledger_seq = _in_ledger_index); - END IF; - IF _min IS NULL THEN - RETURN jsonb_build_object('error', 'ledger not found'); - END IF; - _max := _min; - ELSE - _min := min_ledger(); - _max := max_ledger(); - END IF; - - IF _in_marker_seq IS NOT NULL OR _in_marker_index IS NOT NULL THEN - _marker := TRUE; - IF _in_marker_seq IS NULL OR _in_marker_index IS NULL THEN - -- The rippled implementation returns no transaction results - -- if either of these values are missing. - _between_min := 0; - _between_max := 0; - ELSE - IF _in_forward IS TRUE THEN - _between_min := _in_marker_seq; - _between_max := _max; - ELSE - _between_min := _min; - _between_max := _in_marker_seq; - END IF; - END IF; - ELSE - _marker := FALSE; - _between_min := _min; - _between_max := _max; - END IF; - IF _between_max < _between_min THEN - RETURN jsonb_build_object('error', 'ledger search range is ' - || to_char(_between_min, '999') || '-' - || to_char(_between_max, '999')); - END IF; - - _sql := format(' - SELECT transactions.ledger_seq, transactions.transaction_index, - transactions.trans_id, transactions.nodestore_hash - FROM transactions - INNER JOIN account_transactions - ON transactions.ledger_seq = - account_transactions.ledger_seq - AND transactions.transaction_index = - account_transactions.transaction_index - WHERE account_transactions.account = $1 - AND account_transactions.ledger_seq BETWEEN $2 AND $3 - ORDER BY transactions.ledger_seq %s, transactions.transaction_index %s - ', _sort_order, _sort_order); - - OPEN _cursor FOR EXECUTE _sql USING _in_account_id, _between_min, - _between_max; - LOOP - FETCH _cursor INTO _record; - IF _record IS NULL THEN EXIT; END IF; - IF _marker IS TRUE THEN - IF _in_marker_seq = _record.ledger_seq THEN - IF _in_forward IS TRUE THEN - IF _in_marker_index > _record.transaction_index THEN - CONTINUE; - END IF; - ELSE - IF _in_marker_index < _record.transaction_index THEN - CONTINUE; - END IF; - END IF; - END IF; - _marker := FALSE; - END IF; - - _tally := _tally + 1; - IF _tally > _in_limit THEN - _ret_marker := jsonb_build_object( - 'ledger', _record.ledger_seq, - 'seq', _record.transaction_index); - EXIT; - END IF; - - -- Is the transaction index in the tx object? - _transactions := _transactions || jsonb_build_object( - 'ledger_seq', _record.ledger_seq, - 'transaction_index', _record.transaction_index, - 'trans_id', _record.trans_id, - 'nodestore_hash', _record.nodestore_hash); - - END LOOP; - CLOSE _cursor; - - _result := jsonb_build_object('ledger_index_min', _min, - 'ledger_index_max', _max, - 'transactions', _transactions); - IF _ret_marker IS NOT NULL THEN - _result := _result || jsonb_build_object('marker', _ret_marker); - END IF; - RETURN _result; -END; -$$ LANGUAGE plpgsql; - --- Trigger prior to insert on ledgers table. Validates length of hash fields. --- Verifies ancestry based on ledger_hash & prev_hash as follows: --- 1) If ledgers is empty, allows insert. --- 2) For each new row, check for previous and later ledgers by a single --- sequence. For each that exist, confirm ancestry based on hashes. --- 3) Disallow inserts with no prior or next ledger by sequence if any --- ledgers currently exist. This disallows gaps to be introduced by --- way of inserting. -CREATE OR REPLACE FUNCTION insert_ancestry() RETURNS TRIGGER AS $$ -DECLARE - _parent bytea; - _child bytea; -BEGIN - IF length(NEW.ledger_hash) != 32 OR length(NEW.prev_hash) != 32 THEN - RAISE 'ledger_hash and prev_hash must each be 32 bytes: %', NEW; - END IF; - - IF (SELECT ledger_hash - FROM ledgers - ORDER BY ledger_seq DESC - LIMIT 1) = NEW.prev_hash THEN RETURN NEW; END IF; - - IF NOT EXISTS (SELECT 1 FROM LEDGERS) THEN RETURN NEW; END IF; - - _parent := (SELECT ledger_hash - FROM ledgers - WHERE ledger_seq = NEW.ledger_seq - 1); - _child := (SELECT prev_hash - FROM ledgers - WHERE ledger_seq = NEW.ledger_seq + 1); - IF _parent IS NULL AND _child IS NULL THEN - RAISE 'Ledger Ancestry error: orphan.'; - END IF; - IF _parent != NEW.prev_hash THEN - RAISE 'Ledger Ancestry error: bad parent.'; - END IF; - IF _child != NEW.ledger_hash THEN - RAISE 'Ledger Ancestry error: bad child.'; - END IF; - - RETURN NEW; -END; -$$ LANGUAGE plpgsql; - --- Trigger function prior to delete on ledgers table. Disallow gaps from --- forming. Do not allow deletions if both the previous and next ledgers --- are present. In other words, only allow either the least or greatest --- to be deleted. -CREATE OR REPLACE FUNCTION delete_ancestry () RETURNS TRIGGER AS $$ -BEGIN - IF EXISTS (SELECT 1 - FROM ledgers - WHERE ledger_seq = OLD.ledger_seq + 1) - AND EXISTS (SELECT 1 - FROM ledgers - WHERE ledger_seq = OLD.ledger_seq - 1) THEN - RAISE 'Ledger Ancestry error: Can only delete the least or greatest ' - 'ledger.'; - END IF; - RETURN OLD; -END; -$$ LANGUAGE plpgsql; - --- Track the minimum sequence that should be used for ranged queries --- with protection against deletion during the query. This should --- be updated before calling online_delete() to not block deleting that --- range. -CREATE TABLE IF NOT EXISTS min_seq ( - ledger_seq bigint NOT NULL -); - --- Set the minimum sequence for use in ranged queries with protection --- against deletion greater than or equal to the input parameter. This --- should be called prior to online_delete() with the same parameter --- value so that online_delete() is not blocked by range queries --- that are protected against concurrent deletion of the ledger at --- the bottom of the range. This function needs to be called from a --- separate transaction from that which executes online_delete(). -CREATE OR REPLACE FUNCTION prepare_delete ( - _in_last_rotated bigint -) RETURNS void AS $$ -BEGIN - IF EXISTS (SELECT 1 FROM min_seq) THEN - DELETE FROM min_seq; - END IF; - INSERT INTO min_seq VALUES (_in_last_rotated + 1); -END; -$$ LANGUAGE plpgsql; - --- Function to delete old data. All data belonging to ledgers prior to and --- equal to the _in_seq parameter will be deleted. This should be --- called with the input parameter equivalent to the value of lastRotated --- in rippled's online_delete routine. -CREATE OR REPLACE FUNCTION online_delete ( - _in_seq bigint -) RETURNS void AS $$ -BEGIN - DELETE FROM LEDGERS WHERE ledger_seq <= _in_seq; -END; -$$ LANGUAGE plpgsql; - --- Function to delete data from the top of the ledger range. Delete --- everything greater than the input parameter. --- It doesn't do a normal range delete because of the trigger protecting --- deletions causing gaps. Instead, it walks back from the greatest ledger. -CREATE OR REPLACE FUNCTION delete_above ( - _in_seq bigint -) RETURNS void AS $$ -DECLARE - _max_seq bigint := max_ledger(); - _i bigint := _max_seq; -BEGIN - IF _max_seq IS NULL THEN RETURN; END IF; - LOOP - IF _i <= _in_seq THEN RETURN; END IF; - EXECUTE 'DELETE FROM ledgers WHERE ledger_seq = $1' USING _i; - _i := _i - 1; - END LOOP; -END; -$$ LANGUAGE plpgsql; - --- Verify correct ancestry of ledgers in database: --- Table to persist last-confirmed latest ledger with proper ancestry. -CREATE TABLE IF NOT EXISTS ancestry_verified ( - ledger_seq bigint NOT NULL -); - --- Function to verify ancestry of ledgers based on ledger_hash and prev_hash. --- Upon failure, returns ledger sequence failing ancestry check. --- Otherwise, returns NULL. --- _in_full: If TRUE, verify entire table. Else verify starting from --- value in ancestry_verfied table. If no value, then start --- from lowest ledger. --- _in_persist: If TRUE, persist the latest ledger with correct ancestry. --- If an exception was raised because of failure, persist --- the latest ledger prior to that which failed. --- _in_min: If set and _in_full is not true, the starting ledger from which --- to verify. --- _in_max: If set and _in_full is not true, the latest ledger to verify. -CREATE OR REPLACE FUNCTION check_ancestry ( - _in_full bool = FALSE, - _in_persist bool = TRUE, - _in_min bigint = NULL, - _in_max bigint = NULL -) RETURNS bigint AS $$ -DECLARE - _min bigint; - _max bigint; - _last_verified bigint; - _parent ledgers; - _current ledgers; - _cursor refcursor; -BEGIN - IF _in_full IS TRUE AND - (_in_min IS NOT NULL) OR (_in_max IS NOT NULL) THEN - RAISE 'Cannot specify manual range and do full check.'; - END IF; - - IF _in_min IS NOT NULL THEN - _min := _in_min; - ELSIF _in_full IS NOT TRUE THEN - _last_verified := (SELECT ledger_seq FROM ancestry_verified); - IF _last_verified IS NULL THEN - _min := min_ledger(); - ELSE - _min := _last_verified + 1; - END IF; - ELSE - _min := min_ledger(); - END IF; - EXECUTE 'SELECT * FROM ledgers WHERE ledger_seq = $1' - INTO _parent USING _min - 1; - IF _last_verified IS NOT NULL AND _parent IS NULL THEN - RAISE 'Verified ledger % doesn''t exist.', _last_verified; - END IF; - - IF _in_max IS NOT NULL THEN - _max := _in_max; - ELSE - _max := max_ledger(); - END IF; - - OPEN _cursor FOR EXECUTE 'SELECT * - FROM ledgers - WHERE ledger_seq BETWEEN $1 AND $2 - ORDER BY ledger_seq ASC' - USING _min, _max; - LOOP - FETCH _cursor INTO _current; - IF _current IS NULL THEN EXIT; END IF; - IF _parent IS NOT NULL THEN - IF _current.prev_hash != _parent.ledger_hash THEN - CLOSE _cursor; - RETURN _current.ledger_seq; - RAISE 'Ledger ancestry failure current, parent:% %', - _current, _parent; - END IF; - END IF; - _parent := _current; - END LOOP; - CLOSE _cursor; - - IF _in_persist IS TRUE AND _parent IS NOT NULL THEN - DELETE FROM ancestry_verified; - INSERT INTO ancestry_verified VALUES (_parent.ledger_seq); - END IF; - - RETURN NULL; -END; -$$ LANGUAGE plpgsql; - --- Return number of whole seconds since the latest ledger was inserted, based --- on ledger close time (not wall clock) of the insert. --- Note that ledgers.closing_time is number of seconds since the XRP --- epoch, which is 01/01/2000 00:00:00. This in turn is 946684800 seconds --- after the UNIX epoch. This conforms to the "age" field in the --- server_info RPC call. -CREATE OR REPLACE FUNCTION age () RETURNS bigint AS $$ -BEGIN - RETURN (EXTRACT(EPOCH FROM (now())) - - (946684800 + (SELECT closing_time - FROM ledgers - ORDER BY ledger_seq DESC - LIMIT 1)))::bigint; -END; -$$ LANGUAGE plpgsql; - --- Return range of ledgers, or empty if none. This conforms to the --- "complete_ledgers" field of the server_info RPC call. Note --- that ledger gaps are prevented for reporting mode so the range --- is simply the set between the least and greatest ledgers. -CREATE OR REPLACE FUNCTION complete_ledgers () RETURNS text AS $$ -DECLARE - _min bigint := min_ledger(); - _max bigint := max_ledger(); -BEGIN - IF _min IS NULL THEN RETURN 'empty'; END IF; - IF _min = _max THEN RETURN _min; END IF; - RETURN _min || '-' || _max; -END; -$$ LANGUAGE plpgsql; - -)" - - // version 2: - // , R"(Full idempotent text of schema version 2)" - - // version 3: - // , R"(Full idempotent text of schema version 3)" - - // version 4: - // , R"(Full idempotent text of schema version 4)" - - // ... - - // version n: - // , R"(Full idempotent text of schema version n)" -}; - -std::array upgrade_schemata = { - // upgrade from version 0: - "There is no upgrade path from version 0. Instead, install " - "from full_schemata." - // upgrade from version 1 to 2: - //, R"(Text to idempotently upgrade from version 1 to 2)" - // upgrade from version 2 to 3: - //, R"(Text to idempotently upgrade from version 2 to 3)" - // upgrade from version 3 to 4: - //, R"(Text to idempotently upgrade from version 3 to 4)" - // ... - // upgrade from version n-1 to n: - //, R"(Text to idempotently upgrade from version n-1 to n)" -}; - -/** Apply schema to postgres. - * - * The schema text should contain idempotent SQL & plpgSQL statements. - * Once completed, the version of the schema will be persisted. - * - * Throws upon error. - * - * @param pool Postgres connection pool manager. - * @param schema SQL commands separated by semi-colon. - * @param currentVersion The current version of the schema on the database. - * @param schemaVersion The version that will be in place once the schema - * has been applied. - */ -void -applySchema( - std::shared_ptr const& pool, - char const* schema, - std::uint32_t currentVersion, - std::uint32_t schemaVersion) -{ - if (currentVersion != 0 && schemaVersion != currentVersion + 1) - { - assert(false); - std::stringstream ss; - ss << "Schema upgrade versions past initial deployment must increase " - "monotonically. Versions: current, target: " - << currentVersion << ", " << schemaVersion; - Throw(ss.str()); - } - - auto res = PgQuery(pool)({schema, {}}); - if (!res) - { - std::stringstream ss; - ss << "Error applying schema from version " << currentVersion << "to " - << schemaVersion << ": " << res.msg(); - Throw(ss.str()); - } - - auto cmd = boost::format(R"(SELECT set_schema_version(%u, 0))"); - res = PgQuery(pool)({boost::str(cmd % schemaVersion).c_str(), {}}); - if (!res) - { - std::stringstream ss; - ss << "Error setting schema version from " << currentVersion << " to " - << schemaVersion << ": " << res.msg(); - Throw(ss.str()); - } -} - -void -initSchema(std::shared_ptr const& pool) -{ - // Figure out what schema version, if any, is already installed. - auto res = PgQuery(pool)({version_query, {}}); - if (!res) - { - std::stringstream ss; - ss << "Error getting database schema version: " << res.msg(); - Throw(ss.str()); - } - std::uint32_t currentSchemaVersion = res.asInt(); - std::uint32_t const pendingSchemaVersion = res.asInt(0, 1); - - // Nothing to do if we are on the latest schema; - if (currentSchemaVersion == LATEST_SCHEMA_VERSION) - return; - - if (currentSchemaVersion == 0) - { - // If a fresh install has not been completed, then re-attempt - // the install of the same schema version. - std::uint32_t const freshVersion = - pendingSchemaVersion ? pendingSchemaVersion : LATEST_SCHEMA_VERSION; - // Persist that we are attempting a fresh install to the latest version. - // This protects against corruption in an aborted install that is - // followed by a fresh installation attempt with a new schema. - auto cmd = boost::format(R"(SELECT set_schema_version(0, %u))"); - res = PgQuery(pool)({boost::str(cmd % freshVersion).c_str(), {}}); - if (!res) - { - std::stringstream ss; - ss << "Error setting schema version from " << currentSchemaVersion - << " to " << freshVersion << ": " << res.msg(); - Throw(ss.str()); - } - - // Install the full latest schema. - applySchema( - pool, - full_schemata[freshVersion], - currentSchemaVersion, - freshVersion); - currentSchemaVersion = freshVersion; - } - - // Incrementally upgrade one version at a time until latest. - for (; currentSchemaVersion < LATEST_SCHEMA_VERSION; ++currentSchemaVersion) - { - applySchema( - pool, - upgrade_schemata[currentSchemaVersion], - currentSchemaVersion, - currentSchemaVersion + 1); - } -} - -} // namespace ripple -#endif diff --git a/src/xrpld/core/Pg.h b/src/xrpld/core/Pg.h deleted file mode 100644 index c1333ed66fb..00000000000 --- a/src/xrpld/core/Pg.h +++ /dev/null @@ -1,520 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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. -*/ -//============================================================================== - -#ifdef RIPPLED_REPORTING -#ifndef RIPPLE_CORE_PG_H_INCLUDED -#define RIPPLE_CORE_PG_H_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { - -// These postgres structs must be freed only by the postgres API. -using pg_result_type = std::unique_ptr; -using pg_connection_type = std::unique_ptr; - -/** first: command - * second: parameter values - * - * The 2nd member takes an optional string to - * distinguish between NULL parameters and empty strings. An empty - * item corresponds to a NULL parameter. - * - * Postgres reads each parameter as a c-string, regardless of actual type. - * Binary types (bytea) need to be converted to hex and prepended with - * \x ("\\x"). - */ -using pg_params = - std::pair>>; - -/** Parameter values for pg API. */ -using pg_formatted_params = std::vector; - -/** Parameters for managing postgres connections. */ -struct PgConfig -{ - /** Maximum connections allowed to db. */ - std::size_t max_connections{std::numeric_limits::max()}; - /** Close idle connections past this duration. */ - std::chrono::seconds timeout{600}; - - /** Index of DB connection parameter names. */ - std::vector keywordsIdx; - /** DB connection parameter names. */ - std::vector keywords; - /** Index of DB connection parameter values. */ - std::vector valuesIdx; - /** DB connection parameter values. */ - std::vector values; -}; - -//----------------------------------------------------------------------------- - -/** Class that operates on postgres query results. - * - * The functions that return results do not check first whether the - * expected results are actually there. Therefore, the caller first needs - * to check whether or not a valid response was returned using the operator - * bool() overload. If number of tuples or fields are unknown, then check - * those. Each result field should be checked for null before attempting - * to return results. Finally, the caller must know the type of the field - * before calling the corresponding function to return a field. Postgres - * internally stores each result field as null-terminated strings. - */ -class PgResult -{ - // The result object must be freed using the libpq API PQclear() call. - pg_result_type result_{nullptr, [](PGresult* result) { PQclear(result); }}; - std::optional> error_; - -public: - /** Constructor for when the process is stopping. - * - */ - PgResult() - { - } - - /** Constructor for successful query results. - * - * @param result Query result. - */ - explicit PgResult(pg_result_type&& result) : result_(std::move(result)) - { - } - - /** Constructor for failed query results. - * - * @param result Query result that contains error information. - * @param conn Postgres connection that contains error information. - */ - PgResult(PGresult* result, PGconn* conn) - : error_({PQresultStatus(result), PQerrorMessage(conn)}) - { - } - - /** Return field as a null-terminated string pointer. - * - * Note that this function does not guarantee that the result struct - * exists, or that the row and fields exist, or that the field is - * not null. - * - * @param ntuple Row number. - * @param nfield Field number. - * @return Field contents. - */ - char const* - c_str(int ntuple = 0, int nfield = 0) const - { - return PQgetvalue(result_.get(), ntuple, nfield); - } - - /** Return field as equivalent to Postgres' INT type (32 bit signed). - * - * Note that this function does not guarantee that the result struct - * exists, or that the row and fields exist, or that the field is - * not null, or that the type is that requested. - - * @param ntuple Row number. - * @param nfield Field number. - * @return Field contents. - */ - std::int32_t - asInt(int ntuple = 0, int nfield = 0) const - { - return boost::lexical_cast( - PQgetvalue(result_.get(), ntuple, nfield)); - } - - /** Return field as equivalent to Postgres' BIGINT type (64 bit signed). - * - * Note that this function does not guarantee that the result struct - * exists, or that the row and fields exist, or that the field is - * not null, or that the type is that requested. - - * @param ntuple Row number. - * @param nfield Field number. - * @return Field contents. - */ - std::int64_t - asBigInt(int ntuple = 0, int nfield = 0) const - { - return boost::lexical_cast( - PQgetvalue(result_.get(), ntuple, nfield)); - } - - /** Returns whether the field is NULL or not. - * - * Note that this function does not guarantee that the result struct - * exists, or that the row and fields exist. - * - * @param ntuple Row number. - * @param nfield Field number. - * @return Whether field is NULL. - */ - bool - isNull(int ntuple = 0, int nfield = 0) const - { - return PQgetisnull(result_.get(), ntuple, nfield); - } - - /** Check whether a valid response occurred. - * - * @return Whether or not the query returned a valid response. - */ - operator bool() const - { - return result_ != nullptr; - } - - /** Message describing the query results suitable for diagnostics. - * - * If error, then the postgres error type and message are returned. - * Otherwise, "ok" - * - * @return Query result message. - */ - std::string - msg() const; - - /** Get number of rows in result. - * - * Note that this function does not guarantee that the result struct - * exists. - * - * @return Number of result rows. - */ - int - ntuples() const - { - return PQntuples(result_.get()); - } - - /** Get number of fields in result. - * - * Note that this function does not guarantee that the result struct - * exists. - * - * @return Number of result fields. - */ - int - nfields() const - { - return PQnfields(result_.get()); - } - - /** Return result status of the command. - * - * Note that this function does not guarantee that the result struct - * exists. - * - * @return - */ - ExecStatusType - status() const - { - return PQresultStatus(result_.get()); - } -}; - -/* Class that contains and operates upon a postgres connection. */ -class Pg -{ - friend class PgPool; - friend class PgQuery; - - PgConfig const& config_; - beast::Journal const j_; - bool& stop_; - std::mutex& mutex_; - - // The connection object must be freed using the libpq API PQfinish() call. - pg_connection_type conn_{nullptr, [](PGconn* conn) { PQfinish(conn); }}; - - /** Clear results from the connection. - * - * Results from previous commands must be cleared before new commands - * can be processed. This function should be called on connections - * that weren't processed completely before being reused, such as - * when being checked-in. - * - * @return whether or not connection still exists. - */ - bool - clear(); - - /** Connect to postgres. - * - * Idempotently connects to postgres by first checking whether an - * existing connection is already present. If connection is not present - * or in an errored state, reconnects to the database. - */ - void - connect(); - - /** Disconnect from postgres. */ - void - disconnect() - { - conn_.reset(); - } - - /** Execute postgres query. - * - * If parameters are included, then the command should contain only a - * single SQL statement. If no parameters, then multiple SQL statements - * delimited by semi-colons can be processed. The response is from - * the last command executed. - * - * @param command postgres API command string. - * @param nParams postgres API number of parameters. - * @param values postgres API array of parameter. - * @return Query result object. - */ - PgResult - query(char const* command, std::size_t nParams, char const* const* values); - - /** Execute postgres query with no parameters. - * - * @param command Query string. - * @return Query result object; - */ - PgResult - query(char const* command) - { - return query(command, 0, nullptr); - } - - /** Execute postgres query with parameters. - * - * @param dbParams Database command and parameter values. - * @return Query result object. - */ - PgResult - query(pg_params const& dbParams); - - /** Insert multiple records into a table using Postgres' bulk COPY. - * - * Throws upon error. - * - * @param table Name of table for import. - * @param records Records in the COPY IN format. - */ - void - bulkInsert(char const* table, std::string const& records); - -public: - /** Constructor for Pg class. - * - * @param config Config parameters. - * @param j Logger object. - * @param stop Reference to connection pool's stop flag. - * @param mutex Reference to connection pool's mutex. - */ - Pg(PgConfig const& config, - beast::Journal const j, - bool& stop, - std::mutex& mutex) - : config_(config), j_(j), stop_(stop), mutex_(mutex) - { - } -}; - -//----------------------------------------------------------------------------- - -/** Database connection pool. - * - * Allow re-use of postgres connections. Postgres connections are created - * as needed until configurable limit is reached. After use, each connection - * is placed in a container ordered by time of use. Each request for - * a connection grabs the most recently used connection from the container. - * If none are available, a new connection is used (up to configured limit). - * Idle connections are destroyed periodically after configurable - * timeout duration. - * - * This should be stored as a shared pointer so PgQuery objects can safely - * outlive it. - */ -class PgPool -{ - friend class PgQuery; - - using clock_type = std::chrono::steady_clock; - - PgConfig config_; - beast::Journal const j_; - std::mutex mutex_; - std::condition_variable cond_; - std::size_t connections_{}; - bool stop_{false}; - - /** Idle database connections ordered by timestamp to allow timing out. */ - std::multimap, std::unique_ptr> - idle_; - - /** Get a postgres connection object. - * - * Return the most recent idle connection in the pool, if available. - * Otherwise, return a new connection unless we're at the threshold. - * If so, then wait until a connection becomes available. - * - * @return Postgres object. - */ - std::unique_ptr - checkout(); - - /** Return a postgres object to the pool for reuse. - * - * If connection is healthy, place in pool for reuse. After calling this, - * the container no longer have a connection unless checkout() is called. - * - * @param pg Pg object. - */ - void - checkin(std::unique_ptr& pg); - -public: - /** Connection pool constructor. - * - * @param pgConfig Postgres config. - * @param j Logger object. - */ - PgPool(Section const& pgConfig, beast::Journal j); - - /** Initiate idle connection timer. - * - * The PgPool object needs to be fully constructed to support asynchronous - * operations. - */ - void - setup(); - - /** Prepare for process shutdown. */ - void - stop(); - - /** Disconnect idle postgres connections. */ - void - idleSweeper(); -}; - -//----------------------------------------------------------------------------- - -/** Class to query postgres. - * - * This class should be used by functions outside of this - * compilation unit for querying postgres. It automatically acquires and - * relinquishes a database connection to handle each query. - */ -class PgQuery -{ -private: - std::shared_ptr pool_; - std::unique_ptr pg_; - -public: - PgQuery() = delete; - - PgQuery(std::shared_ptr const& pool) - : pool_(pool), pg_(pool->checkout()) - { - } - - ~PgQuery() - { - pool_->checkin(pg_); - } - - /** Execute postgres query with parameters. - * - * @param dbParams Database command with parameters. - * @return Result of query, including errors. - */ - PgResult - operator()(pg_params const& dbParams) - { - if (!pg_) // It means we're stopping. Return empty result. - return PgResult(); - return pg_->query(dbParams); - } - - /** Execute postgres query with only command statement. - * - * @param command Command statement. - * @return Result of query, including errors. - */ - PgResult - operator()(char const* command) - { - return operator()(pg_params{command, {}}); - } - - /** Insert multiple records into a table using Postgres' bulk COPY. - * - * Throws upon error. - * - * @param table Name of table for import. - * @param records Records in the COPY IN format. - */ - void - bulkInsert(char const* table, std::string const& records) - { - pg_->bulkInsert(table, records); - } -}; - -//----------------------------------------------------------------------------- - -/** Create Postgres connection pool manager. - * - * @param pgConfig Configuration for Postgres. - * @param j Logger object. - * @return Postgres connection pool manager - */ -std::shared_ptr -make_PgPool(Section const& pgConfig, beast::Journal j); - -/** Initialize the Postgres schema. - * - * This function ensures that the database is running the latest version - * of the schema. - * - * @param pool Postgres connection pool manager. - */ -void -initSchema(std::shared_ptr const& pool); - -} // namespace ripple - -#endif // RIPPLE_CORE_PG_H_INCLUDED -#endif // RIPPLED_REPORTING diff --git a/src/xrpld/core/detail/Config.cpp b/src/xrpld/core/detail/Config.cpp index 07d269883e2..885951111c0 100644 --- a/src/xrpld/core/detail/Config.cpp +++ b/src/xrpld/core/detail/Config.cpp @@ -382,11 +382,6 @@ Config::setup( // Update default values load(); - if (exists("reporting")) - { - RUN_REPORTING = true; - RUN_STANDALONE = true; - } { // load() may have set a new value for the dataDir std::string const dbPath(legacy("database_path")); diff --git a/src/xrpld/core/detail/DatabaseCon.cpp b/src/xrpld/core/detail/DatabaseCon.cpp index c23c7491b04..10b34efd41e 100644 --- a/src/xrpld/core/detail/DatabaseCon.cpp +++ b/src/xrpld/core/detail/DatabaseCon.cpp @@ -109,7 +109,6 @@ setup_DatabaseCon(Config const& c, std::optional j) setup.startUp = c.START_UP; setup.standAlone = c.standalone(); - setup.reporting = c.reporting(); setup.dataDir = c.legacy("database_path"); if (!setup.standAlone && setup.dataDir.empty()) { diff --git a/src/xrpld/nodestore/Backend.h b/src/xrpld/nodestore/Backend.h index 85d38ec0a7b..29f37553327 100644 --- a/src/xrpld/nodestore/Backend.h +++ b/src/xrpld/nodestore/Backend.h @@ -39,29 +39,6 @@ namespace NodeStore { class Backend { public: - template - struct Counters - { - Counters() = default; - Counters(Counters const&) = default; - - template - Counters(Counters const& other) - : writeDurationUs(other.writeDurationUs) - , writeRetries(other.writeRetries) - , writesDelayed(other.writesDelayed) - , readRetries(other.readRetries) - , readErrors(other.readErrors) - { - } - - T writeDurationUs = {}; - T writeRetries = {}; - T writesDelayed = {}; - T readRetries = {}; - T readErrors = {}; - }; - /** Destroy the backend. All open files are closed and flushed. If there are batched writes @@ -174,17 +151,6 @@ class Backend /** Returns the number of file descriptors the backend expects to need. */ virtual int fdRequired() const = 0; - - /** Returns read and write stats. - - @note The Counters struct is specific to and only used - by CassandraBackend. - */ - virtual std::optional> - counters() const - { - return std::nullopt; - } }; } // namespace NodeStore diff --git a/src/xrpld/nodestore/Database.h b/src/xrpld/nodestore/Database.h index daf0483e890..bd25046fee2 100644 --- a/src/xrpld/nodestore/Database.h +++ b/src/xrpld/nodestore/Database.h @@ -302,17 +302,6 @@ class Database virtual void for_each(std::function)> f) = 0; - /** Retrieve backend read and write stats. - - @note The Counters struct is specific to and only used - by CassandraBackend. - */ - virtual std::optional> - getCounters() const - { - return std::nullopt; - } - void threadEntry(); }; diff --git a/src/xrpld/nodestore/backend/CassandraFactory.cpp b/src/xrpld/nodestore/backend/CassandraFactory.cpp deleted file mode 100644 index c53e7709587..00000000000 --- a/src/xrpld/nodestore/backend/CassandraFactory.cpp +++ /dev/null @@ -1,983 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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. -*/ -//============================================================================== - -#ifdef RIPPLED_REPORTING - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ripple { -namespace NodeStore { - -void -writeCallback(CassFuture* fut, void* cbData); -void -readCallback(CassFuture* fut, void* cbData); - -class CassandraBackend : public Backend -{ -private: - // convenience function for one-off queries. For normal reads and writes, - // use the prepared statements insert_ and select_ - CassStatement* - makeStatement(char const* query, std::size_t params) - { - CassStatement* ret = cass_statement_new(query, params); - CassError rc = - cass_statement_set_consistency(ret, CASS_CONSISTENCY_QUORUM); - if (rc != CASS_OK) - { - std::stringstream ss; - ss << "nodestore: Error setting query consistency: " << query - << ", result: " << rc << ", " << cass_error_desc(rc); - Throw(ss.str()); - } - return ret; - } - - beast::Journal const j_; - // size of a key - size_t const keyBytes_; - - Section const config_; - - std::atomic open_{false}; - - // mutex used for open() and close() - std::mutex mutex_; - - std::unique_ptr session_{ - nullptr, - [](CassSession* session) { - // Try to disconnect gracefully. - CassFuture* fut = cass_session_close(session); - cass_future_wait(fut); - cass_future_free(fut); - cass_session_free(session); - }}; - - // Database statements cached server side. Using these is more efficient - // than making a new statement - const CassPrepared* insert_ = nullptr; - const CassPrepared* select_ = nullptr; - - // io_context used for exponential backoff for write retries - boost::asio::io_context ioContext_; - std::optional work_; - std::thread ioThread_; - - // maximum number of concurrent in flight requests. New requests will wait - // for earlier requests to finish if this limit is exceeded - uint32_t maxRequestsOutstanding = 10000000; - std::atomic_uint32_t numRequestsOutstanding_ = 0; - - // mutex and condition_variable to limit the number of concurrent in flight - // requests - std::mutex throttleMutex_; - std::condition_variable throttleCv_; - - // writes are asynchronous. This mutex and condition_variable is used to - // wait for all writes to finish - std::mutex syncMutex_; - std::condition_variable syncCv_; - - Counters> counters_; - -public: - CassandraBackend( - size_t keyBytes, - Section const& keyValues, - beast::Journal journal) - : j_(journal), keyBytes_(keyBytes), config_(keyValues) - { - } - - ~CassandraBackend() override - { - close(); - } - - std::string - getName() override - { - return "cassandra"; - } - - bool - isOpen() override - { - return open_; - } - - // Setup all of the necessary components for talking to the database. - // Create the table if it doesn't exist already - // @param createIfMissing ignored - void - open(bool createIfMissing) override - { - if (open_) - { - assert(false); - JLOG(j_.error()) << "database is already open"; - return; - } - - std::lock_guard lock(mutex_); - CassCluster* cluster = cass_cluster_new(); - if (!cluster) - Throw( - "nodestore:: Failed to create CassCluster"); - - std::string secureConnectBundle = get(config_, "secure_connect_bundle"); - - if (!secureConnectBundle.empty()) - { - /* Setup driver to connect to the cloud using the secure connection - * bundle */ - if (cass_cluster_set_cloud_secure_connection_bundle( - cluster, secureConnectBundle.c_str()) != CASS_OK) - { - JLOG(j_.error()) << "Unable to configure cloud using the " - "secure connection bundle: " - << secureConnectBundle; - Throw( - "nodestore: Failed to connect using secure connection " - "bundle"); - return; - } - } - else - { - std::string contact_points = get(config_, "contact_points"); - if (contact_points.empty()) - { - Throw( - "nodestore: Missing contact_points in Cassandra config"); - } - CassError rc = cass_cluster_set_contact_points( - cluster, contact_points.c_str()); - if (rc != CASS_OK) - { - std::stringstream ss; - ss << "nodestore: Error setting Cassandra contact_points: " - << contact_points << ", result: " << rc << ", " - << cass_error_desc(rc); - - Throw(ss.str()); - } - - int port = get(config_, "port"); - if (port) - { - rc = cass_cluster_set_port(cluster, port); - if (rc != CASS_OK) - { - std::stringstream ss; - ss << "nodestore: Error setting Cassandra port: " << port - << ", result: " << rc << ", " << cass_error_desc(rc); - - Throw(ss.str()); - } - } - } - cass_cluster_set_token_aware_routing(cluster, cass_true); - CassError rc = cass_cluster_set_protocol_version( - cluster, CASS_PROTOCOL_VERSION_V4); - if (rc != CASS_OK) - { - std::stringstream ss; - ss << "nodestore: Error setting cassandra protocol version: " - << ", result: " << rc << ", " << cass_error_desc(rc); - - Throw(ss.str()); - } - - std::string username = get(config_, "username"); - if (username.size()) - { - std::cout << "user = " << username - << " password = " << get(config_, "password") - << std::endl; - cass_cluster_set_credentials( - cluster, username.c_str(), get(config_, "password").c_str()); - } - - unsigned int const ioThreads = get(config_, "io_threads", 4); - maxRequestsOutstanding = - get(config_, "max_requests_outstanding", 10000000); - JLOG(j_.info()) << "Configuring Cassandra driver to use " << ioThreads - << " IO threads. Capping maximum pending requests at " - << maxRequestsOutstanding; - rc = cass_cluster_set_num_threads_io(cluster, ioThreads); - if (rc != CASS_OK) - { - std::stringstream ss; - ss << "nodestore: Error setting Cassandra io threads to " - << ioThreads << ", result: " << rc << ", " - << cass_error_desc(rc); - Throw(ss.str()); - } - - rc = cass_cluster_set_queue_size_io( - cluster, - maxRequestsOutstanding); // This number needs to scale w/ the - // number of request per sec - if (rc != CASS_OK) - { - std::stringstream ss; - ss << "nodestore: Error setting Cassandra max core connections per " - "host" - << ", result: " << rc << ", " << cass_error_desc(rc); - std::cout << ss.str() << std::endl; - return; - ; - } - cass_cluster_set_request_timeout(cluster, 2000); - - std::string certfile = get(config_, "certfile"); - if (certfile.size()) - { - std::ifstream fileStream( - boost::filesystem::path(certfile).string(), std::ios::in); - if (!fileStream) - { - std::stringstream ss; - ss << "opening config file " << certfile; - Throw( - errno, std::generic_category(), ss.str()); - } - std::string cert( - std::istreambuf_iterator{fileStream}, - std::istreambuf_iterator{}); - if (fileStream.bad()) - { - std::stringstream ss; - ss << "reading config file " << certfile; - Throw( - errno, std::generic_category(), ss.str()); - } - - CassSsl* context = cass_ssl_new(); - cass_ssl_set_verify_flags(context, CASS_SSL_VERIFY_NONE); - rc = cass_ssl_add_trusted_cert(context, cert.c_str()); - if (rc != CASS_OK) - { - std::stringstream ss; - ss << "nodestore: Error setting Cassandra ssl context: " << rc - << ", " << cass_error_desc(rc); - Throw(ss.str()); - } - - cass_cluster_set_ssl(cluster, context); - cass_ssl_free(context); - } - - std::string keyspace = get(config_, "keyspace"); - if (keyspace.empty()) - { - Throw( - "nodestore: Missing keyspace in Cassandra config"); - } - - std::string tableName = get(config_, "table_name"); - if (tableName.empty()) - { - Throw( - "nodestore: Missing table name in Cassandra config"); - } - - cass_cluster_set_connect_timeout(cluster, 10000); - - CassStatement* statement; - CassFuture* fut; - bool setupSessionAndTable = false; - while (!setupSessionAndTable) - { - std::this_thread::sleep_for(std::chrono::seconds(1)); - session_.reset(cass_session_new()); - assert(session_); - - fut = cass_session_connect_keyspace( - session_.get(), cluster, keyspace.c_str()); - rc = cass_future_error_code(fut); - cass_future_free(fut); - if (rc != CASS_OK) - { - std::stringstream ss; - ss << "nodestore: Error connecting Cassandra session keyspace: " - << rc << ", " << cass_error_desc(rc); - JLOG(j_.error()) << ss.str(); - continue; - } - - std::stringstream query; - query << "CREATE TABLE IF NOT EXISTS " << tableName - << " ( hash blob PRIMARY KEY, object blob)"; - - statement = makeStatement(query.str().c_str(), 0); - fut = cass_session_execute(session_.get(), statement); - rc = cass_future_error_code(fut); - cass_future_free(fut); - cass_statement_free(statement); - if (rc != CASS_OK && rc != CASS_ERROR_SERVER_INVALID_QUERY) - { - std::stringstream ss; - ss << "nodestore: Error creating Cassandra table: " << rc - << ", " << cass_error_desc(rc); - JLOG(j_.error()) << ss.str(); - continue; - } - - query.str(""); - query << "SELECT * FROM " << tableName << " LIMIT 1"; - statement = makeStatement(query.str().c_str(), 0); - fut = cass_session_execute(session_.get(), statement); - rc = cass_future_error_code(fut); - cass_future_free(fut); - cass_statement_free(statement); - if (rc != CASS_OK) - { - if (rc == CASS_ERROR_SERVER_INVALID_QUERY) - { - JLOG(j_.warn()) << "table not here yet, sleeping 1s to " - "see if table creation propagates"; - continue; - } - else - { - std::stringstream ss; - ss << "nodestore: Error checking for table: " << rc << ", " - << cass_error_desc(rc); - JLOG(j_.error()) << ss.str(); - continue; - } - } - - setupSessionAndTable = true; - } - - cass_cluster_free(cluster); - - bool setupPreparedStatements = false; - while (!setupPreparedStatements) - { - std::this_thread::sleep_for(std::chrono::seconds(1)); - std::stringstream query; - query << "INSERT INTO " << tableName - << " (hash, object) VALUES (?, ?)"; - CassFuture* prepare_future = - cass_session_prepare(session_.get(), query.str().c_str()); - - /* Wait for the statement to prepare and get the result */ - rc = cass_future_error_code(prepare_future); - - if (rc != CASS_OK) - { - /* Handle error */ - cass_future_free(prepare_future); - - std::stringstream ss; - ss << "nodestore: Error preparing insert : " << rc << ", " - << cass_error_desc(rc); - JLOG(j_.error()) << ss.str(); - continue; - } - - /* Get the prepared object from the future */ - insert_ = cass_future_get_prepared(prepare_future); - - /* The future can be freed immediately after getting the prepared - * object - */ - cass_future_free(prepare_future); - - query.str(""); - query << "SELECT object FROM " << tableName << " WHERE hash = ?"; - prepare_future = - cass_session_prepare(session_.get(), query.str().c_str()); - - /* Wait for the statement to prepare and get the result */ - rc = cass_future_error_code(prepare_future); - - if (rc != CASS_OK) - { - /* Handle error */ - cass_future_free(prepare_future); - - std::stringstream ss; - ss << "nodestore: Error preparing select : " << rc << ", " - << cass_error_desc(rc); - JLOG(j_.error()) << ss.str(); - continue; - } - - /* Get the prepared object from the future */ - select_ = cass_future_get_prepared(prepare_future); - - /* The future can be freed immediately after getting the prepared - * object - */ - cass_future_free(prepare_future); - setupPreparedStatements = true; - } - - work_.emplace(ioContext_); - ioThread_ = std::thread{[this]() { ioContext_.run(); }}; - open_ = true; - } - - // Close the connection to the database - void - close() override - { - { - std::lock_guard lock(mutex_); - if (insert_) - { - cass_prepared_free(insert_); - insert_ = nullptr; - } - if (select_) - { - cass_prepared_free(select_); - select_ = nullptr; - } - work_.reset(); - ioThread_.join(); - } - open_ = false; - } - - // Synchronously fetch the object with key key and store the result in pno - // @param key the key of the object - // @param pno object in which to store the result - // @return result status of query - Status - fetch(void const* key, std::shared_ptr* pno) override - { - JLOG(j_.trace()) << "Fetching from cassandra"; - CassStatement* statement = cass_prepared_bind(select_); - cass_statement_set_consistency(statement, CASS_CONSISTENCY_QUORUM); - CassError rc = cass_statement_bind_bytes( - statement, 0, static_cast(key), keyBytes_); - if (rc != CASS_OK) - { - cass_statement_free(statement); - JLOG(j_.error()) << "Binding Cassandra fetch query: " << rc << ", " - << cass_error_desc(rc); - pno->reset(); - return backendError; - } - CassFuture* fut; - do - { - fut = cass_session_execute(session_.get(), statement); - rc = cass_future_error_code(fut); - if (rc != CASS_OK) - { - std::stringstream ss; - ss << "Cassandra fetch error"; - ss << ", retrying"; - ++counters_.readRetries; - ss << ": " << cass_error_desc(rc); - JLOG(j_.warn()) << ss.str(); - } - } while (rc != CASS_OK); - - CassResult const* res = cass_future_get_result(fut); - cass_statement_free(statement); - cass_future_free(fut); - - CassRow const* row = cass_result_first_row(res); - if (!row) - { - cass_result_free(res); - pno->reset(); - return notFound; - } - cass_byte_t const* buf; - std::size_t bufSize; - rc = cass_value_get_bytes(cass_row_get_column(row, 0), &buf, &bufSize); - if (rc != CASS_OK) - { - cass_result_free(res); - pno->reset(); - JLOG(j_.error()) << "Cassandra fetch result error: " << rc << ", " - << cass_error_desc(rc); - ++counters_.readErrors; - return backendError; - } - - nudb::detail::buffer bf; - std::pair uncompressed = - nodeobject_decompress(buf, bufSize, bf); - DecodedBlob decoded(key, uncompressed.first, uncompressed.second); - cass_result_free(res); - - if (!decoded.wasOk()) - { - pno->reset(); - JLOG(j_.error()) << "Cassandra error decoding result: " << rc - << ", " << cass_error_desc(rc); - ++counters_.readErrors; - return dataCorrupt; - } - *pno = decoded.createObject(); - return ok; - } - - struct ReadCallbackData - { - CassandraBackend& backend; - const void* const key; - std::shared_ptr& result; - std::condition_variable& cv; - - std::atomic_uint32_t& numFinished; - size_t batchSize; - - ReadCallbackData( - CassandraBackend& backend, - const void* const key, - std::shared_ptr& result, - std::condition_variable& cv, - std::atomic_uint32_t& numFinished, - size_t batchSize) - : backend(backend) - , key(key) - , result(result) - , cv(cv) - , numFinished(numFinished) - , batchSize(batchSize) - { - } - - ReadCallbackData(ReadCallbackData const& other) = default; - }; - - std::pair>, Status> - fetchBatch(std::vector const& hashes) override - { - std::size_t const numHashes = hashes.size(); - JLOG(j_.trace()) << "Fetching " << numHashes - << " records from Cassandra"; - std::atomic_uint32_t numFinished = 0; - std::condition_variable cv; - std::mutex mtx; - std::vector> results{numHashes}; - std::vector> cbs; - cbs.reserve(numHashes); - for (std::size_t i = 0; i < hashes.size(); ++i) - { - cbs.push_back(std::make_shared( - *this, - static_cast(hashes[i]), - results[i], - cv, - numFinished, - numHashes)); - read(*cbs[i]); - } - assert(results.size() == cbs.size()); - - std::unique_lock lck(mtx); - cv.wait(lck, [&numFinished, &numHashes]() { - return numFinished == numHashes; - }); - - JLOG(j_.trace()) << "Fetched " << numHashes - << " records from Cassandra"; - return {results, ok}; - } - - void - read(ReadCallbackData& data) - { - CassStatement* statement = cass_prepared_bind(select_); - cass_statement_set_consistency(statement, CASS_CONSISTENCY_QUORUM); - CassError rc = cass_statement_bind_bytes( - statement, 0, static_cast(data.key), keyBytes_); - if (rc != CASS_OK) - { - size_t batchSize = data.batchSize; - if (++(data.numFinished) == batchSize) - data.cv.notify_all(); - cass_statement_free(statement); - JLOG(j_.error()) << "Binding Cassandra fetch query: " << rc << ", " - << cass_error_desc(rc); - return; - } - - CassFuture* fut = cass_session_execute(session_.get(), statement); - - cass_statement_free(statement); - - cass_future_set_callback(fut, readCallback, static_cast(&data)); - cass_future_free(fut); - } - - struct WriteCallbackData - { - CassandraBackend* backend; - // The shared pointer to the node object must exist until it's - // confirmed persisted. Otherwise, it can become deleted - // prematurely if other copies are removed from caches. - std::shared_ptr no; - std::optional e; - std::pair compressed; - std::chrono::steady_clock::time_point begin; - // The data is stored in this buffer. The void* in the above member - // is a pointer into the below buffer - nudb::detail::buffer bf; - std::atomic& totalWriteRetries; - - uint32_t currentRetries = 0; - - WriteCallbackData( - CassandraBackend* f, - std::shared_ptr const& nobj, - std::atomic& retries) - : backend(f), no(nobj), totalWriteRetries(retries) - { - e.emplace(no); - - compressed = - NodeStore::nodeobject_compress(e->getData(), e->getSize(), bf); - } - }; - - void - write(WriteCallbackData& data, bool isRetry) - { - { - // We limit the total number of concurrent inflight writes. This is - // a client side throttling to prevent overloading the database. - // This is mostly useful when the very first ledger is being written - // in full, which is several millions records. On sufficiently large - // Cassandra clusters, this throttling is not needed; the default - // value of maxRequestsOutstanding is 10 million, which is more - // records than are present in any single ledger - std::unique_lock lck(throttleMutex_); - if (!isRetry && numRequestsOutstanding_ > maxRequestsOutstanding) - { - JLOG(j_.trace()) << __func__ << " : " - << "Max outstanding requests reached. " - << "Waiting for other requests to finish"; - ++counters_.writesDelayed; - throttleCv_.wait(lck, [this]() { - return numRequestsOutstanding_ < maxRequestsOutstanding; - }); - } - } - - CassStatement* statement = cass_prepared_bind(insert_); - cass_statement_set_consistency(statement, CASS_CONSISTENCY_QUORUM); - CassError rc = cass_statement_bind_bytes( - statement, - 0, - static_cast(data.e->getKey()), - keyBytes_); - if (rc != CASS_OK) - { - cass_statement_free(statement); - std::stringstream ss; - ss << "Binding cassandra insert hash: " << rc << ", " - << cass_error_desc(rc); - JLOG(j_.error()) << __func__ << " : " << ss.str(); - Throw(ss.str()); - } - rc = cass_statement_bind_bytes( - statement, - 1, - static_cast(data.compressed.first), - data.compressed.second); - if (rc != CASS_OK) - { - cass_statement_free(statement); - std::stringstream ss; - ss << "Binding cassandra insert object: " << rc << ", " - << cass_error_desc(rc); - JLOG(j_.error()) << __func__ << " : " << ss.str(); - Throw(ss.str()); - } - data.begin = std::chrono::steady_clock::now(); - CassFuture* fut = cass_session_execute(session_.get(), statement); - cass_statement_free(statement); - - cass_future_set_callback(fut, writeCallback, static_cast(&data)); - cass_future_free(fut); - } - - void - store(std::shared_ptr const& no) override - { - JLOG(j_.trace()) << "Writing to cassandra"; - WriteCallbackData* data = - new WriteCallbackData(this, no, counters_.writeRetries); - - ++numRequestsOutstanding_; - write(*data, false); - } - - void - storeBatch(Batch const& batch) override - { - for (auto const& no : batch) - { - store(no); - } - } - - void - sync() override - { - std::unique_lock lck(syncMutex_); - - syncCv_.wait(lck, [this]() { return numRequestsOutstanding_ == 0; }); - } - - // Iterate through entire table and execute f(). Used for import only, - // with database not being written to, so safe to paginate through - // objects table with LIMIT x OFFSET y. - void - for_each(std::function)> f) override - { - assert(false); - Throw("not implemented"); - } - - int - getWriteLoad() override - { - return 0; - } - - void - setDeletePath() override - { - } - - int - fdRequired() const override - { - return 0; - } - - std::optional> - counters() const override - { - return counters_; - } - - friend void - writeCallback(CassFuture* fut, void* cbData); - - friend void - readCallback(CassFuture* fut, void* cbData); -}; - -// Process the result of an asynchronous read. Retry on error -// @param fut cassandra future associated with the read -// @param cbData struct that holds the request parameters -void -readCallback(CassFuture* fut, void* cbData) -{ - CassandraBackend::ReadCallbackData& requestParams = - *static_cast(cbData); - - CassError rc = cass_future_error_code(fut); - - if (rc != CASS_OK) - { - ++(requestParams.backend.counters_.readRetries); - JLOG(requestParams.backend.j_.warn()) - << "Cassandra fetch error : " << rc << " : " << cass_error_desc(rc) - << " - retrying"; - // Retry right away. The only time the cluster should ever be overloaded - // is when the very first ledger is being written in full (millions of - // writes at once), during which no reads should be occurring. If reads - // are timing out, the code/architecture should be modified to handle - // greater read load, as opposed to just exponential backoff - requestParams.backend.read(requestParams); - } - else - { - auto finish = [&requestParams]() { - size_t batchSize = requestParams.batchSize; - if (++(requestParams.numFinished) == batchSize) - requestParams.cv.notify_all(); - }; - CassResult const* res = cass_future_get_result(fut); - - CassRow const* row = cass_result_first_row(res); - if (!row) - { - cass_result_free(res); - JLOG(requestParams.backend.j_.error()) - << "Cassandra fetch get row error : " << rc << ", " - << cass_error_desc(rc); - finish(); - return; - } - cass_byte_t const* buf; - std::size_t bufSize; - rc = cass_value_get_bytes(cass_row_get_column(row, 0), &buf, &bufSize); - if (rc != CASS_OK) - { - cass_result_free(res); - JLOG(requestParams.backend.j_.error()) - << "Cassandra fetch get bytes error : " << rc << ", " - << cass_error_desc(rc); - ++requestParams.backend.counters_.readErrors; - finish(); - return; - } - nudb::detail::buffer bf; - std::pair uncompressed = - nodeobject_decompress(buf, bufSize, bf); - DecodedBlob decoded( - requestParams.key, uncompressed.first, uncompressed.second); - cass_result_free(res); - - if (!decoded.wasOk()) - { - JLOG(requestParams.backend.j_.fatal()) - << "Cassandra fetch error - data corruption : " << rc << ", " - << cass_error_desc(rc); - ++requestParams.backend.counters_.readErrors; - finish(); - return; - } - requestParams.result = decoded.createObject(); - finish(); - } -} - -// Process the result of an asynchronous write. Retry on error -// @param fut cassandra future associated with the write -// @param cbData struct that holds the request parameters -void -writeCallback(CassFuture* fut, void* cbData) -{ - CassandraBackend::WriteCallbackData& requestParams = - *static_cast(cbData); - CassandraBackend& backend = *requestParams.backend; - auto rc = cass_future_error_code(fut); - if (rc != CASS_OK) - { - JLOG(backend.j_.error()) - << "ERROR!!! Cassandra insert error: " << rc << ", " - << cass_error_desc(rc) << ", retrying "; - ++requestParams.totalWriteRetries; - // exponential backoff with a max wait of 2^10 ms (about 1 second) - auto wait = std::chrono::milliseconds( - lround(std::pow(2, std::min(10u, requestParams.currentRetries)))); - ++requestParams.currentRetries; - std::shared_ptr timer = - std::make_shared( - backend.ioContext_, std::chrono::steady_clock::now() + wait); - timer->async_wait([timer, &requestParams, &backend]( - const boost::system::error_code& error) { - backend.write(requestParams, true); - }); - } - else - { - backend.counters_.writeDurationUs += - std::chrono::duration_cast( - std::chrono::steady_clock::now() - requestParams.begin) - .count(); - --(backend.numRequestsOutstanding_); - - backend.throttleCv_.notify_all(); - if (backend.numRequestsOutstanding_ == 0) - backend.syncCv_.notify_all(); - delete &requestParams; - } -} - -//------------------------------------------------------------------------------ - -class CassandraFactory : public Factory -{ -public: - CassandraFactory() - { - Manager::instance().insert(*this); - } - - ~CassandraFactory() override - { - Manager::instance().erase(*this); - } - - std::string - getName() const override - { - return "cassandra"; - } - - std::unique_ptr - createInstance( - size_t keyBytes, - Section const& keyValues, - std::size_t burstSize, - Scheduler& scheduler, - beast::Journal journal) override - { - return std::make_unique(keyBytes, keyValues, journal); - } -}; - -static CassandraFactory cassandraFactory; - -} // namespace NodeStore -} // namespace ripple -#endif diff --git a/src/xrpld/nodestore/detail/Database.cpp b/src/xrpld/nodestore/detail/Database.cpp index 60cfb35051c..da15088e895 100644 --- a/src/xrpld/nodestore/detail/Database.cpp +++ b/src/xrpld/nodestore/detail/Database.cpp @@ -273,15 +273,6 @@ Database::getCountsJson(Json::Value& obj) obj[jss::node_written_bytes] = std::to_string(storeSz_); obj[jss::node_read_bytes] = std::to_string(fetchSz_); obj[jss::node_reads_duration_us] = std::to_string(fetchDurationUs_); - - if (auto c = getCounters()) - { - obj[jss::node_read_errors] = std::to_string(c->readErrors); - obj[jss::node_read_retries] = std::to_string(c->readRetries); - obj[jss::node_write_retries] = std::to_string(c->writeRetries); - obj[jss::node_writes_delayed] = std::to_string(c->writesDelayed); - obj[jss::node_writes_duration_us] = std::to_string(c->writeDurationUs); - } } } // namespace NodeStore diff --git a/src/xrpld/nodestore/detail/DatabaseNodeImp.h b/src/xrpld/nodestore/detail/DatabaseNodeImp.h index c2bf237b943..b8a9a3fa2b4 100644 --- a/src/xrpld/nodestore/detail/DatabaseNodeImp.h +++ b/src/xrpld/nodestore/detail/DatabaseNodeImp.h @@ -150,12 +150,6 @@ class DatabaseNodeImp : public Database { backend_->for_each(f); } - - std::optional> - getCounters() const override - { - return backend_->counters(); - } }; } // namespace NodeStore diff --git a/src/xrpld/nodestore/detail/ManagerImp.cpp b/src/xrpld/nodestore/detail/ManagerImp.cpp index 019dd1f8122..56dc66ee644 100644 --- a/src/xrpld/nodestore/detail/ManagerImp.cpp +++ b/src/xrpld/nodestore/detail/ManagerImp.cpp @@ -55,12 +55,6 @@ ManagerImp::make_Backend( auto factory{find(type)}; if (!factory) { -#ifndef RIPPLED_REPORTING - if (boost::iequals(type, "cassandra")) - Throw( - "To use Cassandra as a nodestore, build rippled with " - "-Dreporting=ON"); -#endif missing_backend(); } diff --git a/src/xrpld/rpc/detail/DeliveredAmount.cpp b/src/xrpld/rpc/detail/DeliveredAmount.cpp index 7874997e24f..93af8599146 100644 --- a/src/xrpld/rpc/detail/DeliveredAmount.cpp +++ b/src/xrpld/rpc/detail/DeliveredAmount.cpp @@ -119,20 +119,10 @@ canHaveDeliveredAmount( { // These lambdas are used to compute the values lazily auto const getFix1623Enabled = [&context]() -> bool { - if (context.app.config().reporting()) - { - auto const view = context.ledgerMaster.getValidatedLedger(); - if (!view) - return false; - return view->rules().enabled(fix1623); - } - else - { - auto const view = context.app.openLedger().current(); - if (!view) - return false; - return view->rules().enabled(fix1623); - } + auto const view = context.app.openLedger().current(); + if (!view) + return false; + return view->rules().enabled(fix1623); }; return canHaveDeliveredAmountHelp( diff --git a/src/xrpld/rpc/detail/Handler.cpp b/src/xrpld/rpc/detail/Handler.cpp index d4a3fda380f..90dee4475a1 100644 --- a/src/xrpld/rpc/detail/Handler.cpp +++ b/src/xrpld/rpc/detail/Handler.cpp @@ -106,11 +106,7 @@ Handler const handlerArray[]{ {"feature", byRef(&doFeature), Role::USER, NO_CONDITION}, {"fee", byRef(&doFee), Role::USER, NEEDS_CURRENT_LEDGER}, {"fetch_info", byRef(&doFetchInfo), Role::ADMIN, NO_CONDITION}, -#ifdef RIPPLED_REPORTING - {"gateway_balances", byRef(&doGatewayBalances), Role::ADMIN, NO_CONDITION}, -#else {"gateway_balances", byRef(&doGatewayBalances), Role::USER, NO_CONDITION}, -#endif {"get_counts", byRef(&doGetCounts), Role::ADMIN, NO_CONDITION}, {"get_aggregate_price", byRef(&doGetAggregatePrice), diff --git a/src/xrpld/rpc/detail/Handler.h b/src/xrpld/rpc/detail/Handler.h index 81fbc2be321..cb1a2579ecb 100644 --- a/src/xrpld/rpc/detail/Handler.h +++ b/src/xrpld/rpc/detail/Handler.h @@ -81,22 +81,6 @@ template error_code_i conditionMet(Condition condition_required, T& context) { - if (context.app.config().reporting()) - { - if (condition_required == NEEDS_CURRENT_LEDGER) - { - return rpcNO_CURRENT; - } - else if (condition_required == NEEDS_CLOSED_LEDGER) - { - return rpcNO_CLOSED; - } - else - { - return rpcSUCCESS; - } - } - if (context.app.getOPs().isAmendmentBlocked() && (condition_required != NO_CONDITION)) { diff --git a/src/xrpld/rpc/detail/RPCHandler.cpp b/src/xrpld/rpc/detail/RPCHandler.cpp index 8504fe72a83..19b33709c83 100644 --- a/src/xrpld/rpc/detail/RPCHandler.cpp +++ b/src/xrpld/rpc/detail/RPCHandler.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -206,11 +205,6 @@ callMethod( perfLog.rpcFinish(name, curId); return ret; } - catch (ReportingShouldProxy&) - { - result = forwardToP2p(context); - return rpcSUCCESS; - } catch (std::exception& e) { perfLog.rpcError(name, curId); @@ -226,36 +220,9 @@ callMethod( } // namespace -void -injectReportingWarning(RPC::JsonContext& context, Json::Value& result) -{ - if (context.app.config().reporting()) - { - Json::Value warnings{Json::arrayValue}; - Json::Value& w = warnings.append(Json::objectValue); - w[jss::id] = warnRPC_REPORTING; - w[jss::message] = - "This is a reporting server. " - " The default behavior of a reporting server is to only" - " return validated data. If you are looking for not yet" - " validated data, include \"ledger_index : current\"" - " in your request, which will cause this server to forward" - " the request to a p2p node. If the forward is successful" - " the response will include \"forwarded\" : \"true\""; - result[jss::warnings] = std::move(warnings); - } -} - Status doCommand(RPC::JsonContext& context, Json::Value& result) { - if (shouldForwardToP2p(context)) - { - result = forwardToP2p(context); - injectReportingWarning(context, result); - // this return value is ignored - return rpcSUCCESS; - } Handler const* handler = nullptr; if (auto error = fillHandler(context, handler)) { @@ -285,7 +252,6 @@ doCommand(RPC::JsonContext& context, Json::Value& result) else { auto ret = callMethod(context, method, handler->name_, result); - injectReportingWarning(context, result); return ret; } } diff --git a/src/xrpld/rpc/detail/RPCHelpers.cpp b/src/xrpld/rpc/detail/RPCHelpers.cpp index 71513ddcd5c..fa66fecfbba 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.cpp +++ b/src/xrpld/rpc/detail/RPCHelpers.cpp @@ -329,9 +329,9 @@ getAccountObjects( namespace { bool -isValidatedOld(LedgerMaster& ledgerMaster, bool standaloneOrReporting) +isValidatedOld(LedgerMaster& ledgerMaster, bool standalone) { - if (standaloneOrReporting) + if (standalone) return false; return ledgerMaster.getValidatedLedgerAge() > Tuning::maxValidatedLedgerAge; @@ -371,12 +371,10 @@ ledgerFromRequest(T& ledger, JsonContext& context) auto const index = indexValue.asString(); - if (index == "current" || - (index.empty() && !context.app.config().reporting())) + if (index == "current" || index.empty()) return getLedger(ledger, LedgerShortcut::CURRENT, context); - if (index == "validated" || - (index.empty() && context.app.config().reporting())) + if (index == "validated") return getLedger(ledger, LedgerShortcut::VALIDATED, context); if (index == "closed") @@ -442,13 +440,8 @@ ledgerFromSpecifier( [[fallthrough]]; case LedgerCase::LEDGER_NOT_SET: { auto const shortcut = specifier.shortcut(); - // note, unspecified defaults to validated in reporting mode if (shortcut == - org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED || - (shortcut == - org::xrpl::rpc::v1::LedgerSpecifier:: - SHORTCUT_UNSPECIFIED && - context.app.config().reporting())) + org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED) { return getLedger(ledger, LedgerShortcut::VALIDATED, context); } @@ -492,8 +485,6 @@ getLedger(T& ledger, uint32_t ledgerIndex, Context& context) ledger = context.ledgerMaster.getLedgerBySeq(ledgerIndex); if (ledger == nullptr) { - if (context.app.config().reporting()) - return {rpcLGR_NOT_FOUND, "ledgerNotFound"}; auto cur = context.ledgerMaster.getCurrentLedger(); if (cur->info().seq == ledgerIndex) { @@ -520,10 +511,7 @@ template Status getLedger(T& ledger, LedgerShortcut shortcut, Context& context) { - if (isValidatedOld( - context.ledgerMaster, - context.app.config().standalone() || - context.app.config().reporting())) + if (isValidatedOld(context.ledgerMaster, context.app.config().standalone())) { if (context.apiVersion == 1) return {rpcNO_NETWORK, "InsufficientNetworkMode"}; @@ -546,18 +534,11 @@ getLedger(T& ledger, LedgerShortcut shortcut, Context& context) { if (shortcut == LedgerShortcut::CURRENT) { - if (context.app.config().reporting()) - return { - rpcLGR_NOT_FOUND, - "Reporting does not track current ledger"}; ledger = context.ledgerMaster.getCurrentLedger(); assert(ledger->open()); } else if (shortcut == LedgerShortcut::CLOSED) { - if (context.app.config().reporting()) - return { - rpcLGR_NOT_FOUND, "Reporting does not track closed ledger"}; ledger = context.ledgerMaster.getClosedLedger(); assert(!ledger->open()); } @@ -1030,9 +1011,6 @@ getAPIVersionNumber(Json::Value const& jv, bool betaEnabled) std::variant, Json::Value> getLedgerByContext(RPC::JsonContext& context) { - if (context.app.config().reporting()) - return rpcError(rpcREPORTING_UNSUPPORTED); - auto const hasHash = context.params.isMember(jss::ledger_hash); auto const hasIndex = context.params.isMember(jss::ledger_index); std::uint32_t ledgerIndex = 0; diff --git a/src/xrpld/rpc/detail/TransactionSign.cpp b/src/xrpld/rpc/detail/TransactionSign.cpp index 1fee84c683b..65ee50c0891 100644 --- a/src/xrpld/rpc/detail/TransactionSign.cpp +++ b/src/xrpld/rpc/detail/TransactionSign.cpp @@ -827,11 +827,7 @@ transactionSign( if (!preprocResult.second) return preprocResult.first; - std::shared_ptr ledger; - if (app.config().reporting()) - ledger = app.getLedgerMaster().getValidatedLedger(); - else - ledger = app.openLedger().current(); + std::shared_ptr ledger = app.openLedger().current(); // Make sure the STTx makes a legitimate Transaction. std::pair txn = transactionConstructImpl(preprocResult.second, ledger->rules(), app); diff --git a/src/xrpld/rpc/handlers/AccountTx.cpp b/src/xrpld/rpc/handlers/AccountTx.cpp index 3b9165eecf1..a85abd86682 100644 --- a/src/xrpld/rpc/handlers/AccountTx.cpp +++ b/src/xrpld/rpc/handlers/AccountTx.cpp @@ -22,9 +22,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -218,16 +216,6 @@ std::pair doAccountTxHelp(RPC::Context& context, AccountTxArgs const& args) { context.loadType = Resource::feeMediumBurdenRPC; - if (context.app.config().reporting()) - { - auto const db = dynamic_cast( - &context.app.getRelationalDatabase()); - - if (!db) - Throw("Failed to get relational database"); - - return db->getAccountTx(args); - } AccountTxResult result; @@ -391,8 +379,6 @@ populateJsonResponse( response[jss::marker][jss::ledger] = result.marker->ledgerSeq; response[jss::marker][jss::seq] = result.marker->txnSeq; } - if (context.app.config().reporting()) - response["used_postgres"] = true; } JLOG(context.j.debug()) << __func__ << " : finished"; diff --git a/src/xrpld/rpc/handlers/CanDelete.cpp b/src/xrpld/rpc/handlers/CanDelete.cpp index db9fdf7c5d0..df2301d03e0 100644 --- a/src/xrpld/rpc/handlers/CanDelete.cpp +++ b/src/xrpld/rpc/handlers/CanDelete.cpp @@ -34,9 +34,6 @@ namespace ripple { Json::Value doCanDelete(RPC::JsonContext& context) { - if (context.app.config().reporting()) - return RPC::make_error(rpcREPORTING_UNSUPPORTED); - if (!context.app.getSHAMapStore().advisoryDelete()) return RPC::make_error(rpcNOT_ENABLED); diff --git a/src/xrpld/rpc/handlers/Connect.cpp b/src/xrpld/rpc/handlers/Connect.cpp index dadf0a0515e..c564319dc8b 100644 --- a/src/xrpld/rpc/handlers/Connect.cpp +++ b/src/xrpld/rpc/handlers/Connect.cpp @@ -37,9 +37,6 @@ namespace ripple { Json::Value doConnect(RPC::JsonContext& context) { - if (context.app.config().reporting()) - return rpcError(rpcREPORTING_UNSUPPORTED); - if (context.app.config().standalone()) return "cannot connect in standalone mode"; diff --git a/src/xrpld/rpc/handlers/ConsensusInfo.cpp b/src/xrpld/rpc/handlers/ConsensusInfo.cpp index 42fbb60ba76..ce727bb4006 100644 --- a/src/xrpld/rpc/handlers/ConsensusInfo.cpp +++ b/src/xrpld/rpc/handlers/ConsensusInfo.cpp @@ -30,9 +30,6 @@ namespace ripple { Json::Value doConsensusInfo(RPC::JsonContext& context) { - if (context.app.config().reporting()) - return rpcError(rpcREPORTING_UNSUPPORTED); - Json::Value ret(Json::objectValue); ret[jss::info] = context.netOps.getConsensusInfo(); diff --git a/src/xrpld/rpc/handlers/Feature1.cpp b/src/xrpld/rpc/handlers/Feature1.cpp index c06756ca00a..75e583a352c 100644 --- a/src/xrpld/rpc/handlers/Feature1.cpp +++ b/src/xrpld/rpc/handlers/Feature1.cpp @@ -35,9 +35,6 @@ namespace ripple { Json::Value doFeature(RPC::JsonContext& context) { - if (context.app.config().reporting()) - return rpcError(rpcREPORTING_UNSUPPORTED); - if (context.params.isMember(jss::feature)) { // ensure that the `feature` param is a string diff --git a/src/xrpld/rpc/handlers/FetchInfo.cpp b/src/xrpld/rpc/handlers/FetchInfo.cpp index 113ae78a35c..a4287266e52 100644 --- a/src/xrpld/rpc/handlers/FetchInfo.cpp +++ b/src/xrpld/rpc/handlers/FetchInfo.cpp @@ -30,9 +30,6 @@ namespace ripple { Json::Value doFetchInfo(RPC::JsonContext& context) { - if (context.app.config().reporting()) - return rpcError(rpcREPORTING_UNSUPPORTED); - Json::Value ret(Json::objectValue); if (context.params.isMember(jss::clear) && diff --git a/src/xrpld/rpc/handlers/GetCounts.cpp b/src/xrpld/rpc/handlers/GetCounts.cpp index 035d698a5d4..690106ebbd2 100644 --- a/src/xrpld/rpc/handlers/GetCounts.cpp +++ b/src/xrpld/rpc/handlers/GetCounts.cpp @@ -71,7 +71,7 @@ getCountsJson(Application& app, int minObjectCount) ret[k] = v; } - if (!app.config().reporting() && app.config().useTxTables()) + if (app.config().useTxTables()) { auto const db = dynamic_cast(&app.getRelationalDatabase()); diff --git a/src/xrpld/rpc/handlers/LedgerAccept.cpp b/src/xrpld/rpc/handlers/LedgerAccept.cpp index 742a84fbb4e..dbd7eb9f1ca 100644 --- a/src/xrpld/rpc/handlers/LedgerAccept.cpp +++ b/src/xrpld/rpc/handlers/LedgerAccept.cpp @@ -36,7 +36,7 @@ doLedgerAccept(RPC::JsonContext& context) { Json::Value jvResult; - if (!context.app.config().standalone() || context.app.config().reporting()) + if (!context.app.config().standalone()) { jvResult[jss::error] = "notStandAlone"; } diff --git a/src/xrpld/rpc/handlers/LedgerHandler.cpp b/src/xrpld/rpc/handlers/LedgerHandler.cpp index 6d695abc85f..2bf4fb09f94 100644 --- a/src/xrpld/rpc/handlers/LedgerHandler.cpp +++ b/src/xrpld/rpc/handlers/LedgerHandler.cpp @@ -40,8 +40,7 @@ LedgerHandler::check() { auto const& params = context_.params; bool needsLedger = params.isMember(jss::ledger) || - params.isMember(jss::ledger_hash) || - params.isMember(jss::ledger_index) || context_.app.config().reporting(); + params.isMember(jss::ledger_hash) || params.isMember(jss::ledger_index); if (!needsLedger) return Status::OK; diff --git a/src/xrpld/rpc/handlers/Manifest.cpp b/src/xrpld/rpc/handlers/Manifest.cpp index 700d6ab39df..1debd48422a 100644 --- a/src/xrpld/rpc/handlers/Manifest.cpp +++ b/src/xrpld/rpc/handlers/Manifest.cpp @@ -29,9 +29,6 @@ namespace ripple { Json::Value doManifest(RPC::JsonContext& context) { - if (context.app.config().reporting()) - return rpcError(rpcREPORTING_UNSUPPORTED); - auto& params = context.params; if (!params.isMember(jss::public_key)) diff --git a/src/xrpld/rpc/handlers/Peers.cpp b/src/xrpld/rpc/handlers/Peers.cpp index 718070ec927..f3be0df558e 100644 --- a/src/xrpld/rpc/handlers/Peers.cpp +++ b/src/xrpld/rpc/handlers/Peers.cpp @@ -31,9 +31,6 @@ namespace ripple { Json::Value doPeers(RPC::JsonContext& context) { - if (context.app.config().reporting()) - return rpcError(rpcREPORTING_UNSUPPORTED); - Json::Value jvResult(Json::objectValue); jvResult[jss::peers] = context.app.overlay().json(); diff --git a/src/xrpld/rpc/handlers/Reservations.cpp b/src/xrpld/rpc/handlers/Reservations.cpp index 57a8fb3664a..1ff2d506afa 100644 --- a/src/xrpld/rpc/handlers/Reservations.cpp +++ b/src/xrpld/rpc/handlers/Reservations.cpp @@ -34,9 +34,6 @@ namespace ripple { Json::Value doPeerReservationsAdd(RPC::JsonContext& context) { - if (context.app.config().reporting()) - return rpcError(rpcREPORTING_UNSUPPORTED); - auto const& params = context.params; if (!params.isMember(jss::public_key)) @@ -90,9 +87,6 @@ doPeerReservationsAdd(RPC::JsonContext& context) Json::Value doPeerReservationsDel(RPC::JsonContext& context) { - if (context.app.config().reporting()) - return rpcError(rpcREPORTING_UNSUPPORTED); - auto const& params = context.params; // We repeat much of the parameter parsing from `doPeerReservationsAdd`. @@ -120,9 +114,6 @@ doPeerReservationsDel(RPC::JsonContext& context) Json::Value doPeerReservationsList(RPC::JsonContext& context) { - if (context.app.config().reporting()) - return rpcError(rpcREPORTING_UNSUPPORTED); - auto const& reservations = context.app.peerReservations().list(); // Enumerate the reservations in context.app.peerReservations() // as a Json::Value. diff --git a/src/xrpld/rpc/handlers/ServerInfo.cpp b/src/xrpld/rpc/handlers/ServerInfo.cpp index 769974985da..72beb37ed64 100644 --- a/src/xrpld/rpc/handlers/ServerInfo.cpp +++ b/src/xrpld/rpc/handlers/ServerInfo.cpp @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -330,14 +329,6 @@ doServerInfo(RPC::JsonContext& context) context.params.isMember(jss::counters) && context.params[jss::counters].asBool()); - if (context.app.config().reporting()) - { - Json::Value const proxied = forwardToP2p(context); - auto const lf = proxied[jss::result][jss::info][jss::load_factor]; - auto const vq = proxied[jss::result][jss::info][jss::validation_quorum]; - ret[jss::info][jss::validation_quorum] = vq.isNull() ? 1 : vq; - ret[jss::info][jss::load_factor] = lf.isNull() ? 1 : lf; - } return ret; } diff --git a/src/xrpld/rpc/handlers/Subscribe.cpp b/src/xrpld/rpc/handlers/Subscribe.cpp index 9f9181e1ab2..66fe89dea04 100644 --- a/src/xrpld/rpc/handlers/Subscribe.cpp +++ b/src/xrpld/rpc/handlers/Subscribe.cpp @@ -128,8 +128,6 @@ doSubscribe(RPC::JsonContext& context) std::string streamName = it.asString(); if (streamName == "server") { - if (context.app.config().reporting()) - return rpcError(rpcREPORTING_UNSUPPORTED); context.netOps.subServer( ispSub, jvResult, context.role == Role::ADMIN); } @@ -161,16 +159,12 @@ doSubscribe(RPC::JsonContext& context) } else if (streamName == "peer_status") { - if (context.app.config().reporting()) - return rpcError(rpcREPORTING_UNSUPPORTED); if (context.role != Role::ADMIN) return rpcError(rpcNO_PERMISSION); context.netOps.subPeerStatus(ispSub); } else if (streamName == "consensus") { - if (context.app.config().reporting()) - return rpcError(rpcREPORTING_UNSUPPORTED); context.netOps.subConsensus(ispSub); } else diff --git a/src/xrpld/rpc/handlers/Tx.cpp b/src/xrpld/rpc/handlers/Tx.cpp index e32d926e566..ba103d186fc 100644 --- a/src/xrpld/rpc/handlers/Tx.cpp +++ b/src/xrpld/rpc/handlers/Tx.cpp @@ -70,128 +70,9 @@ struct TxArgs std::optional> ledgerRange; }; -std::pair -doTxPostgres(RPC::Context& context, TxArgs const& args) -{ - if (!context.app.config().reporting()) - { - assert(false); - Throw( - "Called doTxPostgres yet not in reporting mode"); - } - - TxResult res; - res.searchedAll = TxSearched::unknown; - - if (!args.hash) - return { - res, - {rpcNOT_IMPL, - "Use of CTIDs on reporting mode is not currently supported."}}; - - JLOG(context.j.debug()) << "Fetching from postgres"; - Transaction::Locator locator = - Transaction::locate(*(args.hash), context.app); - - std::pair, std::shared_ptr> - pair; - // database returned the nodestore hash. Fetch the txn directly from the - // nodestore. Don't traverse the transaction SHAMap - if (locator.isFound()) - { - auto start = std::chrono::system_clock::now(); - if (auto obj = context.app.getNodeFamily().db().fetchNodeObject( - locator.getNodestoreHash(), locator.getLedgerSequence())) - { - auto node = SHAMapTreeNode::makeFromPrefix( - makeSlice(obj->getData()), - SHAMapHash{locator.getNodestoreHash()}); - if (!node) - { - assert(false); - return {res, {rpcINTERNAL, "Error making SHAMap node"}}; - } - auto item = (static_cast(node.get()))->peekItem(); - if (!item) - { - assert(false); - return {res, {rpcINTERNAL, "Error reading SHAMap node"}}; - } - - auto [sttx, meta] = deserializeTxPlusMeta(*item); - JLOG(context.j.debug()) << "Successfully fetched from db"; - - if (!sttx || !meta) - { - assert(false); - return {res, {rpcINTERNAL, "Error deserializing SHAMap node"}}; - } - std::string reason; - res.txn = std::make_shared(sttx, reason, context.app); - res.txn->setLedger(locator.getLedgerSequence()); - res.txn->setStatus(COMMITTED); - if (args.binary) - { - SerialIter it(item->slice()); - it.skip(it.getVLDataLength()); // skip transaction - Blob blob = it.getVL(); - res.meta = std::move(blob); - } - else - { - res.meta = std::make_shared( - *(args.hash), res.txn->getLedger(), *meta); - } - res.validated = true; - - auto const ledgerInfo = - context.app.getRelationalDatabase().getLedgerInfoByIndex( - locator.getLedgerSequence()); - res.closeTime = ledgerInfo->closeTime; - res.ledgerHash = ledgerInfo->hash; - - return {res, rpcSUCCESS}; - } - else - { - JLOG(context.j.error()) << "Failed to fetch from db"; - assert(false); - return {res, {rpcINTERNAL, "Containing SHAMap node not found"}}; - } - auto end = std::chrono::system_clock::now(); - JLOG(context.j.debug()) << "tx flat fetch time : " - << ((end - start).count() / 1000000000.0); - } - // database did not find the transaction, and returned the ledger range - // that was searched - else - { - if (args.ledgerRange) - { - auto range = locator.getLedgerRangeSearched(); - auto min = args.ledgerRange->first; - auto max = args.ledgerRange->second; - if (min >= range.lower() && max <= range.upper()) - { - res.searchedAll = TxSearched::all; - } - else - { - res.searchedAll = TxSearched::some; - } - } - return {res, rpcTXN_NOT_FOUND}; - } - // database didn't return anything. This shouldn't happen - assert(false); - return {res, {rpcINTERNAL, "unexpected Postgres response"}}; -} - std::pair doTxHelp(RPC::Context& context, TxArgs args) { - if (context.app.config().reporting()) - return doTxPostgres(context, args); TxResult result; ClosedInterval range; @@ -344,7 +225,7 @@ populateJsonResponse( } // Note, result.ledgerHash is only set in a closed or validated - // ledger - as seen in `doTxHelp` and `doTxPostgres` + // ledger - as seen in `doTxHelp` if (result.ledgerHash) response[jss::ledger_hash] = to_string(*result.ledgerHash); diff --git a/src/xrpld/rpc/handlers/TxHistory.cpp b/src/xrpld/rpc/handlers/TxHistory.cpp index de86b182534..1122eab51c3 100644 --- a/src/xrpld/rpc/handlers/TxHistory.cpp +++ b/src/xrpld/rpc/handlers/TxHistory.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -60,8 +59,6 @@ doTxHistory(RPC::JsonContext& context) Json::Value obj; Json::Value& txs = obj[jss::txs]; obj[jss::index] = startIndex; - if (context.app.config().reporting()) - obj["used_postgres"] = true; for (auto const& t : trans) { diff --git a/src/xrpld/rpc/handlers/UnlList.cpp b/src/xrpld/rpc/handlers/UnlList.cpp index 78bd3f14eab..b3394534372 100644 --- a/src/xrpld/rpc/handlers/UnlList.cpp +++ b/src/xrpld/rpc/handlers/UnlList.cpp @@ -29,8 +29,6 @@ namespace ripple { Json::Value doUnlList(RPC::JsonContext& context) { - if (context.app.config().reporting()) - return rpcError(rpcREPORTING_UNSUPPORTED); Json::Value obj(Json::objectValue); context.app.validators().for_each_listed( diff --git a/src/xrpld/rpc/handlers/ValidatorListSites.cpp b/src/xrpld/rpc/handlers/ValidatorListSites.cpp index 902c373766f..39bc4e36471 100644 --- a/src/xrpld/rpc/handlers/ValidatorListSites.cpp +++ b/src/xrpld/rpc/handlers/ValidatorListSites.cpp @@ -28,9 +28,6 @@ namespace ripple { Json::Value doValidatorListSites(RPC::JsonContext& context) { - if (context.app.config().reporting()) - return rpcError(rpcREPORTING_UNSUPPORTED); - return context.app.validatorSites().getJson(); } diff --git a/src/xrpld/rpc/handlers/Validators.cpp b/src/xrpld/rpc/handlers/Validators.cpp index 4048e8962de..599e76f847a 100644 --- a/src/xrpld/rpc/handlers/Validators.cpp +++ b/src/xrpld/rpc/handlers/Validators.cpp @@ -28,9 +28,6 @@ namespace ripple { Json::Value doValidators(RPC::JsonContext& context) { - if (context.app.config().reporting()) - return rpcError(rpcREPORTING_UNSUPPORTED); - return context.app.validators().getJson(); } diff --git a/src/xrpld/shamap/Family.h b/src/xrpld/shamap/Family.h index 6559ce5059b..bbb22c273d0 100644 --- a/src/xrpld/shamap/Family.h +++ b/src/xrpld/shamap/Family.h @@ -65,8 +65,6 @@ class Family sweep() = 0; /** Acquire ledger that has a missing node by ledger sequence - * - * Throw if in reporting mode. * * @param refNum Sequence of ledger to acquire. * @param nodeHash Hash of missing node to report in throw. diff --git a/src/xrpld/shamap/detail/NodeFamily.cpp b/src/xrpld/shamap/detail/NodeFamily.cpp index 01440a48799..bf95003aef8 100644 --- a/src/xrpld/shamap/detail/NodeFamily.cpp +++ b/src/xrpld/shamap/detail/NodeFamily.cpp @@ -69,14 +69,6 @@ void NodeFamily::missingNodeAcquireBySeq(std::uint32_t seq, uint256 const& nodeHash) { JLOG(j_.error()) << "Missing node in " << seq; - if (app_.config().reporting()) - { - std::stringstream ss; - ss << "Node not read, likely a Cassandra error in ledger seq " << seq - << " object hash " << nodeHash; - Throw(ss.str()); - } - std::unique_lock lock(maxSeqMutex_); if (maxSeq_ == 0) { From cad8970a57501fd081788bed5aa15cf9a4472183 Mon Sep 17 00:00:00 2001 From: John Freeman Date: Wed, 28 Aug 2024 14:23:38 -0500 Subject: [PATCH 46/82] refactor: Remove dead headers (#5081) --- bin/ci/README.md | 26 -- bin/ci/build.sh | 31 -- bin/ci/test.sh | 41 -- bin/ci/ubuntu/build-and-test.sh | 274 ------------ bin/ci/ubuntu/build-in-docker.sh | 36 -- bin/ci/ubuntu/travis-cache-start.sh | 44 -- include/xrpl/beast/test/fail_counter.h | 160 ------- include/xrpl/beast/test/fail_stream.h | 182 -------- include/xrpl/beast/test/pipe_stream.h | 482 --------------------- include/xrpl/beast/test/sig_wait.h | 29 -- include/xrpl/beast/test/string_iostream.h | 166 ------- include/xrpl/beast/test/string_istream.h | 155 ------- include/xrpl/beast/test/string_ostream.h | 137 ------ include/xrpl/beast/test/test_allocator.h | 159 ------- include/xrpl/beast/unit_test/dstream.h | 121 ------ include/xrpl/beast/utility/hash_pair.h | 72 --- src/xrpld/peerfinder/detail/Logic.h | 1 - src/xrpld/peerfinder/detail/Reporting.h | 49 --- src/xrpld/peerfinder/sim/FunctionQueue.h | 100 ----- src/xrpld/peerfinder/sim/GraphAlgorithms.h | 76 ---- src/xrpld/peerfinder/sim/Message.h | 47 -- src/xrpld/peerfinder/sim/NodeSnapshot.h | 37 -- src/xrpld/peerfinder/sim/Params.h | 45 -- src/xrpld/peerfinder/sim/Predicates.h | 87 ---- 24 files changed, 2557 deletions(-) delete mode 100644 bin/ci/README.md delete mode 100755 bin/ci/build.sh delete mode 100755 bin/ci/test.sh delete mode 100755 bin/ci/ubuntu/build-and-test.sh delete mode 100755 bin/ci/ubuntu/build-in-docker.sh delete mode 100755 bin/ci/ubuntu/travis-cache-start.sh delete mode 100644 include/xrpl/beast/test/fail_counter.h delete mode 100644 include/xrpl/beast/test/fail_stream.h delete mode 100644 include/xrpl/beast/test/pipe_stream.h delete mode 100644 include/xrpl/beast/test/sig_wait.h delete mode 100644 include/xrpl/beast/test/string_iostream.h delete mode 100644 include/xrpl/beast/test/string_istream.h delete mode 100644 include/xrpl/beast/test/string_ostream.h delete mode 100644 include/xrpl/beast/test/test_allocator.h delete mode 100644 include/xrpl/beast/unit_test/dstream.h delete mode 100644 include/xrpl/beast/utility/hash_pair.h delete mode 100644 src/xrpld/peerfinder/detail/Reporting.h delete mode 100644 src/xrpld/peerfinder/sim/FunctionQueue.h delete mode 100644 src/xrpld/peerfinder/sim/GraphAlgorithms.h delete mode 100644 src/xrpld/peerfinder/sim/Message.h delete mode 100644 src/xrpld/peerfinder/sim/NodeSnapshot.h delete mode 100644 src/xrpld/peerfinder/sim/Params.h delete mode 100644 src/xrpld/peerfinder/sim/Predicates.h diff --git a/bin/ci/README.md b/bin/ci/README.md deleted file mode 100644 index 32ae24b3a20..00000000000 --- a/bin/ci/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Continuous Integration (CI) Scripts - -In this directory are two scripts, `build.sh` and `test.sh` used for building -and testing rippled. - -(For now, they assume Bash and Linux. Once I get Windows containers for -testing, I'll try them there, but if Bash is not available, then they will -soon be joined by PowerShell scripts `build.ps` and `test.ps`.) - -We don't want these scripts to require arcane invocations that can only be -pieced together from within a CI configuration. We want something that humans -can easily invoke, read, and understand, for when we eventually have to test -and debug them interactively. That means: - -(1) They should work with no arguments. -(2) They should document their arguments. -(3) They should expand short arguments into long arguments. - -While we want to provide options for common use cases, we don't need to offer -the kitchen sink. We can rightfully expect users with esoteric, complicated -needs to write their own scripts. - -To make argument-handling easy for us, the implementers, we can just take all -arguments from environment variables. They have the nice advantage that every -command-line uses named arguments. For the benefit of us and our users, we -document those variables at the top of each script. diff --git a/bin/ci/build.sh b/bin/ci/build.sh deleted file mode 100755 index fa7a0c96829..00000000000 --- a/bin/ci/build.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash - -set -o xtrace -set -o errexit - -# The build system. Either 'Unix Makefiles' or 'Ninja'. -GENERATOR=${GENERATOR:-Unix Makefiles} -# The compiler. Either 'gcc' or 'clang'. -COMPILER=${COMPILER:-gcc} -# The build type. Either 'Debug' or 'Release'. -BUILD_TYPE=${BUILD_TYPE:-Debug} -# Additional arguments to CMake. -# We use the `-` substitution here instead of `:-` so that callers can erase -# the default by setting `$CMAKE_ARGS` to the empty string. -CMAKE_ARGS=${CMAKE_ARGS-'-Dwerr=ON'} - -# https://gitlab.kitware.com/cmake/cmake/issues/18865 -CMAKE_ARGS="-DBoost_NO_BOOST_CMAKE=ON ${CMAKE_ARGS}" - -if [[ ${COMPILER} == 'gcc' ]]; then - export CC='gcc' - export CXX='g++' -elif [[ ${COMPILER} == 'clang' ]]; then - export CC='clang' - export CXX='clang++' -fi - -mkdir build -cd build -cmake -G "${GENERATOR}" -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ${CMAKE_ARGS} .. -cmake --build . -- -j $(nproc) diff --git a/bin/ci/test.sh b/bin/ci/test.sh deleted file mode 100755 index 11615d732b7..00000000000 --- a/bin/ci/test.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash - -set -o xtrace -set -o errexit - -# Set to 'true' to run the known "manual" tests in rippled. -MANUAL_TESTS=${MANUAL_TESTS:-false} -# The maximum number of concurrent tests. -CONCURRENT_TESTS=${CONCURRENT_TESTS:-$(nproc)} -# The path to rippled. -RIPPLED=${RIPPLED:-build/rippled} -# Additional arguments to rippled. -RIPPLED_ARGS=${RIPPLED_ARGS:-} - -function join_by { local IFS="$1"; shift; echo "$*"; } - -declare -a manual_tests=( - 'beast.chrono.abstract_clock' - 'beast.unit_test.print' - 'ripple.NodeStore.Timing' - 'ripple.app.Flow_manual' - 'ripple.app.NoRippleCheckLimits' - 'ripple.app.PayStrandAllPairs' - 'ripple.consensus.ByzantineFailureSim' - 'ripple.consensus.DistributedValidators' - 'ripple.consensus.ScaleFreeSim' - 'ripple.tx.CrossingLimits' - 'ripple.tx.FindOversizeCross' - 'ripple.tx.Offer_manual' - 'ripple.tx.OversizeMeta' - 'ripple.tx.PlumpBook' -) - -if [[ ${MANUAL_TESTS} == 'true' ]]; then - RIPPLED_ARGS+=" --unittest=$(join_by , "${manual_tests[@]}")" -else - RIPPLED_ARGS+=" --unittest --quiet --unittest-log" -fi -RIPPLED_ARGS+=" --unittest-jobs ${CONCURRENT_TESTS}" - -${RIPPLED} ${RIPPLED_ARGS} diff --git a/bin/ci/ubuntu/build-and-test.sh b/bin/ci/ubuntu/build-and-test.sh deleted file mode 100755 index 2c1734863fb..00000000000 --- a/bin/ci/ubuntu/build-and-test.sh +++ /dev/null @@ -1,274 +0,0 @@ -#!/usr/bin/env bash -set -ex - -function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; } - -__dirname=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) -echo "using CC: ${CC}" -"${CC}" --version -export CC - -COMPNAME=$(basename $CC) -echo "using CXX: ${CXX:-notset}" -if [[ $CXX ]]; then - "${CXX}" --version - export CXX -fi -: ${BUILD_TYPE:=Debug} -echo "BUILD TYPE: ${BUILD_TYPE}" - -: ${TARGET:=install} -echo "BUILD TARGET: ${TARGET}" - -JOBS=${NUM_PROCESSORS:-2} -if [[ ${TRAVIS:-false} != "true" ]]; then - JOBS=$((JOBS+1)) -fi - -if [[ ! -z "${CMAKE_EXE:-}" ]] ; then - export PATH="$(dirname ${CMAKE_EXE}):$PATH" -fi - -if [ -x /usr/bin/time ] ; then - : ${TIME:="Duration: %E"} - export TIME - time=/usr/bin/time -else - time= -fi - -echo "Building rippled" -: ${CMAKE_EXTRA_ARGS:=""} -if [[ ${NINJA_BUILD:-} == true ]]; then - CMAKE_EXTRA_ARGS+=" -G Ninja" -fi - -coverage=false -if [[ "${TARGET}" == "coverage" ]] ; then - echo "coverage option detected." - coverage=true -fi - -cmake --version -CMAKE_VER=$(cmake --version | cut -d " " -f 3 | head -1) - -# -# allow explicit setting of the name of the build -# dir, otherwise default to the compiler.build_type -# -: "${BUILD_DIR:=${COMPNAME}.${BUILD_TYPE}}" -BUILDARGS="--target ${TARGET}" -BUILDTOOLARGS="" -if version_ge $CMAKE_VER "3.12.0" ; then - BUILDARGS+=" --parallel" -fi - -if [[ ${NINJA_BUILD:-} == false ]]; then - if version_ge $CMAKE_VER "3.12.0" ; then - BUILDARGS+=" ${JOBS}" - else - BUILDTOOLARGS+=" -j ${JOBS}" - fi -fi - -if [[ ${VERBOSE_BUILD:-} == true ]]; then - CMAKE_EXTRA_ARGS+=" -DCMAKE_VERBOSE_MAKEFILE=ON" - if version_ge $CMAKE_VER "3.14.0" ; then - BUILDARGS+=" --verbose" - else - if [[ ${NINJA_BUILD:-} == false ]]; then - BUILDTOOLARGS+=" verbose=1" - else - BUILDTOOLARGS+=" -v" - fi - fi -fi - -if [[ ${USE_CCACHE:-} == true ]]; then - echo "using ccache with basedir [${CCACHE_BASEDIR:-}]" - CMAKE_EXTRA_ARGS+=" -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache" -fi -if [ -d "build/${BUILD_DIR}" ]; then - rm -rf "build/${BUILD_DIR}" -fi - -mkdir -p "build/${BUILD_DIR}" -pushd "build/${BUILD_DIR}" - -# cleanup possible artifacts -rm -fv CMakeFiles/CMakeOutput.log CMakeFiles/CMakeError.log -# Clean up NIH directories which should be git repos, but aren't -for nih_path in ${NIH_CACHE_ROOT}/*/*/*/src ${NIH_CACHE_ROOT}/*/*/src -do - for dir in lz4 snappy rocksdb - do - if [ -e ${nih_path}/${dir} -a \! -e ${nih_path}/${dir}/.git ] - then - ls -la ${nih_path}/${dir}* - rm -rfv ${nih_path}/${dir}* - fi - done -done - -# generate -${time} cmake ../.. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ${CMAKE_EXTRA_ARGS} -# Display the cmake output, to help with debugging if something fails -for file in CMakeOutput.log CMakeError.log -do - if [ -f CMakeFiles/${file} ] - then - ls -l CMakeFiles/${file} - cat CMakeFiles/${file} - fi -done -# build -export DESTDIR=$(pwd)/_INSTALLED_ - -${time} eval cmake --build . ${BUILDARGS} -- ${BUILDTOOLARGS} - -if [[ ${TARGET} == "docs" ]]; then - ## mimic the standard test output for docs build - ## to make controlling processes like jenkins happy - if [ -f docs/html/index.html ]; then - echo "1 case, 1 test total, 0 failures" - else - echo "1 case, 1 test total, 1 failures" - fi - exit -fi -popd - -if [[ "${TARGET}" == "validator-keys" ]] ; then - export APP_PATH="$PWD/build/${BUILD_DIR}/validator-keys/validator-keys" -else - export APP_PATH="$PWD/build/${BUILD_DIR}/rippled" -fi -echo "using APP_PATH: ${APP_PATH}" - -# See what we've actually built -ldd ${APP_PATH} - -: ${APP_ARGS:=} - -if [[ "${TARGET}" == "validator-keys" ]] ; then - APP_ARGS="--unittest" -else - function join_by { local IFS="$1"; shift; echo "$*"; } - - # This is a list of manual tests - # in rippled that we want to run - # ORDER matters here...sorted in approximately - # descending execution time (longest running tests at top) - declare -a manual_tests=( - 'ripple.ripple_data.reduce_relay_simulate' - 'ripple.tx.Offer_manual' - 'ripple.tx.CrossingLimits' - 'ripple.tx.PlumpBook' - 'ripple.app.Flow_manual' - 'ripple.tx.OversizeMeta' - 'ripple.consensus.DistributedValidators' - 'ripple.app.NoRippleCheckLimits' - 'ripple.ripple_data.compression' - 'ripple.NodeStore.Timing' - 'ripple.consensus.ByzantineFailureSim' - 'beast.chrono.abstract_clock' - 'beast.unit_test.print' - ) - if [[ ${TRAVIS:-false} != "true" ]]; then - # these two tests cause travis CI to run out of memory. - # TODO: investigate possible workarounds. - manual_tests=( - 'ripple.consensus.ScaleFreeSim' - 'ripple.tx.FindOversizeCross' - "${manual_tests[@]}" - ) - fi - - if [[ ${MANUAL_TESTS:-} == true ]]; then - APP_ARGS+=" --unittest=$(join_by , "${manual_tests[@]}")" - else - APP_ARGS+=" --unittest --quiet --unittest-log" - fi - if [[ ${coverage} == false && ${PARALLEL_TESTS:-} == true ]]; then - APP_ARGS+=" --unittest-jobs ${JOBS}" - fi - - if [[ ${IPV6_TESTS:-} == true ]]; then - APP_ARGS+=" --unittest-ipv6" - fi -fi - -if [[ ${coverage} == true && $CC =~ ^gcc ]]; then - # Push the results (lcov.info) to codecov - codecov -X gcov # don't even try and look for .gcov files ;) - find . -name "*.gcda" | xargs rm -f -fi - -if [[ ${SKIP_TESTS:-} == true ]]; then - echo "skipping tests." - exit -fi - -ulimit -a -corepat=$(cat /proc/sys/kernel/core_pattern) -if [[ ${corepat} =~ ^[:space:]*\| ]] ; then - echo "WARNING: core pattern is piping - can't search for core files" - look_core=false -else - look_core=true - coredir=$(dirname ${corepat}) -fi -if [[ ${look_core} == true ]]; then - before=$(ls -A1 ${coredir}) -fi - -set +e -echo "Running tests for ${APP_PATH}" -if [[ ${MANUAL_TESTS:-} == true && ${PARALLEL_TESTS:-} != true ]]; then - for t in "${manual_tests[@]}" ; do - ${APP_PATH} --unittest=${t} - TEST_STAT=$? - if [[ $TEST_STAT -ne 0 ]] ; then - break - fi - done -else - ${APP_PATH} ${APP_ARGS} - TEST_STAT=$? -fi -set -e - -if [[ ${look_core} == true ]]; then - after=$(ls -A1 ${coredir}) - oIFS="${IFS}" - IFS=$'\n\r' - found_core=false - for l in $(diff -w --suppress-common-lines <(echo "$before") <(echo "$after")) ; do - if [[ "$l" =~ ^[[:space:]]*\>[[:space:]]*(.+)$ ]] ; then - corefile="${BASH_REMATCH[1]}" - echo "FOUND core dump file at '${coredir}/${corefile}'" - gdb_output=$(/bin/mktemp /tmp/gdb_output_XXXXXXXXXX.txt) - found_core=true - gdb \ - -ex "set height 0" \ - -ex "set logging file ${gdb_output}" \ - -ex "set logging on" \ - -ex "print 'ripple::BuildInfo::versionString'" \ - -ex "thread apply all backtrace full" \ - -ex "info inferiors" \ - -ex quit \ - "$APP_PATH" \ - "${coredir}/${corefile}" &> /dev/null - - echo -e "CORE INFO: \n\n $(cat ${gdb_output}) \n\n)" - fi - done - IFS="${oIFS}" -fi - -if [[ ${found_core} == true ]]; then - exit -1 -else - exit $TEST_STAT -fi - diff --git a/bin/ci/ubuntu/build-in-docker.sh b/bin/ci/ubuntu/build-in-docker.sh deleted file mode 100755 index feeabb1189a..00000000000 --- a/bin/ci/ubuntu/build-in-docker.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env bash -# run our build script in a docker container -# using travis-ci hosts -set -eux - -function join_by { local IFS="$1"; shift; echo "$*"; } - -set +x -echo "VERBOSE_BUILD=true" > /tmp/co.env -matchers=( - 'TRAVIS.*' 'CI' 'CC' 'CXX' - 'BUILD_TYPE' 'TARGET' 'MAX_TIME' - 'CODECOV.+' 'CMAKE.*' '.+_TESTS' - '.+_OPTIONS' 'NINJA.*' 'NUM_.+' - 'NIH_.+' 'BOOST.*' '.*CCACHE.*') - -matchstring=$(join_by '|' "${matchers[@]}") -echo "MATCHSTRING IS:: $matchstring" -env | grep -E "^(${matchstring})=" >> /tmp/co.env -set -x -# need to eliminate TRAVIS_CMD...don't want to pass it to the container -cat /tmp/co.env | grep -v TRAVIS_CMD > /tmp/co.env.2 -mv /tmp/co.env.2 /tmp/co.env -cat /tmp/co.env -mkdir -p -m 0777 ${TRAVIS_BUILD_DIR}/cores -echo "${TRAVIS_BUILD_DIR}/cores/%e.%p" | sudo tee /proc/sys/kernel/core_pattern -docker run \ - -t --env-file /tmp/co.env \ - -v ${TRAVIS_HOME}:${TRAVIS_HOME} \ - -w ${TRAVIS_BUILD_DIR} \ - --cap-add SYS_PTRACE \ - --ulimit "core=-1" \ - $DOCKER_IMAGE \ - /bin/bash -c 'if [[ $CC =~ ([[:alpha:]]+)-([[:digit:].]+) ]] ; then sudo update-alternatives --set ${BASH_REMATCH[1]} /usr/bin/$CC; fi; bin/ci/ubuntu/build-and-test.sh' - - diff --git a/bin/ci/ubuntu/travis-cache-start.sh b/bin/ci/ubuntu/travis-cache-start.sh deleted file mode 100755 index 6811acb9043..00000000000 --- a/bin/ci/ubuntu/travis-cache-start.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash -# some cached files create churn, so save them here for -# later restoration before packing the cache -set -eux -clean_cache="travis_clean_cache" -if [[ ! ( "${TRAVIS_JOB_NAME}" =~ "windows" || \ - "${TRAVIS_JOB_NAME}" =~ "prereq-keep" ) ]] && \ - ( [[ "${TRAVIS_COMMIT_MESSAGE}" =~ "${clean_cache}" ]] || \ - ( [[ -v TRAVIS_PULL_REQUEST_SHA && \ - "${TRAVIS_PULL_REQUEST_SHA}" != "" ]] && \ - git log -1 "${TRAVIS_PULL_REQUEST_SHA}" | grep -cq "${clean_cache}" - - ) - ) -then - find ${TRAVIS_HOME}/_cache -maxdepth 2 -type d - rm -rf ${TRAVIS_HOME}/_cache - mkdir -p ${TRAVIS_HOME}/_cache -fi - -pushd ${TRAVIS_HOME} -if [ -f cache_ignore.tar ] ; then - rm -f cache_ignore.tar -fi - -if [ -d _cache/nih_c ] ; then - find _cache/nih_c -name "build.ninja" | tar rf cache_ignore.tar --files-from - - find _cache/nih_c -name ".ninja_deps" | tar rf cache_ignore.tar --files-from - - find _cache/nih_c -name ".ninja_log" | tar rf cache_ignore.tar --files-from - - find _cache/nih_c -name "*.log" | tar rf cache_ignore.tar --files-from - - find _cache/nih_c -name "*.tlog" | tar rf cache_ignore.tar --files-from - - # show .a files in the cache, for sanity checking - find _cache/nih_c -name "*.a" -ls -fi - -if [ -d _cache/ccache ] ; then - find _cache/ccache -name "stats" | tar rf cache_ignore.tar --files-from - -fi - -if [ -f cache_ignore.tar ] ; then - tar -tf cache_ignore.tar -fi -popd - - diff --git a/include/xrpl/beast/test/fail_counter.h b/include/xrpl/beast/test/fail_counter.h deleted file mode 100644 index d0cae77ddad..00000000000 --- a/include/xrpl/beast/test/fail_counter.h +++ /dev/null @@ -1,160 +0,0 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_TEST_FAIL_COUNTER_HPP -#define BEAST_TEST_FAIL_COUNTER_HPP - -#include -#include - -namespace beast { -namespace test { - -enum class error { fail_error = 1 }; - -namespace detail { - -class fail_error_category : public boost::system::error_category -{ -public: - const char* - name() const noexcept override - { - return "test"; - } - - std::string - message(int ev) const override - { - switch (static_cast(ev)) - { - default: - case error::fail_error: - return "test error"; - } - } - - boost::system::error_condition - default_error_condition(int ev) const noexcept override - { - return boost::system::error_condition{ev, *this}; - } - - bool - equivalent(int ev, boost::system::error_condition const& condition) - const noexcept override - { - return condition.value() == ev && &condition.category() == this; - } - - bool - equivalent(error_code const& error, int ev) const noexcept override - { - return error.value() == ev && &error.category() == this; - } -}; - -inline boost::system::error_category const& -get_error_category() -{ - static fail_error_category const cat{}; - return cat; -} - -} // namespace detail - -inline error_code -make_error_code(error ev) -{ - return error_code{ - static_cast::type>(ev), - detail::get_error_category()}; -} - -/** An error code with an error set on default construction - - Default constructed versions of this object will have - an error code set right away. This helps tests find code - which forgets to clear the error code on success. -*/ -struct fail_error_code : error_code -{ - fail_error_code() : error_code(make_error_code(error::fail_error)) - { - } - - template - fail_error_code(Arg0&& arg0, ArgN&&... argn) - : error_code(arg0, std::forward(argn)...) - { - } -}; - -/** A countdown to simulated failure. - - On the Nth operation, the class will fail with the specified - error code, or the default error code of @ref error::fail_error. -*/ -class fail_counter -{ - std::size_t n_; - error_code ec_; - -public: - fail_counter(fail_counter&&) = default; - - /** Construct a counter. - - @param The 0-based index of the operation to fail on or after. - */ - explicit fail_counter( - std::size_t n, - error_code ev = make_error_code(error::fail_error)) - : n_(n), ec_(ev) - { - } - - /// Throw an exception on the Nth failure - void - fail() - { - if (n_ > 0) - --n_; - if (!n_) - BOOST_THROW_EXCEPTION(system_error{ec_}); - } - - /// Set an error code on the Nth failure - bool - fail(error_code& ec) - { - if (n_ > 0) - --n_; - if (!n_) - { - ec = ec_; - return true; - } - ec.assign(0, ec.category()); - return false; - } -}; - -} // namespace test -} // namespace beast - -namespace boost { -namespace system { -template <> -struct is_error_code_enum -{ - static bool const value = true; -}; -} // namespace system -} // namespace boost - -#endif diff --git a/include/xrpl/beast/test/fail_stream.h b/include/xrpl/beast/test/fail_stream.h deleted file mode 100644 index 161e73ef091..00000000000 --- a/include/xrpl/beast/test/fail_stream.h +++ /dev/null @@ -1,182 +0,0 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_TEST_FAIL_STREAM_HPP -#define BEAST_TEST_FAIL_STREAM_HPP - -#include -#include -#include -#include -#include -#include -#include - -namespace beast { -namespace test { - -/** A stream wrapper that fails. - - On the Nth operation, the stream will fail with the specified - error code, or the default error code of invalid_argument. -*/ -template -class fail_stream -{ - boost::optional fc_; - fail_counter* pfc_; - NextLayer next_layer_; - -public: - using next_layer_type = typename std::remove_reference::type; - - using lowest_layer_type = typename get_lowest_layer::type; - - fail_stream(fail_stream&&) = delete; - fail_stream(fail_stream const&) = delete; - fail_stream& - operator=(fail_stream&&) = delete; - fail_stream& - operator=(fail_stream const&) = delete; - - template - explicit fail_stream(std::size_t n, Args&&... args) - : fc_(n), pfc_(&*fc_), next_layer_(std::forward(args)...) - { - } - - template - explicit fail_stream(fail_counter& fc, Args&&... args) - : pfc_(&fc), next_layer_(std::forward(args)...) - { - } - - next_layer_type& - next_layer() - { - return next_layer_; - } - - lowest_layer_type& - lowest_layer() - { - return next_layer_.lowest_layer(); - } - - lowest_layer_type const& - lowest_layer() const - { - return next_layer_.lowest_layer(); - } - - boost::asio::io_service& - get_io_service() - { - return next_layer_.get_io_service(); - } - - template - std::size_t - read_some(MutableBufferSequence const& buffers) - { - pfc_->fail(); - return next_layer_.read_some(buffers); - } - - template - std::size_t - read_some(MutableBufferSequence const& buffers, error_code& ec) - { - if (pfc_->fail(ec)) - return 0; - return next_layer_.read_some(buffers, ec); - } - - template - async_return_type - async_read_some(MutableBufferSequence const& buffers, ReadHandler&& handler) - { - error_code ec; - if (pfc_->fail(ec)) - { - async_completion init{ - handler}; - next_layer_.get_io_service().post( - bind_handler(init.completion_handler, ec, 0)); - return init.result.get(); - } - return next_layer_.async_read_some( - buffers, std::forward(handler)); - } - - template - std::size_t - write_some(ConstBufferSequence const& buffers) - { - pfc_->fail(); - return next_layer_.write_some(buffers); - } - - template - std::size_t - write_some(ConstBufferSequence const& buffers, error_code& ec) - { - if (pfc_->fail(ec)) - return 0; - return next_layer_.write_some(buffers, ec); - } - - template - async_return_type - async_write_some(ConstBufferSequence const& buffers, WriteHandler&& handler) - { - error_code ec; - if (pfc_->fail(ec)) - { - async_completion init{ - handler}; - next_layer_.get_io_service().post( - bind_handler(init.completion_handler, ec, 0)); - return init.result.get(); - } - return next_layer_.async_write_some( - buffers, std::forward(handler)); - } - - friend void - teardown( - websocket::teardown_tag, - fail_stream& stream, - boost::system::error_code& ec) - { - if (stream.pfc_->fail(ec)) - return; - beast::websocket_helpers::call_teardown(stream.next_layer(), ec); - } - - template - friend void - async_teardown( - websocket::teardown_tag, - fail_stream& stream, - TeardownHandler&& handler) - { - error_code ec; - if (stream.pfc_->fail(ec)) - { - stream.get_io_service().post(bind_handler(std::move(handler), ec)); - return; - } - beast::websocket_helpers::call_async_teardown( - stream.next_layer(), std::forward(handler)); - } -}; - -} // namespace test -} // namespace beast - -#endif diff --git a/include/xrpl/beast/test/pipe_stream.h b/include/xrpl/beast/test/pipe_stream.h deleted file mode 100644 index 762419a539a..00000000000 --- a/include/xrpl/beast/test/pipe_stream.h +++ /dev/null @@ -1,482 +0,0 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_TEST_PIPE_STREAM_HPP -#define BEAST_TEST_PIPE_STREAM_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace beast { -namespace test { - -/** A bidirectional in-memory communication channel - - An instance of this class provides a client and server - endpoint that are automatically connected to each other - similarly to a connected socket. - - Test pipes are used to facilitate writing unit tests - where the behavior of the transport is tightly controlled - to help illuminate all code paths (for code coverage) -*/ -class pipe -{ -public: - using buffer_type = flat_buffer; - -private: - struct read_op - { - virtual ~read_op() = default; - virtual void - operator()() = 0; - }; - - struct state - { - std::mutex m; - buffer_type b; - std::condition_variable cv; - std::unique_ptr op; - bool eof = false; - }; - - state s_[2]; - -public: - /** Represents an endpoint. - - Each pipe has a client stream and a server stream. - */ - class stream - { - friend class pipe; - - template - class read_op_impl; - - state& in_; - state& out_; - boost::asio::io_service& ios_; - fail_counter* fc_ = nullptr; - std::size_t read_max_ = (std::numeric_limits::max)(); - std::size_t write_max_ = (std::numeric_limits::max)(); - - stream(state& in, state& out, boost::asio::io_service& ios) - : in_(in), out_(out), ios_(ios), buffer(in_.b) - { - } - - public: - using buffer_type = pipe::buffer_type; - - /// Direct access to the underlying buffer - buffer_type& buffer; - - /// Counts the number of read calls - std::size_t nread = 0; - - /// Counts the number of write calls - std::size_t nwrite = 0; - - ~stream() = default; - stream(stream&&) = default; - - /// Set the fail counter on the object - void - fail(fail_counter& fc) - { - fc_ = &fc; - } - - /// Return the `io_service` associated with the object - boost::asio::io_service& - get_io_service() - { - return ios_; - } - - /// Set the maximum number of bytes returned by read_some - void - read_size(std::size_t n) - { - read_max_ = n; - } - - /// Set the maximum number of bytes returned by write_some - void - write_size(std::size_t n) - { - write_max_ = n; - } - - /// Returns a string representing the pending input data - string_view - str() const - { - using boost::asio::buffer_cast; - using boost::asio::buffer_size; - return { - buffer_cast(*in_.b.data().begin()), - buffer_size(*in_.b.data().begin())}; - } - - /// Clear the buffer holding the input data - void - clear() - { - in_.b.consume((std::numeric_limits::max)()); - } - - /** Close the stream. - - The other end of the pipe will see - `boost::asio::error::eof` on read. - */ - template - void - close(); - - template - std::size_t - read_some(MutableBufferSequence const& buffers); - - template - std::size_t - read_some(MutableBufferSequence const& buffers, error_code& ec); - - template - async_return_type - async_read_some( - MutableBufferSequence const& buffers, - ReadHandler&& handler); - - template - std::size_t - write_some(ConstBufferSequence const& buffers); - - template - std::size_t - write_some(ConstBufferSequence const& buffers, error_code&); - - template - async_return_type - async_write_some( - ConstBufferSequence const& buffers, - WriteHandler&& handler); - - friend void - teardown( - websocket::teardown_tag, - stream&, - boost::system::error_code& ec) - { - ec.assign(0, ec.category()); - } - - template - friend void - async_teardown( - websocket::teardown_tag, - stream& s, - TeardownHandler&& handler) - { - s.get_io_service().post( - bind_handler(std::move(handler), error_code{})); - } - }; - - /** Constructor. - - The client and server endpoints will use the same `io_service`. - */ - explicit pipe(boost::asio::io_service& ios) - : client(s_[0], s_[1], ios), server(s_[1], s_[0], ios) - { - } - - /** Constructor. - - The client and server endpoints will different `io_service` objects. - */ - explicit pipe(boost::asio::io_service& ios1, boost::asio::io_service& ios2) - : client(s_[0], s_[1], ios1), server(s_[1], s_[0], ios2) - { - } - - /// Represents the client endpoint - stream client; - - /// Represents the server endpoint - stream server; -}; - -//------------------------------------------------------------------------------ - -template -class pipe::stream::read_op_impl : public pipe::read_op -{ - stream& s_; - Buffers b_; - Handler h_; - -public: - read_op_impl(stream& s, Buffers const& b, Handler&& h) - : s_(s), b_(b), h_(std::move(h)) - { - } - - read_op_impl(stream& s, Buffers const& b, Handler const& h) - : s_(s), b_(b), h_(h) - { - } - - void - operator()() override; -}; - -//------------------------------------------------------------------------------ - -template -void -pipe::stream::read_op_impl::operator()() -{ - using boost::asio::buffer_copy; - using boost::asio::buffer_size; - s_.ios_.post([&]() { - BOOST_ASSERT(s_.in_.op); - std::unique_lock lock{s_.in_.m}; - if (s_.in_.b.size() > 0) - { - auto const bytes_transferred = - buffer_copy(b_, s_.in_.b.data(), s_.read_max_); - s_.in_.b.consume(bytes_transferred); - auto& s = s_; - Handler h{std::move(h_)}; - lock.unlock(); - s.in_.op.reset(nullptr); - ++s.nread; - s.ios_.post( - bind_handler(std::move(h), error_code{}, bytes_transferred)); - } - else - { - BOOST_ASSERT(s_.in_.eof); - auto& s = s_; - Handler h{std::move(h_)}; - lock.unlock(); - s.in_.op.reset(nullptr); - ++s.nread; - s.ios_.post(bind_handler(std::move(h), boost::asio::error::eof, 0)); - } - }); -} - -//------------------------------------------------------------------------------ - -template -void -pipe::stream::close() -{ - std::lock_guard lock{out_.m}; - out_.eof = true; - if (out_.op) - out_.op.get()->operator()(); - else - out_.cv.notify_all(); -} - -template -std::size_t -pipe::stream::read_some(MutableBufferSequence const& buffers) -{ - static_assert( - is_mutable_buffer_sequence::value, - "MutableBufferSequence requirements not met"); - error_code ec; - auto const n = read_some(buffers, ec); - if (ec) - BOOST_THROW_EXCEPTION(system_error{ec}); - return n; -} - -template -std::size_t -pipe::stream::read_some(MutableBufferSequence const& buffers, error_code& ec) -{ - static_assert( - is_mutable_buffer_sequence::value, - "MutableBufferSequence requirements not met"); - using boost::asio::buffer_copy; - using boost::asio::buffer_size; - BOOST_ASSERT(!in_.op); - BOOST_ASSERT(buffer_size(buffers) > 0); - if (fc_ && fc_->fail(ec)) - return 0; - std::unique_lock lock{in_.m}; - in_.cv.wait(lock, [&]() { return in_.b.size() > 0 || in_.eof; }); - std::size_t bytes_transferred; - if (in_.b.size() > 0) - { - ec.assign(0, ec.category()); - bytes_transferred = buffer_copy(buffers, in_.b.data(), read_max_); - in_.b.consume(bytes_transferred); - } - else - { - BOOST_ASSERT(in_.eof); - bytes_transferred = 0; - ec = boost::asio::error::eof; - } - ++nread; - return bytes_transferred; -} - -template -async_return_type -pipe::stream::async_read_some( - MutableBufferSequence const& buffers, - ReadHandler&& handler) -{ - static_assert( - is_mutable_buffer_sequence::value, - "MutableBufferSequence requirements not met"); - using boost::asio::buffer_copy; - using boost::asio::buffer_size; - BOOST_ASSERT(!in_.op); - BOOST_ASSERT(buffer_size(buffers) > 0); - async_completion init{handler}; - if (fc_) - { - error_code ec; - if (fc_->fail(ec)) - return ios_.post(bind_handler(init.completion_handler, ec, 0)); - } - { - std::unique_lock lock{in_.m}; - if (in_.eof) - { - lock.unlock(); - ++nread; - ios_.post(bind_handler( - init.completion_handler, boost::asio::error::eof, 0)); - } - else if (buffer_size(buffers) == 0 || buffer_size(in_.b.data()) > 0) - { - auto const bytes_transferred = - buffer_copy(buffers, in_.b.data(), read_max_); - in_.b.consume(bytes_transferred); - lock.unlock(); - ++nread; - ios_.post(bind_handler( - init.completion_handler, error_code{}, bytes_transferred)); - } - else - { - in_.op.reset( - new read_op_impl< - handler_type, - MutableBufferSequence>{ - *this, buffers, init.completion_handler}); - } - } - return init.result.get(); -} - -template -std::size_t -pipe::stream::write_some(ConstBufferSequence const& buffers) -{ - static_assert( - is_const_buffer_sequence::value, - "ConstBufferSequence requirements not met"); - BOOST_ASSERT(!out_.eof); - error_code ec; - auto const bytes_transferred = write_some(buffers, ec); - if (ec) - BOOST_THROW_EXCEPTION(system_error{ec}); - return bytes_transferred; -} - -template -std::size_t -pipe::stream::write_some(ConstBufferSequence const& buffers, error_code& ec) -{ - static_assert( - is_const_buffer_sequence::value, - "ConstBufferSequence requirements not met"); - using boost::asio::buffer_copy; - using boost::asio::buffer_size; - BOOST_ASSERT(!out_.eof); - if (fc_ && fc_->fail(ec)) - return 0; - auto const n = (std::min)(buffer_size(buffers), write_max_); - std::unique_lock lock{out_.m}; - auto const bytes_transferred = buffer_copy(out_.b.prepare(n), buffers); - out_.b.commit(bytes_transferred); - lock.unlock(); - if (out_.op) - out_.op.get()->operator()(); - else - out_.cv.notify_all(); - ++nwrite; - ec.assign(0, ec.category()); - return bytes_transferred; -} - -template -async_return_type -pipe::stream::async_write_some( - ConstBufferSequence const& buffers, - WriteHandler&& handler) -{ - static_assert( - is_const_buffer_sequence::value, - "ConstBufferSequence requirements not met"); - using boost::asio::buffer_copy; - using boost::asio::buffer_size; - BOOST_ASSERT(!out_.eof); - async_completion init{handler}; - if (fc_) - { - error_code ec; - if (fc_->fail(ec)) - return ios_.post(bind_handler(init.completion_handler, ec, 0)); - } - auto const n = (std::min)(buffer_size(buffers), write_max_); - std::unique_lock lock{out_.m}; - auto const bytes_transferred = buffer_copy(out_.b.prepare(n), buffers); - out_.b.commit(bytes_transferred); - lock.unlock(); - if (out_.op) - out_.op.get()->operator()(); - else - out_.cv.notify_all(); - ++nwrite; - ios_.post( - bind_handler(init.completion_handler, error_code{}, bytes_transferred)); - return init.result.get(); -} - -} // namespace test -} // namespace beast - -#endif diff --git a/include/xrpl/beast/test/sig_wait.h b/include/xrpl/beast/test/sig_wait.h deleted file mode 100644 index 92720561fa6..00000000000 --- a/include/xrpl/beast/test/sig_wait.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_TEST_SIG_WAIT_HPP -#define BEAST_TEST_SIG_WAIT_HPP - -#include - -namespace beast { -namespace test { - -/// Block until SIGINT or SIGTERM is received. -inline void -sig_wait() -{ - boost::asio::io_service ios; - boost::asio::signal_set signals(ios, SIGINT, SIGTERM); - signals.async_wait([&](boost::system::error_code const&, int) {}); - ios.run(); -} - -} // namespace test -} // namespace beast - -#endif diff --git a/include/xrpl/beast/test/string_iostream.h b/include/xrpl/beast/test/string_iostream.h deleted file mode 100644 index bed6299a2bc..00000000000 --- a/include/xrpl/beast/test/string_iostream.h +++ /dev/null @@ -1,166 +0,0 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_TEST_STRING_IOSTREAM_HPP -#define BEAST_TEST_STRING_IOSTREAM_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace beast { -namespace test { - -/** A SyncStream and AsyncStream that reads from a string and writes to another - string. - - This class behaves like a socket, except that written data is - appended to a string exposed as a public data member, and when - data is read it comes from a string provided at construction. -*/ -class string_iostream -{ - std::string s_; - boost::asio::const_buffer cb_; - boost::asio::io_service& ios_; - std::size_t read_max_; - -public: - std::string str; - - string_iostream( - boost::asio::io_service& ios, - std::string s, - std::size_t read_max = (std::numeric_limits::max)()) - : s_(std::move(s)) - , cb_(boost::asio::buffer(s_)) - , ios_(ios) - , read_max_(read_max) - { - } - - boost::asio::io_service& - get_io_service() - { - return ios_; - } - - template - std::size_t - read_some(MutableBufferSequence const& buffers) - { - error_code ec; - auto const n = read_some(buffers, ec); - if (ec) - BOOST_THROW_EXCEPTION(system_error{ec}); - return n; - } - - template - std::size_t - read_some(MutableBufferSequence const& buffers, error_code& ec) - { - auto const n = - boost::asio::buffer_copy(buffers, buffer_prefix(read_max_, cb_)); - if (n > 0) - { - ec.assign(0, ec.category()); - cb_ = cb_ + n; - } - else - { - ec = boost::asio::error::eof; - } - return n; - } - - template - async_return_type - async_read_some(MutableBufferSequence const& buffers, ReadHandler&& handler) - { - auto const n = - boost::asio::buffer_copy(buffers, boost::asio::buffer(s_)); - error_code ec; - if (n > 0) - s_.erase(0, n); - else - ec = boost::asio::error::eof; - async_completion init{ - handler}; - ios_.post(bind_handler(init.completion_handler, ec, n)); - return init.result.get(); - } - - template - std::size_t - write_some(ConstBufferSequence const& buffers) - { - error_code ec; - auto const n = write_some(buffers, ec); - if (ec) - BOOST_THROW_EXCEPTION(system_error{ec}); - return n; - } - - template - std::size_t - write_some(ConstBufferSequence const& buffers, error_code& ec) - { - ec.assign(0, ec.category()); - using boost::asio::buffer_cast; - using boost::asio::buffer_size; - auto const n = buffer_size(buffers); - str.reserve(str.size() + n); - for (boost::asio::const_buffer buffer : buffers) - str.append(buffer_cast(buffer), buffer_size(buffer)); - return n; - } - - template - async_return_type - async_write_some(ConstBufferSequence const& buffers, WriteHandler&& handler) - { - error_code ec; - auto const bytes_transferred = write_some(buffers, ec); - async_completion init{ - handler}; - get_io_service().post( - bind_handler(init.completion_handler, ec, bytes_transferred)); - return init.result.get(); - } - - friend void - teardown( - websocket::teardown_tag, - string_iostream&, - boost::system::error_code& ec) - { - ec.assign(0, ec.category()); - } - - template - friend void - async_teardown( - websocket::teardown_tag, - string_iostream& stream, - TeardownHandler&& handler) - { - stream.get_io_service().post( - bind_handler(std::move(handler), error_code{})); - } -}; - -} // namespace test -} // namespace beast - -#endif diff --git a/include/xrpl/beast/test/string_istream.h b/include/xrpl/beast/test/string_istream.h deleted file mode 100644 index 83cb3cfef5d..00000000000 --- a/include/xrpl/beast/test/string_istream.h +++ /dev/null @@ -1,155 +0,0 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_TEST_STRING_ISTREAM_HPP -#define BEAST_TEST_STRING_ISTREAM_HPP - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace beast { -namespace test { - -/** A SyncStream and AsyncStream that reads from a string. - - This class behaves like a socket, except that written data is simply - discarded, and when data is read it comes from a string provided - at construction. -*/ -class string_istream -{ - std::string s_; - boost::asio::const_buffer cb_; - boost::asio::io_service& ios_; - std::size_t read_max_; - -public: - string_istream( - boost::asio::io_service& ios, - std::string s, - std::size_t read_max = (std::numeric_limits::max)()) - : s_(std::move(s)) - , cb_(boost::asio::buffer(s_)) - , ios_(ios) - , read_max_(read_max) - { - } - - boost::asio::io_service& - get_io_service() - { - return ios_; - } - - template - std::size_t - read_some(MutableBufferSequence const& buffers) - { - error_code ec; - auto const n = read_some(buffers, ec); - if (ec) - BOOST_THROW_EXCEPTION(system_error{ec}); - return n; - } - - template - std::size_t - read_some(MutableBufferSequence const& buffers, error_code& ec) - { - auto const n = boost::asio::buffer_copy(buffers, cb_, read_max_); - if (n > 0) - { - ec.assign(0, ec.category()); - cb_ = cb_ + n; - } - else - { - ec = boost::asio::error::eof; - } - return n; - } - - template - async_return_type - async_read_some(MutableBufferSequence const& buffers, ReadHandler&& handler) - { - auto const n = - boost::asio::buffer_copy(buffers, boost::asio::buffer(s_)); - error_code ec; - if (n > 0) - s_.erase(0, n); - else - ec = boost::asio::error::eof; - async_completion init{ - handler}; - ios_.post(bind_handler(init.completion_handler, ec, n)); - return init.result.get(); - } - - template - std::size_t - write_some(ConstBufferSequence const& buffers) - { - error_code ec; - auto const n = write_some(buffers, ec); - if (ec) - BOOST_THROW_EXCEPTION(system_error{ec}); - return n; - } - - template - std::size_t - write_some(ConstBufferSequence const& buffers, error_code& ec) - { - ec.assign(0, ec.category()); - return boost::asio::buffer_size(buffers); - } - - template - async_return_type - async_write_some(ConstBuffeSequence const& buffers, WriteHandler&& handler) - { - async_completion init{ - handler}; - ios_.post(bind_handler( - init.completion_handler, - error_code{}, - boost::asio::buffer_size(buffers))); - return init.result.get(); - } - - friend void - teardown( - websocket::teardown_tag, - string_istream&, - boost::system::error_code& ec) - { - ec.assign(0, ec.category()); - } - - template - friend void - async_teardown( - websocket::teardown_tag, - string_istream& stream, - TeardownHandler&& handler) - { - stream.get_io_service().post( - bind_handler(std::move(handler), error_code{})); - } -}; - -} // namespace test -} // namespace beast - -#endif diff --git a/include/xrpl/beast/test/string_ostream.h b/include/xrpl/beast/test/string_ostream.h deleted file mode 100644 index 9edf69be88f..00000000000 --- a/include/xrpl/beast/test/string_ostream.h +++ /dev/null @@ -1,137 +0,0 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_TEST_STRING_OSTREAM_HPP -#define BEAST_TEST_STRING_OSTREAM_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace beast { -namespace test { - -class string_ostream -{ - boost::asio::io_service& ios_; - std::size_t write_max_; - -public: - std::string str; - - explicit string_ostream( - boost::asio::io_service& ios, - std::size_t write_max = (std::numeric_limits::max)()) - : ios_(ios), write_max_(write_max) - { - } - - boost::asio::io_service& - get_io_service() - { - return ios_; - } - - template - std::size_t - read_some(MutableBufferSequence const& buffers) - { - error_code ec; - auto const n = read_some(buffers, ec); - if (ec) - BOOST_THROW_EXCEPTION(system_error{ec}); - return n; - } - - template - std::size_t - read_some(MutableBufferSequence const&, error_code& ec) - { - ec = boost::asio::error::eof; - return 0; - } - - template - async_return_type - async_read_some(MutableBufferSequence const&, ReadHandler&& handler) - { - async_completion init{ - handler}; - ios_.post( - bind_handler(init.completion_handler, boost::asio::error::eof, 0)); - return init.result.get(); - } - - template - std::size_t - write_some(ConstBufferSequence const& buffers) - { - error_code ec; - auto const n = write_some(buffers, ec); - if (ec) - BOOST_THROW_EXCEPTION(system_error{ec}); - return n; - } - - template - std::size_t - write_some(ConstBufferSequence const& buffers, error_code& ec) - { - ec.assign(0, ec.category()); - using boost::asio::buffer_cast; - using boost::asio::buffer_size; - auto const n = (std::min)(buffer_size(buffers), write_max_); - str.reserve(str.size() + n); - for (boost::asio::const_buffer buffer : buffer_prefix(n, buffers)) - str.append(buffer_cast(buffer), buffer_size(buffer)); - return n; - } - - template - async_return_type - async_write_some(ConstBufferSequence const& buffers, WriteHandler&& handler) - { - error_code ec; - auto const bytes_transferred = write_some(buffers, ec); - async_completion init{ - handler}; - get_io_service().post( - bind_handler(init.completion_handler, ec, bytes_transferred)); - return init.result.get(); - } - - friend void - teardown( - websocket::teardown_tag, - string_ostream&, - boost::system::error_code& ec) - { - ec.assign(0, ec.category()); - } - - template - friend void - async_teardown( - websocket::teardown_tag, - string_ostream& stream, - TeardownHandler&& handler) - { - stream.get_io_service().post( - bind_handler(std::move(handler), error_code{})); - } -}; - -} // namespace test -} // namespace beast - -#endif diff --git a/include/xrpl/beast/test/test_allocator.h b/include/xrpl/beast/test/test_allocator.h deleted file mode 100644 index 598e22c2766..00000000000 --- a/include/xrpl/beast/test/test_allocator.h +++ /dev/null @@ -1,159 +0,0 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_TEST_TEST_ALLOCATOR_HPP -#define BEAST_TEST_TEST_ALLOCATOR_HPP - -#include -#include -#include - -namespace beast { -namespace test { - -struct test_allocator_info -{ - std::size_t id; - std::size_t ncopy = 0; - std::size_t nmove = 0; - std::size_t nmassign = 0; - std::size_t ncpassign = 0; - std::size_t nselect = 0; - - test_allocator_info() - : id([] { - static std::atomic sid(0); - return ++sid; - }()) - { - } -}; - -template -class test_allocator; - -template -struct test_allocator_base -{ -}; - -template -struct test_allocator_base -{ - static test_allocator - select_on_container_copy_construction( - test_allocator const& a) - { - return test_allocator{}; - } -}; - -template -class test_allocator - : public test_allocator_base -{ - std::shared_ptr info_; - - template - friend class test_allocator; - -public: - using value_type = T; - - using propagate_on_container_copy_assignment = - std::integral_constant; - - using propagate_on_container_move_assignment = - std::integral_constant; - - using propagate_on_container_swap = std::integral_constant; - - template - struct rebind - { - using other = test_allocator; - }; - - test_allocator() : info_(std::make_shared()) - { - } - - test_allocator(test_allocator const& u) noexcept : info_(u.info_) - { - ++info_->ncopy; - } - - template - test_allocator( - test_allocator const& u) noexcept - : info_(u.info_) - { - ++info_->ncopy; - } - - test_allocator(test_allocator&& t) : info_(t.info_) - { - ++info_->nmove; - } - - test_allocator& - operator=(test_allocator const& u) noexcept - { - info_ = u.info_; - ++info_->ncpassign; - return *this; - } - - test_allocator& - operator=(test_allocator&& u) noexcept - { - info_ = u.info_; - ++info_->nmassign; - return *this; - } - - value_type* - allocate(std::size_t n) - { - return static_cast(::operator new(n * sizeof(value_type))); - } - - void - deallocate(value_type* p, std::size_t) noexcept - { - ::operator delete(p); - } - - bool - operator==(test_allocator const& other) const - { - return id() == other.id() || Equal; - } - - bool - operator!=(test_allocator const& other) const - { - return !this->operator==(other); - } - - std::size_t - id() const - { - return info_->id; - } - - test_allocator_info const* - operator->() const - { - return info_.get(); - } -}; - -} // namespace test -} // namespace beast - -#endif diff --git a/include/xrpl/beast/unit_test/dstream.h b/include/xrpl/beast/unit_test/dstream.h deleted file mode 100644 index ff2036a12cb..00000000000 --- a/include/xrpl/beast/unit_test/dstream.h +++ /dev/null @@ -1,121 +0,0 @@ -// -// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_UNIT_TEST_DSTREAM_HPP -#define BEAST_UNIT_TEST_DSTREAM_HPP - -#include -#include -#include -#include -#include -#include - -#ifdef BOOST_WINDOWS -#include -//#include -#endif - -namespace beast { -namespace unit_test { - -#ifdef BOOST_WINDOWS - -namespace detail { - -template -class dstream_buf : public std::basic_stringbuf -{ - using ostream = std::basic_ostream; - - bool dbg_; - ostream& os_; - - template - void - write(T const*) = delete; - - void - write(char const* s) - { - if (dbg_) - /*boost::detail::winapi*/ ::OutputDebugStringA(s); - os_ << s; - } - - void - write(wchar_t const* s) - { - if (dbg_) - /*boost::detail::winapi*/ ::OutputDebugStringW(s); - os_ << s; - } - -public: - explicit dstream_buf(ostream& os) - : os_(os), dbg_(/*boost::detail::winapi*/ ::IsDebuggerPresent() != 0) - { - } - - ~dstream_buf() - { - sync(); - } - - int - sync() override - { - write(this->str().c_str()); - this->str(""); - return 0; - } -}; - -} // namespace detail - -/** std::ostream with Visual Studio IDE redirection. - - Instances of this stream wrap a specified `std::ostream` - (such as `std::cout` or `std::cerr`). If the IDE debugger - is attached when the stream is created, output will be - additionally copied to the Visual Studio Output window. -*/ -template < - class CharT, - class Traits = std::char_traits, - class Allocator = std::allocator> -class basic_dstream : public std::basic_ostream -{ - detail::dstream_buf buf_; - -public: - /** Construct a stream. - - @param os The output stream to wrap. - */ - explicit basic_dstream(std::ostream& os) - : std::basic_ostream(&buf_), buf_(os) - { - if (os.flags() & std::ios::unitbuf) - std::unitbuf(*this); - } -}; - -using dstream = basic_dstream; -using dwstream = basic_dstream; - -#else - -using dstream = std::ostream&; -using dwstream = std::wostream&; - -#endif - -} // namespace unit_test -} // namespace beast - -#endif diff --git a/include/xrpl/beast/utility/hash_pair.h b/include/xrpl/beast/utility/hash_pair.h deleted file mode 100644 index 08042b34778..00000000000 --- a/include/xrpl/beast/utility/hash_pair.h +++ /dev/null @@ -1,72 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - 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 BEAST_UTILITY_HASH_PAIR_H_INCLUDED -#define BEAST_UTILITY_HASH_PAIR_H_INCLUDED - -#include -#include - -#include -#include - -namespace std { - -/** Specialization of std::hash for any std::pair type. */ -template -struct hash> - : private boost::base_from_member, 0>, - private boost::base_from_member, 1> -{ -private: - using first_hash = boost::base_from_member, 0>; - using second_hash = boost::base_from_member, 1>; - -public: - hash() - { - } - - hash( - std::hash const& first_hash_, - std::hash const& second_hash_) - : first_hash(first_hash_), second_hash(second_hash_) - { - } - - std::size_t - operator()(std::pair const& value) - { - std::size_t result(first_hash::member(value.first)); - boost::hash_combine(result, second_hash::member(value.second)); - return result; - } - - std::size_t - operator()(std::pair const& value) const - { - std::size_t result(first_hash::member(value.first)); - boost::hash_combine(result, second_hash::member(value.second)); - return result; - } -}; - -} // namespace std - -#endif diff --git a/src/xrpld/peerfinder/detail/Logic.h b/src/xrpld/peerfinder/detail/Logic.h index 49b71a6a545..0403530ecf2 100644 --- a/src/xrpld/peerfinder/detail/Logic.h +++ b/src/xrpld/peerfinder/detail/Logic.h @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/src/xrpld/peerfinder/detail/Reporting.h b/src/xrpld/peerfinder/detail/Reporting.h deleted file mode 100644 index 25c36ea3f27..00000000000 --- a/src/xrpld/peerfinder/detail/Reporting.h +++ /dev/null @@ -1,49 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 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_PEERFINDER_REPORTING_H_INCLUDED -#define RIPPLE_PEERFINDER_REPORTING_H_INCLUDED - -namespace ripple { -namespace PeerFinder { - -/** Severity levels for test reporting. - This allows more fine grained control over reporting for diagnostics. -*/ -struct Reporting -{ - explicit Reporting() = default; - - // Report simulation parameters - static bool const params = true; - - // Report simulation crawl time-evolution - static bool const crawl = true; - - // Report nodes aggregate statistics - static bool const nodes = true; - - // Report nodes detailed information - static bool const dump_nodes = false; -}; - -} // namespace PeerFinder -} // namespace ripple - -#endif diff --git a/src/xrpld/peerfinder/sim/FunctionQueue.h b/src/xrpld/peerfinder/sim/FunctionQueue.h deleted file mode 100644 index d2fbb6dc26b..00000000000 --- a/src/xrpld/peerfinder/sim/FunctionQueue.h +++ /dev/null @@ -1,100 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 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_PEERFINDER_SIM_FUNCTIONQUEUE_H_INCLUDED -#define RIPPLE_PEERFINDER_SIM_FUNCTIONQUEUE_H_INCLUDED - -namespace ripple { -namespace PeerFinder { -namespace Sim { - -/** Maintains a queue of functors that can be called later. */ -class FunctionQueue -{ -public: - explicit FunctionQueue() = default; - -private: - class BasicWork - { - public: - virtual ~BasicWork() - { - } - virtual void - operator()() = 0; - }; - - template - class Work : public BasicWork - { - public: - explicit Work(Function f) : m_f(f) - { - } - void - operator()() - { - (m_f)(); - } - - private: - Function m_f; - }; - - std::list> m_work; - -public: - /** Returns `true` if there is no remaining work */ - bool - empty() - { - return m_work.empty(); - } - - /** Queue a function. - Function must be callable with this signature: - void (void) - */ - template - void - post(Function f) - { - m_work.emplace_back(std::make_unique>(f)); - } - - /** Run all pending functions. - The functions will be invoked in the order they were queued. - */ - void - run() - { - while (!m_work.empty()) - { - (*m_work.front())(); - m_work.pop_front(); - } - } -}; - -} // namespace Sim -} // namespace PeerFinder -} // namespace ripple - -#endif diff --git a/src/xrpld/peerfinder/sim/GraphAlgorithms.h b/src/xrpld/peerfinder/sim/GraphAlgorithms.h deleted file mode 100644 index b11ba42a7a7..00000000000 --- a/src/xrpld/peerfinder/sim/GraphAlgorithms.h +++ /dev/null @@ -1,76 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 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_PEERFINDER_SIM_GRAPHALGORITHMS_H_INCLUDED -#define RIPPLE_PEERFINDER_SIM_GRAPHALGORITHMS_H_INCLUDED - -namespace ripple { -namespace PeerFinder { -namespace Sim { - -template -struct VertexTraits; - -/** Call a function for each vertex in a connected graph. - Function will be called with this signature: - void (Vertex&, std::size_t diameter); -*/ - -template -void -breadth_first_traverse(Vertex& start, Function f) -{ - using Traits = VertexTraits; - using Edges = typename Traits::Edges; - using Edge = typename Traits::Edge; - - using Probe = std::pair; - using Work = std::deque; - using Visited = std::set; - Work work; - Visited visited; - work.emplace_back(&start, 0); - int diameter(0); - while (!work.empty()) - { - Probe const p(work.front()); - work.pop_front(); - if (visited.find(p.first) != visited.end()) - continue; - diameter = std::max(p.second, diameter); - visited.insert(p.first); - for (typename Edges::iterator iter(Traits::edges(*p.first).begin()); - iter != Traits::edges(*p.first).end(); - ++iter) - { - Vertex* v(Traits::vertex(*iter)); - if (visited.find(v) != visited.end()) - continue; - if (!iter->closed()) - work.emplace_back(v, p.second + 1); - } - f(*p.first, diameter); - } -} - -} // namespace Sim -} // namespace PeerFinder -} // namespace ripple - -#endif diff --git a/src/xrpld/peerfinder/sim/Message.h b/src/xrpld/peerfinder/sim/Message.h deleted file mode 100644 index 69be553c01a..00000000000 --- a/src/xrpld/peerfinder/sim/Message.h +++ /dev/null @@ -1,47 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 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_PEERFINDER_SIM_MESSAGE_H_INCLUDED -#define RIPPLE_PEERFINDER_SIM_MESSAGE_H_INCLUDED - -namespace ripple { -namespace PeerFinder { -namespace Sim { - -class Message -{ -public: - explicit Message(Endpoints const& endpoints) : m_payload(endpoints) - { - } - Endpoints const& - payload() const - { - return m_payload; - } - -private: - Endpoints m_payload; -}; - -} // namespace Sim -} // namespace PeerFinder -} // namespace ripple - -#endif diff --git a/src/xrpld/peerfinder/sim/NodeSnapshot.h b/src/xrpld/peerfinder/sim/NodeSnapshot.h deleted file mode 100644 index fbb08ece9a2..00000000000 --- a/src/xrpld/peerfinder/sim/NodeSnapshot.h +++ /dev/null @@ -1,37 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 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_PEERFINDER_SIM_NODESNAPSHOT_H_INCLUDED -#define RIPPLE_PEERFINDER_SIM_NODESNAPSHOT_H_INCLUDED - -namespace ripple { -namespace PeerFinder { -namespace Sim { - -/** A snapshot of a Node in the network simulator. */ -struct NodeSnapshot -{ - explicit NodeSnapshot() = default; -}; - -} // namespace Sim -} // namespace PeerFinder -} // namespace ripple - -#endif diff --git a/src/xrpld/peerfinder/sim/Params.h b/src/xrpld/peerfinder/sim/Params.h deleted file mode 100644 index c3c288bb985..00000000000 --- a/src/xrpld/peerfinder/sim/Params.h +++ /dev/null @@ -1,45 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 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_PEERFINDER_SIM_PARAMS_H_INCLUDED -#define RIPPLE_PEERFINDER_SIM_PARAMS_H_INCLUDED - -namespace ripple { -namespace PeerFinder { -namespace Sim { - -/** Defines the parameters for a network simulation. */ -struct Params -{ - Params() : steps(50), nodes(10), maxPeers(20), outPeers(9.5), firewalled(0) - { - } - - int steps; - int nodes; - int maxPeers; - double outPeers; - double firewalled; // [0, 1) -}; - -} // namespace Sim -} // namespace PeerFinder -} // namespace ripple - -#endif diff --git a/src/xrpld/peerfinder/sim/Predicates.h b/src/xrpld/peerfinder/sim/Predicates.h deleted file mode 100644 index 7bf125b383a..00000000000 --- a/src/xrpld/peerfinder/sim/Predicates.h +++ /dev/null @@ -1,87 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2012, 2013 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_PEERFINDER_SIM_PREDICATES_H_INCLUDED -#define RIPPLE_PEERFINDER_SIM_PREDICATES_H_INCLUDED - -namespace ripple { -namespace PeerFinder { -namespace Sim { - -/** UnaryPredicate, returns `true` if the 'to' node on a Link matches. */ -/** @{ */ -template -class is_remote_node_pred -{ -public: - is_remote_node_pred(Node const& n) : node(n) - { - } - template - bool - operator()(Link const& l) const - { - return &node == &l.remote_node(); - } - -private: - Node const& node; -}; - -template -is_remote_node_pred -is_remote_node(Node const& node) -{ - return is_remote_node_pred(node); -} - -template -is_remote_node_pred -is_remote_node(Node const* node) -{ - return is_remote_node_pred(*node); -} -/** @} */ - -//------------------------------------------------------------------------------ - -/** UnaryPredicate, `true` if the remote address matches. */ -class is_remote_endpoint -{ -public: - explicit is_remote_endpoint(beast::IP::Endpoint const& address) - : m_endpoint(address) - { - } - template - bool - operator()(Link const& link) const - { - return link.remote_endpoint() == m_endpoint; - } - -private: - beast::IP::Endpoint const m_endpoint; -}; - -} // namespace Sim -} // namespace PeerFinder -} // namespace ripple - -#endif From 2f432e812cb773048530ebfaf2e0e6def51e3cc2 Mon Sep 17 00:00:00 2001 From: John Freeman Date: Wed, 28 Aug 2024 17:31:33 -0500 Subject: [PATCH 47/82] docs: Update options documentation (#5083) Co-authored-by: Elliot Lee --- BUILD.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/BUILD.md b/BUILD.md index a39df98a5a6..31755c36919 100644 --- a/BUILD.md +++ b/BUILD.md @@ -377,9 +377,10 @@ stored inside the build directory, as either of: | --- | ---| ---| | `assert` | OFF | Enable assertions. | `coverage` | OFF | Prepare the coverage report. | -| `tests` | ON | Build tests. | -| `unity` | ON | Configure a unity build. | | `san` | N/A | Enable a sanitizer with Clang. Choices are `thread` and `address`. | +| `tests` | OFF | Build tests. | +| `unity` | ON | Configure a unity build. | +| `xrpld` | OFF | Build the xrpld (`rippled`) application, and not just the libxrpl library. | [Unity builds][5] may be faster for the first build (at the cost of much more memory) since they concatenate sources into fewer From cc0177be8712ca367134aa6599b7328bbc5e6bc5 Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Tue, 3 Sep 2024 18:37:47 -0400 Subject: [PATCH 48/82] Update Release Notes for 2.2.1 and 2.2.2 --- RELEASENOTES.md | 109 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index cfc0e618cfe..72eb4687232 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -6,6 +6,115 @@ This document contains the release notes for `rippled`, the reference server imp Have new ideas? Need help with setting up your node? [Please open an issue here](https://github.com/xrplf/rippled/issues/new/choose). +# Version 2.2.2 + +Version 2.2.2 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release fixes an ongoing issue with Mainnet where validators can stall during consensus processing due to lock contention, preventing ledgers from being validated for up to two minutes. There are no new amendments in this release. + +[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) + + + +## Action Required + +If you run an XRP Ledger validator, upgrade to version 2.2.2 as soon as possible to ensure stable and uninterrupted network behavior. + +Additionally, five amendments introduced in version 2.2.0 are open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. If you operate an XRP Ledger server older than version 2.2.0, upgrade by September 17, 2024 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. Version 2.2.2 is recommended because of known bugs affecting stability of versions 2.2.0 and 2.2.1. + +If you operate a Clio server, Clio needs to be updated to 2.1.2 before updating to rippled 2.2.0. Clio will be blocked if it is not updated. + +## Changelog + +### Amendments and New Features + +- None + +### Bug Fixes and Performance Improvements + +- Allow only 1 job queue slot for acquiring inbound ledger [#5115](https://github.com/XRPLF/rippled/pull/5115) ([7741483](https://github.com/XRPLF/rippled/commit/774148389467781aca7c01bac90af2fba870570c)) + +- Allow only 1 job queue slot for each validation ledger check [#5115](https://github.com/XRPLF/rippled/pull/5115) ([fbbea9e](https://github.com/XRPLF/rippled/commit/fbbea9e6e25795a8a6bd1bf64b780771933a9579)) + +### Other improvements + + - Track latencies of certain code blocks, and log if they take too long [#5115](https://github.com/XRPLF/rippled/pull/5115) ([00ed7c9](https://github.com/XRPLF/rippled/commit/00ed7c942436f02644a13169002b5123f4e2a116)) + +### Docs and Build System + +- None + +### GitHub + +The public source code repository for `rippled` is hosted on GitHub at . + +We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. + + +## Credits + +The following people contributed directly to this release: + +Mark Travis +Valentin Balaschenko <13349202+vlntb@users.noreply.github.com> + +Bug Bounties and Responsible Disclosures: + +We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. + +To report a bug, please send a detailed report to: + +# Version 2.2.1 + +Version 2.2.1 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release fixes a critical bug introduced in 2.2.0 handling some types of RPC requests. + +[Sign Up for Future Release Announcements](https://groups.google.com/g/ripple-server) + + + +## Action Required + +If you run an XRP Ledger validator, upgrade to version 2.2.1 as soon as possible to ensure stable and uninterrupted network behavior. + +Additionally, five amendments introduced in version 2.2.0 are open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. If you operate an XRP Ledger server older than version 2.2.0, upgrade by August 14, 2024 to ensure service continuity. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. Version 2.2.1 is recommended because of known bugs affecting stability of versions 2.2.0. + +If you operate a Clio server, Clio needs to be updated to 2.2.2 before updating to rippled 2.2.1. Clio will be blocked if it is not updated. + +## Changelog + +### Amendments and New Features + +- None + +### Bug Fixes and Performance Improvements + +- Improve error handling in some RPC commands. [#5078](https://github.com/XRPLF/rippled/pull/5078) + +- Use error codes throughout fast Base58 implementation. [#5078](https://github.com/XRPLF/rippled/pull/5078) + +### Docs and Build System + +- None + +### GitHub + +The public source code repository for `rippled` is hosted on GitHub at . + +We welcome all contributions and invite everyone to join the community of XRP Ledger developers to help build the Internet of Value. + + +## Credits + +The following people contributed directly to this release: + +John Freeman +Mayukha Vadari + +Bug Bounties and Responsible Disclosures: + +We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. + +To report a bug, please send a detailed report to: + + # Version 2.2.0 Version 2.2.0 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release adds performance optimizations, several bug fixes, and introduces the `featurePriceOracle`, `fixEmptyDID`, `fixXChainRewardRounding`, `fixPreviousTxnID`, and `fixAMMv1_1` amendments. From 23991c99c31ed93ee875a077c7b8312a3ee7f53d Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Wed, 11 Sep 2024 11:29:06 +0100 Subject: [PATCH 49/82] test: Retry RPC commands to try to fix MacOS CI jobs (#5120) * Retry some failed RPC connections / commands in unit tests * Remove orphaned `getAccounts` function Co-authored-by: John Freeman --- src/test/jtx/impl/Env.cpp | 28 ++++++++++++++++++---------- src/xrpld/app/misc/NetworkOPs.cpp | 18 ------------------ 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/src/test/jtx/impl/Env.cpp b/src/test/jtx/impl/Env.cpp index 6f0f9e3fc73..ef5a2124e24 100644 --- a/src/test/jtx/impl/Env.cpp +++ b/src/test/jtx/impl/Env.cpp @@ -317,16 +317,24 @@ Env::submit(JTx const& jt) auto const jr = [&]() { if (jt.stx) { - txid_ = jt.stx->getTransactionID(); - Serializer s; - jt.stx->add(s); - auto const jr = rpc("submit", strHex(s.slice())); - - parsedResult = parseResult(jr); - test.expect(parsedResult.ter, "ter uninitialized!"); - ter_ = parsedResult.ter.value_or(telENV_RPC_FAILED); - - return jr; + // We shouldn't need to retry, but it fixes the test on macOS for + // the moment. + int retries = 3; + do + { + txid_ = jt.stx->getTransactionID(); + Serializer s; + jt.stx->add(s); + auto const jr = rpc("submit", strHex(s.slice())); + + parsedResult = parseResult(jr); + test.expect(parsedResult.ter, "ter uninitialized!"); + ter_ = parsedResult.ter.value_or(telENV_RPC_FAILED); + if (ter_ != telENV_RPC_FAILED || + parsedResult.rpcCode != rpcINTERNAL || + jt.ter == telENV_RPC_FAILED || --retries <= 0) + return jr; + } while (true); } else { diff --git a/src/xrpld/app/misc/NetworkOPs.cpp b/src/xrpld/app/misc/NetworkOPs.cpp index 01906d306cd..02eb0435b57 100644 --- a/src/xrpld/app/misc/NetworkOPs.cpp +++ b/src/xrpld/app/misc/NetworkOPs.cpp @@ -2783,24 +2783,6 @@ NetworkOPsImp::pubProposedTransaction( pubProposedAccountTransaction(ledger, transaction, result); } -static void -getAccounts(Json::Value const& jvObj, std::vector& accounts) -{ - for (auto& jv : jvObj) - { - if (jv.isObject()) - { - getAccounts(jv, accounts); - } - else if (jv.isString()) - { - auto account = RPC::accountFromStringStrict(jv.asString()); - if (account) - accounts.push_back(*account); - } - } -} - void NetworkOPsImp::pubLedger(std::shared_ptr const& lpAccepted) { From 9a6af9c431808c182778bb641c03e092ff7151d4 Mon Sep 17 00:00:00 2001 From: luozexuan Date: Tue, 17 Sep 2024 04:53:19 +0800 Subject: [PATCH 50/82] chore: fix typos in comments (#5094) Signed-off-by: luozexuan --- src/libxrpl/protocol/tokens.cpp | 2 +- src/test/csf/README.md | 2 +- src/test/csf/random.h | 2 +- src/test/ledger/Directory_test.cpp | 2 +- src/xrpld/app/tx/detail/Transactor.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libxrpl/protocol/tokens.cpp b/src/libxrpl/protocol/tokens.cpp index 454ed803f75..ccae1fb8ed2 100644 --- a/src/libxrpl/protocol/tokens.cpp +++ b/src/libxrpl/protocol/tokens.cpp @@ -91,7 +91,7 @@ algorithm that converts a number to coefficients from base B2. There is a useful shortcut that can be used if one of the bases is a power of the other base. If B1 == B2^G, then each coefficient from base B1 can be -converted to base B2 independently to create a a group of "G" B2 coefficient. +converted to base B2 independently to create a group of "G" B2 coefficient. These coefficients can be simply concatenated together. Since 16 == 2^4, this property is what makes base 16 useful when dealing with binary numbers. For example consider converting the base 16 number "93" to binary. The base 16 diff --git a/src/test/csf/README.md b/src/test/csf/README.md index ff6bdc5dfac..a4b69abab57 100644 --- a/src/test/csf/README.md +++ b/src/test/csf/README.md @@ -144,7 +144,7 @@ sim.collectors.add(simDur); ``` The next lines add a single collector to the simulation. The -`SimDurationCollector` is a a simple example collector which tracks the total +`SimDurationCollector` is a simple example collector which tracks the total duration of the simulation. More generally, a collector is any class that implements `void on(NodeID, SimTime, Event)` for all [Events](./events.h) emitted by a Peer. Events are arbitrary types used to indicate some action or diff --git a/src/test/csf/random.h b/src/test/csf/random.h index 5a512400704..e78bbf515be 100644 --- a/src/test/csf/random.h +++ b/src/test/csf/random.h @@ -121,7 +121,7 @@ makeSelector(Iter first, Iter last, std::vector const& w, Generator& g) } //------------------------------------------------------------------------------ -// Additional distributions of interest not defined in in +// Additional distributions of interest not defined in /** Constant "distribution" that always returns the same value */ diff --git a/src/test/ledger/Directory_test.cpp b/src/test/ledger/Directory_test.cpp index 4904b6e6fbf..bea394f2f36 100644 --- a/src/test/ledger/Directory_test.cpp +++ b/src/test/ledger/Directory_test.cpp @@ -29,7 +29,7 @@ namespace test { struct Directory_test : public beast::unit_test::suite { - // Map [0-15576] into a a unique 3 letter currency code + // Map [0-15576] into a unique 3 letter currency code std::string currcode(std::size_t i) { diff --git a/src/xrpld/app/tx/detail/Transactor.cpp b/src/xrpld/app/tx/detail/Transactor.cpp index 6ae8be8a67f..18e11415c0a 100644 --- a/src/xrpld/app/tx/detail/Transactor.cpp +++ b/src/xrpld/app/tx/detail/Transactor.cpp @@ -635,7 +635,7 @@ Transactor::checkMultiSign(PreclaimContext const& ctx) calcAccountID(PublicKey(makeSlice(spk))); // Verify that the signingAcctID and the signingAcctIDFromPubKey - // belong together. Here is are the rules: + // belong together. Here are the rules: // // 1. "Phantom account": an account that is not in the ledger // A. If signingAcctID == signingAcctIDFromPubKey and the From b6391fe0110f8a2d5a406ab458b3f2e0453adcc6 Mon Sep 17 00:00:00 2001 From: Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com> Date: Thu, 19 Sep 2024 08:39:10 -0700 Subject: [PATCH 51/82] fix(book_changes): add "validated" field and reduce RPC latency (#5096) Update book_changes RPC to reduce latency, add "validated" field, and accept shortcut strings (current, closed, validated) for ledger_index. `"validated": true` indicates that the transaction has been included in a validated ledger so the result of the transaction is immutable. Fix #5033 Fix #5034 Fix #5035 Fix #5036 --------- Co-authored-by: Bronek Kozicki --- API-CHANGELOG.md | 10 ++- src/test/rpc/BookChanges_test.cpp | 100 ++++++++++++++++++++++++++ src/xrpld/rpc/BookChanges.h | 12 ++++ src/xrpld/rpc/handlers/BookOffers.cpp | 10 +-- 4 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 src/test/rpc/BookChanges_test.cpp diff --git a/API-CHANGELOG.md b/API-CHANGELOG.md index 58ceed0cde1..967e1ce6052 100644 --- a/API-CHANGELOG.md +++ b/API-CHANGELOG.md @@ -26,7 +26,15 @@ In `api_version: 2`, the `signer_lists` field [will be moved](#modifications-to- The `network_id` field was added in the `server_info` response in version 1.5.0 (2019), but it is not returned in [reporting mode](https://xrpl.org/rippled-server-modes.html#reporting-mode). -## XRP Ledger server version 2.0.0 +### Breaking change in 2.3 + +- `book_changes`: If the requested ledger version is not available on this node, a `ledgerNotFound` error is returned and the node does not attempt to acquire the ledger from the p2p network (as with other non-admin RPCs). + +Admins can still attempt to retrieve old ledgers with the `ledger_request` RPC. + +### Addition in 2.3 + +- `book_changes`: Returns a `validated` field in its response, which was missing in prior versions. ### Additions in 2.2 diff --git a/src/test/rpc/BookChanges_test.cpp b/src/test/rpc/BookChanges_test.cpp new file mode 100644 index 00000000000..95997538d79 --- /dev/null +++ b/src/test/rpc/BookChanges_test.cpp @@ -0,0 +1,100 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 + +namespace ripple { +namespace test { + +class BookChanges_test : public beast::unit_test::suite +{ +public: + void + testConventionalLedgerInputStrings() + { + testcase("Specify well-known strings as ledger input"); + jtx::Env env(*this); + Json::Value params, resp; + + // As per convention in XRPL, ledgers can be specified with strings + // "closed", "validated" or "current" + params["ledger"] = "validated"; + resp = env.rpc("json", "book_changes", to_string(params)); + BEAST_EXPECT(!resp[jss::result].isMember(jss::error)); + BEAST_EXPECT(resp[jss::result][jss::status] == "success"); + BEAST_EXPECT(resp[jss::result][jss::validated] == true); + + params["ledger"] = "current"; + resp = env.rpc("json", "book_changes", to_string(params)); + BEAST_EXPECT(!resp[jss::result].isMember(jss::error)); + BEAST_EXPECT(resp[jss::result][jss::status] == "success"); + BEAST_EXPECT(resp[jss::result][jss::validated] == false); + + params["ledger"] = "closed"; + resp = env.rpc("json", "book_changes", to_string(params)); + BEAST_EXPECT(!resp[jss::result].isMember(jss::error)); + BEAST_EXPECT(resp[jss::result][jss::status] == "success"); + + // In the unit-test framework, requesting for "closed" ledgers appears + // to yield "validated" ledgers. This is not new behavior. It is also + // observed in the unit tests for the LedgerHeader class. + BEAST_EXPECT(resp[jss::result][jss::validated] == true); + + // non-conventional ledger input should throw an error + params["ledger"] = "non_conventional_ledger_input"; + resp = env.rpc("json", "book_changes", to_string(params)); + BEAST_EXPECT(resp[jss::result].isMember(jss::error)); + BEAST_EXPECT(resp[jss::result][jss::status] != "success"); + } + + void + testLedgerInputDefaultBehavior() + { + testcase( + "If ledger_hash or ledger_index is not specified, the behavior " + "must default to the `current` ledger"); + jtx::Env env(*this); + + // As per convention in XRPL, ledgers can be specified with strings + // "closed", "validated" or "current" + Json::Value const resp = + env.rpc("json", "book_changes", to_string(Json::Value{})); + BEAST_EXPECT(!resp[jss::result].isMember(jss::error)); + BEAST_EXPECT(resp[jss::result][jss::status] == "success"); + + // I dislike asserting the below statement, because its dependent on the + // unit-test framework BEAST_EXPECT(resp[jss::result][jss::ledger_index] + // == 3); + } + + void + run() override + { + testConventionalLedgerInputStrings(); + testLedgerInputDefaultBehavior(); + + // Note: Other aspects of the book_changes rpc are fertile grounds for + // unit-testing purposes. It can be included in future work + } +}; + +BEAST_DEFINE_TESTSUITE(BookChanges, app, ripple); + +} // namespace test +} // namespace ripple diff --git a/src/xrpld/rpc/BookChanges.h b/src/xrpld/rpc/BookChanges.h index 7d7978d3fe2..c87fa0ccf4e 100644 --- a/src/xrpld/rpc/BookChanges.h +++ b/src/xrpld/rpc/BookChanges.h @@ -20,6 +20,15 @@ #ifndef RIPPLE_RPC_BOOKCHANGES_H_INCLUDED #define RIPPLE_RPC_BOOKCHANGES_H_INCLUDED +#include +#include +#include +#include +#include +#include + +#include + namespace Json { class Value; } @@ -171,6 +180,9 @@ computeBookChanges(std::shared_ptr const& lpAccepted) Json::Value jvObj(Json::objectValue); jvObj[jss::type] = "bookChanges"; + + // retrieve validated information from LedgerHeader class + jvObj[jss::validated] = lpAccepted->info().validated; jvObj[jss::ledger_index] = lpAccepted->info().seq; jvObj[jss::ledger_hash] = to_string(lpAccepted->info().hash); jvObj[jss::ledger_time] = Json::Value::UInt( diff --git a/src/xrpld/rpc/handlers/BookOffers.cpp b/src/xrpld/rpc/handlers/BookOffers.cpp index 6126913a5b6..dccc03de5be 100644 --- a/src/xrpld/rpc/handlers/BookOffers.cpp +++ b/src/xrpld/rpc/handlers/BookOffers.cpp @@ -204,13 +204,13 @@ doBookOffers(RPC::JsonContext& context) Json::Value doBookChanges(RPC::JsonContext& context) { - auto res = RPC::getLedgerByContext(context); + std::shared_ptr ledger; - if (std::holds_alternative(res)) - return std::get(res); + Json::Value result = RPC::lookupLedger(ledger, context); + if (ledger == nullptr) + return result; - return RPC::computeBookChanges( - std::get>(res)); + return RPC::computeBookChanges(ledger); } } // namespace ripple From 0ece395c24384a33cd143e445da168c468acf5f4 Mon Sep 17 00:00:00 2001 From: Vlad <129996061+vvysokikh1@users.noreply.github.com> Date: Fri, 20 Sep 2024 19:04:10 +0100 Subject: [PATCH 52/82] refactor: re-order PRAGMA statements (#5140) The page_size will soon be made configurable with #5135, making this re-ordering necessary. When opening SQLite connection, there are specific pragmas set with commonPragmas. In particular, PRAGMA journal_mode creates journal file and locks the page_size; as of this commit, this sets the page size to the default value of 4096. Coincidentally, the hardcoded page_size was also 4096, so no issue was noticed. --- src/xrpld/core/DatabaseCon.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/xrpld/core/DatabaseCon.h b/src/xrpld/core/DatabaseCon.h index 219693b11ef..f656d83f9e1 100644 --- a/src/xrpld/core/DatabaseCon.h +++ b/src/xrpld/core/DatabaseCon.h @@ -206,6 +206,12 @@ class DatabaseCon { open(*session_, "sqlite", pPath.string()); + for (auto const& p : pragma) + { + soci::statement st = session_->prepare << p; + st.execute(true); + } + if (commonPragma) { for (auto const& p : *commonPragma) @@ -214,11 +220,7 @@ class DatabaseCon st.execute(true); } } - for (auto const& p : pragma) - { - soci::statement st = session_->prepare << p; - st.execute(true); - } + for (auto const& sql : initSQL) { soci::statement st = session_->prepare << sql; From a75309919e77e82b71daed1bab4ccedab84428d9 Mon Sep 17 00:00:00 2001 From: Denis Angell Date: Fri, 20 Sep 2024 23:26:21 +0200 Subject: [PATCH 53/82] feat(SQLite): allow configurable database pragma values (#5135) Make page_size and journal_size_limit configurable values in rippled.cfg --- cfg/rippled-example.cfg | 14 +++ src/test/nodestore/Database_test.cpp | 109 ++++++++++++++++++++++ src/xrpld/app/main/DBInit.h | 22 ----- src/xrpld/app/rdb/backend/detail/Node.cpp | 4 +- src/xrpld/app/rdb/detail/Vacuum.cpp | 4 +- src/xrpld/app/rdb/detail/Wallet.cpp | 4 +- src/xrpld/core/DatabaseCon.h | 12 ++- src/xrpld/core/detail/DatabaseCon.cpp | 32 ++++++- 8 files changed, 167 insertions(+), 34 deletions(-) diff --git a/cfg/rippled-example.cfg b/cfg/rippled-example.cfg index 673ab3213e8..0ce3406f6b9 100644 --- a/cfg/rippled-example.cfg +++ b/cfg/rippled-example.cfg @@ -1106,6 +1106,20 @@ # This setting may not be combined with the # "safety_level" setting. # +# page_size Valid values: integer (MUST be power of 2 between 512 and 65536) +# The default is 4096 bytes. This setting determines +# the size of a page in the transaction.db file. +# See https://www.sqlite.org/pragma.html#pragma_page_size +# for more details about the available options. +# +# journal_size_limit Valid values: integer +# The default is 1582080. This setting limits +# the size of the journal for transaction.db file. When the limit is +# reached, older entries will be deleted. +# See https://www.sqlite.org/pragma.html#pragma_journal_size_limit +# for more details about the available options. +# +# #------------------------------------------------------------------------------- # # 7. Diagnostics diff --git a/src/test/nodestore/Database_test.cpp b/src/test/nodestore/Database_test.cpp index d866247da89..59557f3c79f 100644 --- a/src/test/nodestore/Database_test.cpp +++ b/src/test/nodestore/Database_test.cpp @@ -439,6 +439,115 @@ class Database_test : public TestBase BEAST_EXPECT(found); } } + { + // N/A: Default values + Env env(*this); + auto const s = setup_DatabaseCon(env.app().config()); + if (BEAST_EXPECT(s.txPragma.size() == 4)) + { + BEAST_EXPECT(s.txPragma.at(0) == "PRAGMA page_size=4096;"); + BEAST_EXPECT( + s.txPragma.at(1) == "PRAGMA journal_size_limit=1582080;"); + BEAST_EXPECT( + s.txPragma.at(2) == "PRAGMA max_page_count=4294967294;"); + BEAST_EXPECT( + s.txPragma.at(3) == "PRAGMA mmap_size=17179869184;"); + } + } + { + // Success: Valid values + Env env = [&]() { + auto p = test::jtx::envconfig(); + { + auto& section = p->section("sqlite"); + section.set("page_size", "512"); + section.set("journal_size_limit", "2582080"); + } + return Env(*this, std::move(p)); + }(); + auto const s = setup_DatabaseCon(env.app().config()); + if (BEAST_EXPECT(s.txPragma.size() == 4)) + { + BEAST_EXPECT(s.txPragma.at(0) == "PRAGMA page_size=512;"); + BEAST_EXPECT( + s.txPragma.at(1) == "PRAGMA journal_size_limit=2582080;"); + BEAST_EXPECT( + s.txPragma.at(2) == "PRAGMA max_page_count=4294967294;"); + BEAST_EXPECT( + s.txPragma.at(3) == "PRAGMA mmap_size=17179869184;"); + } + } + { + // Error: Invalid values + auto const expected = + "Invalid page_size. Must be between 512 and 65536."; + bool found = false; + auto p = test::jtx::envconfig(); + { + auto& section = p->section("sqlite"); + section.set("page_size", "256"); + } + try + { + Env env( + *this, + std::move(p), + std::make_unique(expected, &found), + beast::severities::kWarning); + fail(); + } + catch (...) + { + BEAST_EXPECT(found); + } + } + { + // Error: Invalid values + auto const expected = + "Invalid page_size. Must be between 512 and 65536."; + bool found = false; + auto p = test::jtx::envconfig(); + { + auto& section = p->section("sqlite"); + section.set("page_size", "131072"); + } + try + { + Env env( + *this, + std::move(p), + std::make_unique(expected, &found), + beast::severities::kWarning); + fail(); + } + catch (...) + { + BEAST_EXPECT(found); + } + } + { + // Error: Invalid values + auto const expected = "Invalid page_size. Must be a power of 2."; + bool found = false; + auto p = test::jtx::envconfig(); + { + auto& section = p->section("sqlite"); + section.set("page_size", "513"); + } + try + { + Env env( + *this, + std::move(p), + std::make_unique(expected, &found), + beast::severities::kWarning); + fail(); + } + catch (...) + { + BEAST_EXPECT(found); + } + } } //-------------------------------------------------------------------------- diff --git a/src/xrpld/app/main/DBInit.h b/src/xrpld/app/main/DBInit.h index 6eaf19671ac..192b1bedae3 100644 --- a/src/xrpld/app/main/DBInit.h +++ b/src/xrpld/app/main/DBInit.h @@ -42,9 +42,6 @@ inline constexpr std::uint32_t SQLITE_TUNING_CUTOFF = 10'000'000; // Ledger database holds ledgers and ledger confirmations inline constexpr auto LgrDBName{"ledger.db"}; -inline constexpr std::array LgrDBPragma{ - {"PRAGMA journal_size_limit=1582080;"}}; - inline constexpr std::array LgrDBInit{ {"BEGIN TRANSACTION;", @@ -72,25 +69,6 @@ inline constexpr std::array LgrDBInit{ // Transaction database holds transactions and public keys inline constexpr auto TxDBName{"transaction.db"}; -// In C++17 omitting the explicit template parameters caused -// a crash -inline constexpr std::array TxDBPragma -{ - "PRAGMA page_size=4096;", "PRAGMA journal_size_limit=1582080;", - "PRAGMA max_page_count=4294967294;", - -#if (ULONG_MAX > UINT_MAX) && !defined(NO_SQLITE_MMAP) - "PRAGMA mmap_size=17179869184;" -#else - - // Provide an explicit `no-op` SQL statement - // in order to keep the size of the array - // constant regardless of the preprocessor - // condition evaluation - "PRAGMA sqlite_noop_statement;" -#endif -}; - inline constexpr std::array TxDBInit{ {"BEGIN TRANSACTION;", diff --git a/src/xrpld/app/rdb/backend/detail/Node.cpp b/src/xrpld/app/rdb/backend/detail/Node.cpp index 36ff70d8dc0..2ea6bd12c62 100644 --- a/src/xrpld/app/rdb/backend/detail/Node.cpp +++ b/src/xrpld/app/rdb/backend/detail/Node.cpp @@ -72,7 +72,7 @@ makeLedgerDBs( { // ledger database auto lgr{std::make_unique( - setup, LgrDBName, LgrDBPragma, LgrDBInit, checkpointerSetup, j)}; + setup, LgrDBName, setup.lgrPragma, LgrDBInit, checkpointerSetup, j)}; lgr->getSession() << boost::str( boost::format("PRAGMA cache_size=-%d;") % kilobytes(config.getValueFor(SizedItem::lgrDBCache))); @@ -81,7 +81,7 @@ makeLedgerDBs( { // transaction database auto tx{std::make_unique( - setup, TxDBName, TxDBPragma, TxDBInit, checkpointerSetup, j)}; + setup, TxDBName, setup.txPragma, TxDBInit, checkpointerSetup, j)}; tx->getSession() << boost::str( boost::format("PRAGMA cache_size=-%d;") % kilobytes(config.getValueFor(SizedItem::txnDBCache))); diff --git a/src/xrpld/app/rdb/detail/Vacuum.cpp b/src/xrpld/app/rdb/detail/Vacuum.cpp index 92e20c86831..cc7f01a8409 100644 --- a/src/xrpld/app/rdb/detail/Vacuum.cpp +++ b/src/xrpld/app/rdb/detail/Vacuum.cpp @@ -40,8 +40,8 @@ doVacuumDB(DatabaseCon::Setup const& setup, beast::Journal j) return false; } - auto txnDB = - std::make_unique(setup, TxDBName, TxDBPragma, TxDBInit, j); + auto txnDB = std::make_unique( + setup, TxDBName, setup.txPragma, TxDBInit, j); auto& session = txnDB->getSession(); std::uint32_t pageSize; diff --git a/src/xrpld/app/rdb/detail/Wallet.cpp b/src/xrpld/app/rdb/detail/Wallet.cpp index d0631e6e633..ffb28596918 100644 --- a/src/xrpld/app/rdb/detail/Wallet.cpp +++ b/src/xrpld/app/rdb/detail/Wallet.cpp @@ -27,7 +27,7 @@ makeWalletDB(DatabaseCon::Setup const& setup, beast::Journal j) { // wallet database return std::make_unique( - setup, WalletDBName, std::array(), WalletDBInit, j); + setup, WalletDBName, std::array(), WalletDBInit, j); } std::unique_ptr @@ -38,7 +38,7 @@ makeTestWalletDB( { // wallet database return std::make_unique( - setup, dbname.data(), std::array(), WalletDBInit, j); + setup, dbname.data(), std::array(), WalletDBInit, j); } void diff --git a/src/xrpld/core/DatabaseCon.h b/src/xrpld/core/DatabaseCon.h index f656d83f9e1..935147815ca 100644 --- a/src/xrpld/core/DatabaseCon.h +++ b/src/xrpld/core/DatabaseCon.h @@ -102,6 +102,8 @@ class DatabaseCon } static std::unique_ptr const> globalPragma; + std::array txPragma; + std::array lgrPragma; }; struct CheckpointerSetup @@ -114,7 +116,7 @@ class DatabaseCon DatabaseCon( Setup const& setup, std::string const& dbName, - std::array const& pragma, + std::array const& pragma, std::array const& initSQL, beast::Journal journal) // Use temporary files or regular DB files? @@ -136,7 +138,7 @@ class DatabaseCon DatabaseCon( Setup const& setup, std::string const& dbName, - std::array const& pragma, + std::array const& pragma, std::array const& initSQL, CheckpointerSetup const& checkpointerSetup, beast::Journal journal) @@ -149,7 +151,7 @@ class DatabaseCon DatabaseCon( boost::filesystem::path const& dataDir, std::string const& dbName, - std::array const& pragma, + std::array const& pragma, std::array const& initSQL, beast::Journal journal) : DatabaseCon(dataDir / dbName, nullptr, pragma, initSQL, journal) @@ -161,7 +163,7 @@ class DatabaseCon DatabaseCon( boost::filesystem::path const& dataDir, std::string const& dbName, - std::array const& pragma, + std::array const& pragma, std::array const& initSQL, CheckpointerSetup const& checkpointerSetup, beast::Journal journal) @@ -199,7 +201,7 @@ class DatabaseCon DatabaseCon( boost::filesystem::path const& pPath, std::vector const* commonPragma, - std::array const& pragma, + std::array const& pragma, std::array const& initSQL, beast::Journal journal) : session_(std::make_shared()), j_(journal) diff --git a/src/xrpld/core/detail/DatabaseCon.cpp b/src/xrpld/core/detail/DatabaseCon.cpp index 10b34efd41e..7000899b1f6 100644 --- a/src/xrpld/core/detail/DatabaseCon.cpp +++ b/src/xrpld/core/detail/DatabaseCon.cpp @@ -175,7 +175,7 @@ setup_DatabaseCon(Config const& c, std::optional j) } { - //#synchronous Valid values : off, normal, full, extra + // #synchronous Valid values : off, normal, full, extra if (set(synchronous, "synchronous", sqlite) && !safety_level.empty()) { @@ -237,6 +237,36 @@ setup_DatabaseCon(Config const& c, std::optional j) } setup.useGlobalPragma = true; + auto setPragma = + [](std::string& pragma, std::string const& key, int64_t value) { + pragma = "PRAGMA " + key + "=" + std::to_string(value) + ";"; + }; + + // Lgr Pragma + setPragma(setup.lgrPragma[0], "journal_size_limit", 1582080); + + // TX Pragma + int64_t page_size = 4096; + int64_t journal_size_limit = 1582080; + if (c.exists("sqlite")) + { + auto& s = c.section("sqlite"); + set(journal_size_limit, "journal_size_limit", s); + set(page_size, "page_size", s); + if (page_size < 512 || page_size > 65536) + Throw( + "Invalid page_size. Must be between 512 and 65536."); + + if (page_size & (page_size - 1)) + Throw( + "Invalid page_size. Must be a power of 2."); + } + + setPragma(setup.txPragma[0], "page_size", page_size); + setPragma(setup.txPragma[1], "journal_size_limit", journal_size_limit); + setPragma(setup.txPragma[2], "max_page_count", 4294967294); + setPragma(setup.txPragma[3], "mmap_size", 17179869184); + return setup; } From 1fbf8da79fd2fbfa63d72ab6bbfd85181d156738 Mon Sep 17 00:00:00 2001 From: Elliot Lee Date: Wed, 18 Sep 2024 10:56:33 -0700 Subject: [PATCH 54/82] Set version to 2.3.0-b4 --- src/libxrpl/protocol/BuildInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libxrpl/protocol/BuildInfo.cpp b/src/libxrpl/protocol/BuildInfo.cpp index 1d983a58576..4c88a372ff3 100644 --- a/src/libxrpl/protocol/BuildInfo.cpp +++ b/src/libxrpl/protocol/BuildInfo.cpp @@ -33,7 +33,7 @@ namespace BuildInfo { // and follow the format described at http://semver.org/ //------------------------------------------------------------------------------ // clang-format off -char const* const versionString = "2.3.0-b3" +char const* const versionString = "2.3.0-b4" // clang-format on #if defined(DEBUG) || defined(SANITIZER) From 8e2c85d14de9dfa04394e30910de13d53e45f0ff Mon Sep 17 00:00:00 2001 From: Elliot Lee Date: Tue, 1 Oct 2024 14:07:31 -0700 Subject: [PATCH 55/82] docs: clean up API-CHANGELOG.md (#5064) Move the newest information to the top, i.e., use reverse chronological order within each of the two sections ("API Versions" and "XRP Ledger server versions") --- API-CHANGELOG.md | 162 ++++++++++++++++++++++------------------------- 1 file changed, 74 insertions(+), 88 deletions(-) diff --git a/API-CHANGELOG.md b/API-CHANGELOG.md index 967e1ce6052..1c0595b0081 100644 --- a/API-CHANGELOG.md +++ b/API-CHANGELOG.md @@ -8,23 +8,86 @@ The API version controls the API behavior you see. This includes what properties For a log of breaking changes, see the **API Version [number]** headings. In general, breaking changes are associated with a particular API Version number. For non-breaking changes, scroll to the **XRP Ledger version [x.y.z]** headings. Non-breaking changes are associated with a particular XRP Ledger (`rippled`) release. -## API Version 1 +## API Version 2 + +API version 2 is available in `rippled` version 2.0.0 and later. To use this API, clients specify `"api_version" : 2` in each request. + +#### Removed methods -This version is supported by all `rippled` versions. At time of writing, it is the default API version, used when no `api_version` is specified. When a new API version is introduced, the command line interface will default to the latest API version. The command line is intended for ad-hoc usage by humans, not programs or automated scripts. The command line is not meant for use in production code. +In API version 2, the following deprecated methods are no longer available: (https://github.com/XRPLF/rippled/pull/4759) + +- `tx_history` - Instead, use other methods such as `account_tx` or `ledger` with the `transactions` field set to `true`. +- `ledger_header` - Instead, use the `ledger` method. -### Idiosyncrasies +#### Modifications to JSON transaction element in V2 + +In API version 2, JSON elements for transaction output have been changed and made consistent for all methods which output transactions. (https://github.com/XRPLF/rippled/pull/4775) +This helps to unify the JSON serialization format of transactions. (https://github.com/XRPLF/clio/issues/722, https://github.com/XRPLF/rippled/issues/4727) + +- JSON transaction element is named `tx_json` +- Binary transaction element is named `tx_blob` +- JSON transaction metadata element is named `meta` +- Binary transaction metadata element is named `meta_blob` -#### V1 account_info response +Additionally, these elements are now consistently available next to `tx_json` (i.e. sibling elements), where possible: -In [the response to the `account_info` command](https://xrpl.org/account_info.html#response-format), there is `account_data` - which is supposed to be an `AccountRoot` object - and `signer_lists` is returned in this object. However, the docs say that `signer_lists` should be at the root level of the reponse. +- `hash` - Transaction ID. This data was stored inside transaction output in API version 1, but in API version 2 is a sibling element. +- `ledger_index` - Ledger index (only set on validated ledgers) +- `ledger_hash` - Ledger hash (only set on closed or validated ledgers) +- `close_time_iso` - Ledger close time expressed in ISO 8601 time format (only set on validated ledgers) +- `validated` - Bool element set to `true` if the transaction is in a validated ledger, otherwise `false` -It makes sense for `signer_lists` to be at the root level because signer lists are not part of the AccountRoot object. (First reported in [xrpl-dev-portal#938](https://github.com/XRPLF/xrpl-dev-portal/issues/938).) +This change affects the following methods: -In `api_version: 2`, the `signer_lists` field [will be moved](#modifications-to-account_info-response-in-v2) to the root level of the account_info response. (https://github.com/XRPLF/rippled/pull/3770) +- `tx` - Transaction data moved into element `tx_json` (was inline inside `result`) or, if binary output was requested, moved from `tx` to `tx_blob`. Renamed binary transaction metadata element (if it was requested) from `meta` to `meta_blob`. Changed location of `hash` and added new elements +- `account_tx` - Renamed transaction element from `tx` to `tx_json`. Renamed binary transaction metadata element (if it was requested) from `meta` to `meta_blob`. Changed location of `hash` and added new elements +- `transaction_entry` - Renamed transaction metadata element from `metadata` to `meta`. Changed location of `hash` and added new elements +- `subscribe` - Renamed transaction element from `transaction` to `tx_json`. Changed location of `hash` and added new elements +- `sign`, `sign_for`, `submit` and `submit_multisigned` - Changed location of `hash` element. -#### server_info - network_id +#### Modification to `Payment` transaction JSON schema -The `network_id` field was added in the `server_info` response in version 1.5.0 (2019), but it is not returned in [reporting mode](https://xrpl.org/rippled-server-modes.html#reporting-mode). +When reading Payments, the `Amount` field should generally **not** be used. Instead, use [delivered_amount](https://xrpl.org/partial-payments.html#the-delivered_amount-field) to see the amount that the Payment delivered. To clarify its meaning, the `Amount` field is being renamed to `DeliverMax`. (https://github.com/XRPLF/rippled/pull/4733) + +- In `Payment` transaction type, JSON RPC field `Amount` is renamed to `DeliverMax`. To enable smooth client transition, `Amount` is still handled, as described below: (https://github.com/XRPLF/rippled/pull/4733) + - On JSON RPC input (e.g. `submit_multisigned` etc. methods), `Amount` is recognized as an alias to `DeliverMax` for both API version 1 and version 2 clients. + - On JSON RPC input, submitting both `Amount` and `DeliverMax` fields is allowed _only_ if they are identical; otherwise such input is rejected with `rpcINVALID_PARAMS` error. + - On JSON RPC output (e.g. `subscribe`, `account_tx` etc. methods), `DeliverMax` is present in both API version 1 and version 2. + - On JSON RPC output, `Amount` is only present in API version 1 and _not_ in version 2. + +#### Modifications to account_info response + +- `signer_lists` is returned in the root of the response. (In API version 1, it was nested under `account_data`.) (https://github.com/XRPLF/rippled/pull/3770) +- When using an invalid `signer_lists` value, the API now returns an "invalidParams" error. (https://github.com/XRPLF/rippled/pull/4585) + - (`signer_lists` must be a boolean. In API version 1, strings were accepted and may return a normal response - i.e. as if `signer_lists` were `true`.) + +#### Modifications to [account_tx](https://xrpl.org/account_tx.html#account_tx) response + +- Using `ledger_index_min`, `ledger_index_max`, and `ledger_index` returns `invalidParams` because if you use `ledger_index_min` or `ledger_index_max`, then it does not make sense to also specify `ledger_index`. In API version 1, no error was returned. (https://github.com/XRPLF/rippled/pull/4571) + - The same applies for `ledger_index_min`, `ledger_index_max`, and `ledger_hash`. (https://github.com/XRPLF/rippled/issues/4545#issuecomment-1565065579) +- Using a `ledger_index_min` or `ledger_index_max` beyond the range of ledgers that the server has: + - returns `lgrIdxMalformed` in API version 2. Previously, in API version 1, no error was returned. (https://github.com/XRPLF/rippled/issues/4288) +- Attempting to use a non-boolean value (such as a string) for the `binary` or `forward` parameters returns `invalidParams` (`rpcINVALID_PARAMS`). Previously, in API version 1, no error was returned. (https://github.com/XRPLF/rippled/pull/4620) + +#### Modifications to [noripple_check](https://xrpl.org/noripple_check.html#noripple_check) response + +- Attempting to use a non-boolean value (such as a string) for the `transactions` parameter returns `invalidParams` (`rpcINVALID_PARAMS`). Previously, in API version 1, no error was returned. (https://github.com/XRPLF/rippled/pull/4620) + +## API Version 1 + +This version is supported by all `rippled` versions. For WebSocket and HTTP JSON-RPC requests, it is currently the default API version used when no `api_version` is specified. + +The [commandline](https://xrpl.org/docs/references/http-websocket-apis/api-conventions/request-formatting/#commandline-format) always uses the latest API version. The command line is intended for ad-hoc usage by humans, not programs or automated scripts. The command line is not meant for use in production code. + +### Inconsistency: server_info - network_id + +The `network_id` field was added in the `server_info` response in version 1.5.0 (2019), but it is not returned in [reporting mode](https://xrpl.org/rippled-server-modes.html#reporting-mode). However, use of reporting mode is now discouraged, in favor of using [Clio](https://github.com/XRPLF/clio) instead. + +## XRP Ledger server version 2.2.0 + +The following is a non-breaking addition to the API. + +- The `feature` method now has a non-admin mode for users. (It was previously only available to admin connections.) The method returns an updated list of amendments, including their names and other information. ([#4781](https://github.com/XRPLF/rippled/pull/4781)) ### Breaking change in 2.3 @@ -36,15 +99,7 @@ Admins can still attempt to retrieve old ledgers with the `ledger_request` RPC. - `book_changes`: Returns a `validated` field in its response, which was missing in prior versions. -### Additions in 2.2 - -Additions are intended to be non-breaking (because they are purely additive). - -- `feature`: A non-admin mode that uses the same formatting as admin RPC, but hides potentially-sensitive data. - -### Additions in 2.0 - -Additions are intended to be non-breaking (because they are purely additive). +The following additions are non-breaking (because they are purely additive). - `server_definitions`: A new RPC that generates a `definitions.json`-like output that can be used in XRPL libraries. - In `Payment` transactions, `DeliverMax` has been added. This is a replacement for the `Amount` field, which should not be used. Typically, the `delivered_amount` (in transaction metadata) should be used. To ease the transition, `DeliverMax` is present regardless of API version, since adding a field is non-breaking. @@ -52,11 +107,7 @@ Additions are intended to be non-breaking (because they are purely additive). ## XRP Ledger server version 1.12.0 -[Version 1.12.0](https://github.com/XRPLF/rippled/releases/tag/1.12.0) was released on Sep 6, 2023. - -### Additions in 1.12 - -Additions are intended to be non-breaking (because they are purely additive). +[Version 1.12.0](https://github.com/XRPLF/rippled/releases/tag/1.12.0) was released on Sep 6, 2023. The following additions are non-breaking (because they are purely additive). - `server_info`: Added `ports`, an array which advertises the RPC and WebSocket ports. This information is also included in the `/crawl` endpoint (which calls `server_info` internally). `grpc` and `peer` ports are also included. (https://github.com/XRPLF/rippled/pull/4427) - `ports` contains objects, each containing a `port` for the listening port (a number string), and a `protocol` array listing the supported protocols on that port. @@ -133,71 +184,6 @@ was released on Mar 14, 2023. removed from the [ledger subscription stream](https://xrpl.org/subscribe.html#ledger-stream), because it will no longer have any meaning. -## API Version 2 - -API version 2 is introduced in `rippled` version 2.0. Users can request it explicitly by specifying `"api_version" : 2`. - -#### Removed methods - -In API version 2, the following deprecated methods are no longer available: (https://github.com/XRPLF/rippled/pull/4759) - -- `tx_history` - Instead, use other methods such as `account_tx` or `ledger` with the `transactions` field set to `true`. -- `ledger_header` - Instead, use the `ledger` method. - -#### Modifications to JSON transaction element in V2 - -In API version 2, JSON elements for transaction output have been changed and made consistent for all methods which output transactions. (https://github.com/XRPLF/rippled/pull/4775) -This helps to unify the JSON serialization format of transactions. (https://github.com/XRPLF/clio/issues/722, https://github.com/XRPLF/rippled/issues/4727) - -- JSON transaction element is named `tx_json` -- Binary transaction element is named `tx_blob` -- JSON transaction metadata element is named `meta` -- Binary transaction metadata element is named `meta_blob` - -Additionally, these elements are now consistently available next to `tx_json` (i.e. sibling elements), where possible: - -- `hash` - Transaction ID. This data was stored inside transaction output in API version 1, but in API version 2 is a sibling element. -- `ledger_index` - Ledger index (only set on validated ledgers) -- `ledger_hash` - Ledger hash (only set on closed or validated ledgers) -- `close_time_iso` - Ledger close time expressed in ISO 8601 time format (only set on validated ledgers) -- `validated` - Bool element set to `true` if the transaction is in a validated ledger, otherwise `false` - -This change affects the following methods: - -- `tx` - Transaction data moved into element `tx_json` (was inline inside `result`) or, if binary output was requested, moved from `tx` to `tx_blob`. Renamed binary transaction metadata element (if it was requested) from `meta` to `meta_blob`. Changed location of `hash` and added new elements -- `account_tx` - Renamed transaction element from `tx` to `tx_json`. Renamed binary transaction metadata element (if it was requested) from `meta` to `meta_blob`. Changed location of `hash` and added new elements -- `transaction_entry` - Renamed transaction metadata element from `metadata` to `meta`. Changed location of `hash` and added new elements -- `subscribe` - Renamed transaction element from `transaction` to `tx_json`. Changed location of `hash` and added new elements -- `sign`, `sign_for`, `submit` and `submit_multisigned` - Changed location of `hash` element. - -#### Modification to `Payment` transaction JSON schema - -When reading Payments, the `Amount` field should generally **not** be used. Instead, use [delivered_amount](https://xrpl.org/partial-payments.html#the-delivered_amount-field) to see the amount that the Payment delivered. To clarify its meaning, the `Amount` field is being renamed to `DeliverMax`. (https://github.com/XRPLF/rippled/pull/4733) - -- In `Payment` transaction type, JSON RPC field `Amount` is renamed to `DeliverMax`. To enable smooth client transition, `Amount` is still handled, as described below: (https://github.com/XRPLF/rippled/pull/4733) - - On JSON RPC input (e.g. `submit_multisigned` etc. methods), `Amount` is recognized as an alias to `DeliverMax` for both API version 1 and version 2 clients. - - On JSON RPC input, submitting both `Amount` and `DeliverMax` fields is allowed _only_ if they are identical; otherwise such input is rejected with `rpcINVALID_PARAMS` error. - - On JSON RPC output (e.g. `subscribe`, `account_tx` etc. methods), `DeliverMax` is present in both API version 1 and version 2. - - On JSON RPC output, `Amount` is only present in API version 1 and _not_ in version 2. - -#### Modifications to account_info response - -- `signer_lists` is returned in the root of the response. In API version 1, it was nested under `account_data`. (https://github.com/XRPLF/rippled/pull/3770) -- When using an invalid `signer_lists` value, the API now returns an "invalidParams" error. (https://github.com/XRPLF/rippled/pull/4585) - - (`signer_lists` must be a boolean. In API version 1, strings were accepted and may return a normal response - i.e. as if `signer_lists` were `true`.) - -#### Modifications to [account_tx](https://xrpl.org/account_tx.html#account_tx) response - -- Using `ledger_index_min`, `ledger_index_max`, and `ledger_index` returns `invalidParams` because if you use `ledger_index_min` or `ledger_index_max`, then it does not make sense to also specify `ledger_index`. In API version 1, no error was returned. (https://github.com/XRPLF/rippled/pull/4571) - - The same applies for `ledger_index_min`, `ledger_index_max`, and `ledger_hash`. (https://github.com/XRPLF/rippled/issues/4545#issuecomment-1565065579) -- Using a `ledger_index_min` or `ledger_index_max` beyond the range of ledgers that the server has: - - returns `lgrIdxMalformed` in API version 2. Previously, in API version 1, no error was returned. (https://github.com/XRPLF/rippled/issues/4288) -- Attempting to use a non-boolean value (such as a string) for the `binary` or `forward` parameters returns `invalidParams` (`rpcINVALID_PARAMS`). Previously, in API version 1, no error was returned. (https://github.com/XRPLF/rippled/pull/4620) - -#### Modifications to [noripple_check](https://xrpl.org/noripple_check.html#noripple_check) response - -- Attempting to use a non-boolean value (such as a string) for the `transactions` parameter returns `invalidParams` (`rpcINVALID_PARAMS`). Previously, in API version 1, no error was returned. (https://github.com/XRPLF/rippled/pull/4620) - # Unit tests for API changes The following information is useful to developers contributing to this project: From bf4a7b6ce8bffd0e098831d95d056e70a433ccce Mon Sep 17 00:00:00 2001 From: Chenna Keshava B S <21219765+ckeshava@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:09:42 -0400 Subject: [PATCH 56/82] Expand Error Message for rpcInternal (#4959) Validator operators have been confused by the rpcInternal error, which can occur if the server is not running in another process. --- src/xrpld/net/detail/RPCCall.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/xrpld/net/detail/RPCCall.cpp b/src/xrpld/net/detail/RPCCall.cpp index 997d6463f23..c0d2e205434 100644 --- a/src/xrpld/net/detail/RPCCall.cpp +++ b/src/xrpld/net/detail/RPCCall.cpp @@ -1309,7 +1309,10 @@ struct RPCCallImp // Receive reply if (strData.empty()) - Throw("no response from server"); + Throw( + "no response from server. Please " + "ensure that the rippled server is running in another " + "process."); // Parse reply JLOG(j.debug()) << "RPC reply: " << strData << std::endl; From f6d647d6c3041b887ad753309eea917a6a9e5e22 Mon Sep 17 00:00:00 2001 From: John Freeman Date: Fri, 1 Mar 2024 15:05:03 -0600 Subject: [PATCH 57/82] Update clang-format workflow --- .github/workflows/clang-format.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index e86b7b257a5..91bbff48c09 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -4,9 +4,9 @@ on: [push, pull_request] jobs: check: - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 env: - CLANG_VERSION: 10 + CLANG_VERSION: 18 steps: - uses: actions/checkout@v4 - name: Install clang-format @@ -19,8 +19,8 @@ jobs: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add sudo apt-get update sudo apt-get install clang-format-${CLANG_VERSION} - - name: Format sources - run: find include src -type f \( -name '*.cpp' -o -name '*.h' -o -name '*.ipp' \) -exec clang-format-${CLANG_VERSION} -i {} + + - name: Format first-party sources + run: find include src -type f \( -name '*.cpp' -o -name '*.hpp' -o -name '*.h' -o -name '*.ipp' \) -exec clang-format-${CLANG_VERSION} -i {} + - name: Check for differences id: assert run: | @@ -50,7 +50,7 @@ jobs: To fix it, you can do one of two things: 1. Download and apply the patch generated as an artifact of this job to your repo, commit, and push. - 2. Run 'git-clang-format --extensions c,cpp,h,cxx,ipp develop' + 2. Run 'git-clang-format --extensions cpp,h,hpp,ipp develop' in your repo, commit, and push. run: | echo "${PREAMBLE}" From decb3c178e3286ed10d1b6c00301d82531b7b5b1 Mon Sep 17 00:00:00 2001 From: John Freeman Date: Fri, 1 Mar 2024 15:53:25 -0600 Subject: [PATCH 58/82] Update clang-format settings --- .clang-format | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.clang-format b/.clang-format index 0b1b4efea07..1d0f396dd8f 100644 --- a/.clang-format +++ b/.clang-format @@ -58,6 +58,7 @@ IncludeCategories: IncludeIsMainRegex: '$' IndentCaseLabels: true IndentFunctionDeclarationAfterType: false +IndentRequiresClause: true IndentWidth: 4 IndentWrappedFunctionNames: false KeepEmptyLinesAtTheStartOfBlocks: false @@ -73,6 +74,7 @@ PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left ReflowComments: true +RequiresClausePosition: OwnLine SortIncludes: true SpaceAfterCStyleCast: false SpaceBeforeAssignmentOperators: true From e7cd03325b4ef8360d540518d2d4ab1d513a7e3a Mon Sep 17 00:00:00 2001 From: John Freeman Date: Fri, 1 Mar 2024 15:53:38 -0600 Subject: [PATCH 59/82] Update pre-commit hook --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 04893e956f0..9f69d413797 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ # .pre-commit-config.yaml repos: - repo: https://github.com/pre-commit/mirrors-clang-format - rev: v10.0.1 + rev: v18.1.3 hooks: - id: clang-format From 552377c76f55b403a1c876df873a23d780fcc81c Mon Sep 17 00:00:00 2001 From: John Freeman Date: Tue, 15 Oct 2024 18:27:56 -0500 Subject: [PATCH 60/82] Reformat code with clang-format-18 --- include/xrpl/basics/Expected.h | 53 ++-- include/xrpl/basics/FeeUnits.h | 24 +- include/xrpl/basics/IOUAmount.h | 6 +- include/xrpl/basics/Number.h | 6 +- include/xrpl/basics/XRPAmount.h | 6 +- include/xrpl/basics/base_uint.h | 3 +- include/xrpl/basics/safe_cast.h | 4 +- include/xrpl/basics/tagged_integer.h | 3 +- .../container/detail/aged_ordered_container.h | 8 +- .../detail/aged_unordered_container.h | 10 +- include/xrpl/beast/hash/xxhasher.h | 3 +- include/xrpl/beast/unit_test.h | 2 +- include/xrpl/beast/utility/Journal.h | 3 +- include/xrpl/json/json_value.h | 6 +- include/xrpl/protocol/AccountID.h | 2 +- include/xrpl/protocol/ApiVersion.h | 41 ++- include/xrpl/protocol/MultiApiJson.h | 84 +++--- include/xrpl/protocol/STAmount.h | 6 +- include/xrpl/protocol/STBase.h | 6 +- include/xrpl/protocol/STObject.h | 3 +- include/xrpl/protocol/STVector256.h | 3 +- include/xrpl/protocol/TER.h | 57 ++-- include/xrpl/protocol/digest.h | 21 +- include/xrpl/server/detail/BaseHTTPPeer.h | 4 +- src/libxrpl/basics/ResolverAsio.cpp | 6 +- src/libxrpl/beast/insight/NullCollector.cpp | 12 +- .../beast/utility/src/beast_Journal.cpp | 6 +- src/libxrpl/json/Writer.cpp | 3 +- src/libxrpl/protocol/STAmount.cpp | 3 +- src/libxrpl/protocol/STBase.cpp | 3 +- src/libxrpl/protocol/STCurrency.cpp | 3 +- src/libxrpl/protocol/STInteger.cpp | 12 +- src/libxrpl/protocol/STIssue.cpp | 3 +- src/libxrpl/protocol/STParsedJSON.cpp | 3 +- src/libxrpl/protocol/STPathSet.cpp | 3 +- src/libxrpl/protocol/STVector256.cpp | 3 +- src/test/app/NFTokenBurn_test.cpp | 3 +- src/test/app/ValidatorSite_test.cpp | 25 +- src/test/basics/IOUAmount_test.cpp | 91 +++--- src/test/basics/XRPAmount_test.cpp | 104 +++---- src/test/basics/base_uint_test.cpp | 3 +- src/test/beast/beast_Zero_test.cpp | 6 +- .../consensus/ByzantineFailureSim_test.cpp | 4 +- src/test/csf/Peer.h | 3 +- src/test/csf/collectors.h | 225 ++++++-------- src/test/jtx/TestHelpers.h | 10 +- src/test/jtx/TrustedPublisherServer.h | 12 +- src/test/jtx/amount.h | 14 +- src/test/jtx/impl/AMM.cpp | 4 +- src/test/jtx/impl/amount.cpp | 3 +- src/test/jtx/multisign.h | 5 +- src/test/overlay/reduce_relay_test.cpp | 5 +- src/test/protocol/MultiApiJson_test.cpp | 280 +++++------------- src/test/protocol/STObject_test.cpp | 276 ++++++++--------- src/xrpld/app/ledger/LedgerHistory.cpp | 58 ++-- .../app/ledger/detail/TimeoutCounter.cpp | 4 +- src/xrpld/app/main/GRPCServer.cpp | 4 +- src/xrpld/app/misc/AMMHelpers.h | 6 +- src/xrpld/app/misc/NetworkOPs.cpp | 4 +- src/xrpld/app/misc/detail/TxQ.cpp | 10 +- src/xrpld/app/misc/detail/ValidatorList.cpp | 3 +- src/xrpld/app/paths/Pathfinder.cpp | 3 +- src/xrpld/app/paths/detail/BookStep.cpp | 3 +- src/xrpld/app/paths/detail/DirectStep.cpp | 6 +- .../app/paths/detail/XRPEndpointStep.cpp | 3 +- src/xrpld/app/rdb/RelationalDatabase.h | 4 +- src/xrpld/app/tx/detail/CancelOffer.cpp | 8 +- src/xrpld/app/tx/detail/Payment.cpp | 18 +- src/xrpld/app/tx/detail/Transactor.cpp | 6 +- src/xrpld/conditions/detail/PreimageSha256.h | 3 +- src/xrpld/consensus/Consensus.h | 10 +- src/xrpld/consensus/Validations.h | 3 +- src/xrpld/core/DatabaseCon.h | 3 +- src/xrpld/ledger/detail/View.cpp | 6 +- src/xrpld/nodestore/detail/DatabaseNodeImp.h | 3 +- .../nodestore/detail/DatabaseRotatingImp.h | 3 +- src/xrpld/overlay/detail/PeerImp.cpp | 6 +- src/xrpld/overlay/detail/ProtocolVersion.cpp | 2 +- src/xrpld/peerfinder/detail/Logic.h | 6 +- src/xrpld/rpc/detail/ServerHandler.cpp | 6 +- src/xrpld/shamap/detail/TaggedPointer.ipp | 20 +- src/xrpld/unity/rocksdb.h | 2 +- 82 files changed, 808 insertions(+), 902 deletions(-) diff --git a/include/xrpl/basics/Expected.h b/include/xrpl/basics/Expected.h index 745fa50a69f..10f188af11c 100644 --- a/include/xrpl/basics/Expected.h +++ b/include/xrpl/basics/Expected.h @@ -136,44 +136,49 @@ class [[nodiscard]] Expected public: template - requires std::convertible_to constexpr Expected(U && r) - : Base(T(std::forward(r))) + requires std::convertible_to + constexpr Expected(U&& r) : Base(T(std::forward(r))) { } template - requires std::convertible_to && - (!std::is_reference_v)constexpr Expected(Unexpected e) - : Base(E(std::move(e.value()))) + requires std::convertible_to && (!std::is_reference_v) + constexpr Expected(Unexpected e) : Base(E(std::move(e.value()))) { } - constexpr bool has_value() const + constexpr bool + has_value() const { return Base::has_value(); } - constexpr T const& value() const + constexpr T const& + value() const { return Base::value(); } - constexpr T& value() + constexpr T& + value() { return Base::value(); } - constexpr E const& error() const + constexpr E const& + error() const { return Base::error(); } - constexpr E& error() + constexpr E& + error() { return Base::error(); } - constexpr explicit operator bool() const + constexpr explicit + operator bool() const { return has_value(); } @@ -181,22 +186,26 @@ class [[nodiscard]] Expected // Add operator* and operator-> so the Expected API looks a bit more like // what std::expected is likely to look like. See: // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0323r10.html - [[nodiscard]] constexpr T& operator*() + [[nodiscard]] constexpr T& + operator*() { return this->value(); } - [[nodiscard]] constexpr T const& operator*() const + [[nodiscard]] constexpr T const& + operator*() const { return this->value(); } - [[nodiscard]] constexpr T* operator->() + [[nodiscard]] constexpr T* + operator->() { return &this->value(); } - [[nodiscard]] constexpr T const* operator->() const + [[nodiscard]] constexpr T const* + operator->() const { return &this->value(); } @@ -218,23 +227,25 @@ class [[nodiscard]] Expected } template - requires std::convertible_to && - (!std::is_reference_v)constexpr Expected(Unexpected e) - : Base(E(std::move(e.value()))) + requires std::convertible_to && (!std::is_reference_v) + constexpr Expected(Unexpected e) : Base(E(std::move(e.value()))) { } - constexpr E const& error() const + constexpr E const& + error() const { return Base::error(); } - constexpr E& error() + constexpr E& + error() { return Base::error(); } - constexpr explicit operator bool() const + constexpr explicit + operator bool() const { return Base::has_value(); } diff --git a/include/xrpl/basics/FeeUnits.h b/include/xrpl/basics/FeeUnits.h index 9d5e6e216a4..c63a169f00e 100644 --- a/include/xrpl/basics/FeeUnits.h +++ b/include/xrpl/basics/FeeUnits.h @@ -84,13 +84,13 @@ class TaggedFee : private boost::totally_ordered>, protected: template static constexpr bool is_compatible_v = - std::is_arithmetic_v&& std::is_arithmetic_v&& - std::is_convertible_v; + std::is_arithmetic_v && std::is_arithmetic_v && + std::is_convertible_v; template > static constexpr bool is_compatiblefee_v = - is_compatible_v&& - std::is_same_v; + is_compatible_v && + std::is_same_v; template using enable_if_compatible_t = @@ -110,7 +110,8 @@ class TaggedFee : private boost::totally_ordered>, { } - constexpr TaggedFee& operator=(beast::Zero) + constexpr TaggedFee& + operator=(beast::Zero) { fee_ = 0; return *this; @@ -250,7 +251,8 @@ class TaggedFee : private boost::totally_ordered>, } /** Returns true if the amount is not zero */ - explicit constexpr operator bool() const noexcept + explicit constexpr + operator bool() const noexcept { return fee_ != 0; } @@ -344,8 +346,8 @@ constexpr bool can_muldiv_source_v = template > constexpr bool can_muldiv_dest_v = - can_muldiv_source_v&& // Dest is also a source - std::is_convertible_v && + can_muldiv_source_v && // Dest is also a source + std::is_convertible_v && sizeof(typename Dest::value_type) >= sizeof(std::uint64_t); template < @@ -354,8 +356,8 @@ template < class = enable_if_unit_t, class = enable_if_unit_t> constexpr bool can_muldiv_sources_v = - can_muldiv_source_v&& can_muldiv_source_v&& std:: - is_same_v; + can_muldiv_source_v && can_muldiv_source_v && + std::is_same_v; template < class Source1, @@ -365,7 +367,7 @@ template < class = enable_if_unit_t, class = enable_if_unit_t> constexpr bool can_muldiv_v = - can_muldiv_sources_v&& can_muldiv_dest_v; + can_muldiv_sources_v && can_muldiv_dest_v; // Source and Dest can be the same by default template < diff --git a/include/xrpl/basics/IOUAmount.h b/include/xrpl/basics/IOUAmount.h index 221434aa85a..e89feb123d0 100644 --- a/include/xrpl/basics/IOUAmount.h +++ b/include/xrpl/basics/IOUAmount.h @@ -82,7 +82,8 @@ class IOUAmount : private boost::totally_ordered, operator<(IOUAmount const& other) const; /** Returns true if the amount is not zero */ - explicit operator bool() const noexcept; + explicit + operator bool() const noexcept; /** Return the sign of the amount */ int @@ -109,7 +110,8 @@ inline IOUAmount::IOUAmount(std::int64_t mantissa, int exponent) normalize(); } -inline IOUAmount& IOUAmount::operator=(beast::Zero) +inline IOUAmount& +IOUAmount::operator=(beast::Zero) { // The -100 is used to allow 0 to sort less than small positive values // which will have a large negative exponent. diff --git a/include/xrpl/basics/Number.h b/include/xrpl/basics/Number.h index 30ce3f73173..5856ef325dc 100644 --- a/include/xrpl/basics/Number.h +++ b/include/xrpl/basics/Number.h @@ -88,8 +88,10 @@ class Number static constexpr Number lowest() noexcept; - explicit operator XRPAmount() const; // round to nearest, even on tie - explicit operator rep() const; // round to nearest, even on tie + explicit + operator XRPAmount() const; // round to nearest, even on tie + explicit + operator rep() const; // round to nearest, even on tie friend constexpr bool operator==(Number const& x, Number const& y) noexcept diff --git a/include/xrpl/basics/XRPAmount.h b/include/xrpl/basics/XRPAmount.h index 1d3b32f169b..9a322695168 100644 --- a/include/xrpl/basics/XRPAmount.h +++ b/include/xrpl/basics/XRPAmount.h @@ -65,7 +65,8 @@ class XRPAmount : private boost::totally_ordered, { } - constexpr XRPAmount& operator=(beast::Zero) + constexpr XRPAmount& + operator=(beast::Zero) { drops_ = 0; return *this; @@ -155,7 +156,8 @@ class XRPAmount : private boost::totally_ordered, } /** Returns true if the amount is not zero */ - explicit constexpr operator bool() const noexcept + explicit constexpr + operator bool() const noexcept { return drops_ != 0; } diff --git a/include/xrpl/basics/base_uint.h b/include/xrpl/basics/base_uint.h index 2b44d3072ee..88d21c17d22 100644 --- a/include/xrpl/basics/base_uint.h +++ b/include/xrpl/basics/base_uint.h @@ -521,7 +521,8 @@ class base_uint return bytes; } - base_uint& operator=(beast::Zero) + base_uint& + operator=(beast::Zero) { data_.fill(0); return *this; diff --git a/include/xrpl/basics/safe_cast.h b/include/xrpl/basics/safe_cast.h index e52bceca759..f193f1793f2 100644 --- a/include/xrpl/basics/safe_cast.h +++ b/include/xrpl/basics/safe_cast.h @@ -30,8 +30,8 @@ namespace ripple { template static constexpr bool is_safetocasttovalue_v = - (std::is_integral_v && std::is_integral_v)&&( - std::is_signed::value || std::is_unsigned::value) && + (std::is_integral_v && std::is_integral_v) && + (std::is_signed::value || std::is_unsigned::value) && (std::is_signed::value != std::is_signed::value ? sizeof(Dest) > sizeof(Src) : sizeof(Dest) >= sizeof(Src)); diff --git a/include/xrpl/basics/tagged_integer.h b/include/xrpl/basics/tagged_integer.h index 3ab8c534098..4629e830916 100644 --- a/include/xrpl/basics/tagged_integer.h +++ b/include/xrpl/basics/tagged_integer.h @@ -187,7 +187,8 @@ class tagged_integer return *this; } - explicit operator Int() const noexcept + explicit + operator Int() const noexcept { return m_value; } diff --git a/include/xrpl/beast/container/detail/aged_ordered_container.h b/include/xrpl/beast/container/detail/aged_ordered_container.h index 90a8ea147ae..ad807e92cfe 100644 --- a/include/xrpl/beast/container/detail/aged_ordered_container.h +++ b/include/xrpl/beast/container/detail/aged_ordered_container.h @@ -846,8 +846,9 @@ class aged_ordered_container // set template auto - insert(value_type&& value) -> typename std:: - enable_if>::type; + insert(value_type&& value) -> typename std::enable_if< + !maybe_multi && !maybe_map, + std::pair>::type; // multiset template @@ -1795,7 +1796,8 @@ template < template auto aged_ordered_container:: - insert(value_type&& value) -> typename std:: + insert(value_type&& value) -> + typename std:: enable_if>::type { typename cont_type::insert_commit_data d; diff --git a/include/xrpl/beast/container/detail/aged_unordered_container.h b/include/xrpl/beast/container/detail/aged_unordered_container.h index 45efb3f5561..72e3334801b 100644 --- a/include/xrpl/beast/container/detail/aged_unordered_container.h +++ b/include/xrpl/beast/container/detail/aged_unordered_container.h @@ -1057,8 +1057,9 @@ class aged_unordered_container // map, set template auto - insert(value_type&& value) -> typename std:: - enable_if>::type; + insert(value_type&& value) -> typename std::enable_if< + !maybe_multi && !maybe_map, + std::pair>::type; // multimap, multiset template @@ -2799,8 +2800,9 @@ aged_unordered_container< Clock, Hash, KeyEqual, - Allocator>::insert(value_type&& value) -> typename std:: - enable_if>::type + Allocator>::insert(value_type&& value) -> + typename std:: + enable_if>::type { maybe_rehash(1); typename cont_type::insert_commit_data d; diff --git a/include/xrpl/beast/hash/xxhasher.h b/include/xrpl/beast/hash/xxhasher.h index 1a6fc502321..30af05ef0a1 100644 --- a/include/xrpl/beast/hash/xxhasher.h +++ b/include/xrpl/beast/hash/xxhasher.h @@ -90,7 +90,8 @@ class xxhasher XXH3_64bits_update(state_, key, len); } - explicit operator std::size_t() noexcept + explicit + operator std::size_t() noexcept { return XXH3_64bits_digest(state_); } diff --git a/include/xrpl/beast/unit_test.h b/include/xrpl/beast/unit_test.h index eff82583ea7..bf33b205e62 100644 --- a/include/xrpl/beast/unit_test.h +++ b/include/xrpl/beast/unit_test.h @@ -34,7 +34,7 @@ #ifndef BEAST_EXPECT #define BEAST_EXPECT_S1(x) #x #define BEAST_EXPECT_S2(x) BEAST_EXPECT_S1(x) -//#define BEAST_EXPECT(cond) {expect(cond, __FILE__ ":" ## +// #define BEAST_EXPECT(cond) {expect(cond, __FILE__ ":" ## //__LINE__);}while(false){} #define BEAST_EXPECT(cond) expect(cond, __FILE__ ":" BEAST_EXPECT_S2(__LINE__)) #endif diff --git a/include/xrpl/beast/utility/Journal.h b/include/xrpl/beast/utility/Journal.h index 0738748b6c5..059355ccae7 100644 --- a/include/xrpl/beast/utility/Journal.h +++ b/include/xrpl/beast/utility/Journal.h @@ -238,7 +238,8 @@ class Journal return m_sink.active(m_level); } - explicit operator bool() const + explicit + operator bool() const { return active(); } diff --git a/include/xrpl/json/json_value.h b/include/xrpl/json/json_value.h index c2f9184d79a..e419940171e 100644 --- a/include/xrpl/json/json_value.h +++ b/include/xrpl/json/json_value.h @@ -64,7 +64,8 @@ class StaticString { } - constexpr operator const char*() const + constexpr + operator const char*() const { return str_; } @@ -296,7 +297,8 @@ class Value /** Returns false if this is an empty array, empty object, empty string, or null. */ - explicit operator bool() const; + explicit + operator bool() const; /// Remove all object members and array elements. /// \pre type() is arrayValue, objectValue, or nullValue diff --git a/include/xrpl/protocol/AccountID.h b/include/xrpl/protocol/AccountID.h index ebe7f014d9c..7edf8d388f7 100644 --- a/include/xrpl/protocol/AccountID.h +++ b/include/xrpl/protocol/AccountID.h @@ -22,7 +22,7 @@ #include // VFALCO Uncomment when the header issues are resolved -//#include +// #include #include #include #include diff --git a/include/xrpl/protocol/ApiVersion.h b/include/xrpl/protocol/ApiVersion.h index 1cd03b0651d..dd09cf6bd1a 100644 --- a/include/xrpl/protocol/ApiVersion.h +++ b/include/xrpl/protocol/ApiVersion.h @@ -76,38 +76,35 @@ static_assert(apiMaximumValidVersion >= apiMaximumSupportedVersion); } // namespace RPC template - void - forApiVersions(Fn const& fn, Args&&... args) requires // - (maxVer >= minVer) && // - (minVer >= RPC::apiMinimumSupportedVersion) && // - (RPC::apiMaximumValidVersion >= maxVer) && - requires -{ - fn(std::integral_constant{}, - std::forward(args)...); - fn(std::integral_constant{}, - std::forward(args)...); -} +void +forApiVersions(Fn const& fn, Args&&... args) + requires // + (maxVer >= minVer) && // + (minVer >= RPC::apiMinimumSupportedVersion) && // + (RPC::apiMaximumValidVersion >= maxVer) && requires { + fn(std::integral_constant{}, + std::forward(args)...); + fn(std::integral_constant{}, + std::forward(args)...); + } { constexpr auto size = maxVer + 1 - minVer; - [&](std::index_sequence) - { + [&](std::index_sequence) { (((void)fn( std::integral_constant{}, std::forward(args)...)), ...); - } - (std::make_index_sequence{}); + }(std::make_index_sequence{}); } template void -forAllApiVersions(Fn const& fn, Args&&... args) requires requires -{ - forApiVersions< - RPC::apiMinimumSupportedVersion, - RPC::apiMaximumValidVersion>(fn, std::forward(args)...); -} +forAllApiVersions(Fn const& fn, Args&&... args) + requires requires { + forApiVersions< + RPC::apiMinimumSupportedVersion, + RPC::apiMaximumValidVersion>(fn, std::forward(args)...); + } { forApiVersions< RPC::apiMinimumSupportedVersion, diff --git a/include/xrpl/protocol/MultiApiJson.h b/include/xrpl/protocol/MultiApiJson.h index 4514c54ea34..73c274ff7f7 100644 --- a/include/xrpl/protocol/MultiApiJson.h +++ b/include/xrpl/protocol/MultiApiJson.h @@ -80,9 +80,8 @@ struct MultiApiJson } void - set(const char* key, - auto const& - v) requires std::constructible_from + set(const char* key, auto const& v) + requires std::constructible_from { for (auto& a : this->val) a[key] = v; @@ -110,7 +109,8 @@ struct MultiApiJson unsigned int Version, typename... Args, typename Fn> - requires std::same_as, MultiApiJson> auto + requires std::same_as, MultiApiJson> + auto operator()( Json& json, std::integral_constant const version, @@ -133,7 +133,8 @@ struct MultiApiJson // integral_constant version, Json only template - requires std::same_as, MultiApiJson> auto + requires std::same_as, MultiApiJson> + auto operator()( Json& json, std::integral_constant const, @@ -151,10 +152,10 @@ struct MultiApiJson typename... Args, typename Fn> requires(!some_integral_constant) && - std::convertible_to&& std::same_as< - std::remove_cvref_t, - MultiApiJson> auto - operator()(Json& json, Version version, Fn fn, Args&&... args) const + std::convertible_to && + std::same_as, MultiApiJson> + auto + operator()(Json& json, Version version, Fn fn, Args&&... args) const -> std:: invoke_result_t { @@ -170,9 +171,10 @@ struct MultiApiJson // unsigned int version, Json only template requires(!some_integral_constant) && - std::convertible_to&& std:: - same_as, MultiApiJson> auto - operator()(Json& json, Version version, Fn fn) const + std::convertible_to && + std::same_as, MultiApiJson> + auto + operator()(Json& json, Version version, Fn fn) const -> std::invoke_result_t { assert( @@ -184,53 +186,43 @@ struct MultiApiJson auto visit() { - return [self = this](auto... args) requires requires - { - visitor( - std::declval(), - std::declval()...); - } - { - return visitor(*self, std::forward(args)...); - }; + return [self = this](auto... args) + requires requires { + visitor( + std::declval(), + std::declval()...); + } + { return visitor(*self, std::forward(args)...); }; } auto visit() const { - return [self = this](auto... args) requires requires - { - visitor( - std::declval(), - std::declval()...); - } - { - return visitor(*self, std::forward(args)...); - }; + return [self = this](auto... args) + requires requires { + visitor( + std::declval(), + std::declval()...); + } + { return visitor(*self, std::forward(args)...); }; } template - auto - visit(Args... args) - -> std::invoke_result_t requires( - sizeof...(args) > 0) && - requires - { - visitor(*this, std::forward(args)...); - } + auto + visit(Args... args) + -> std::invoke_result_t + requires(sizeof...(args) > 0) && + requires { visitor(*this, std::forward(args)...); } { return visitor(*this, std::forward(args)...); } template - auto - visit(Args... args) const -> std:: - invoke_result_t requires( - sizeof...(args) > 0) && - requires - { - visitor(*this, std::forward(args)...); - } + auto + visit(Args... args) const + -> std::invoke_result_t + requires(sizeof...(args) > 0) && + requires { visitor(*this, std::forward(args)...); } { return visitor(*this, std::forward(args)...); } diff --git a/include/xrpl/protocol/STAmount.h b/include/xrpl/protocol/STAmount.h index 3eed0860f54..34f82d4cebb 100644 --- a/include/xrpl/protocol/STAmount.h +++ b/include/xrpl/protocol/STAmount.h @@ -197,7 +197,8 @@ class STAmount final : public STBase, public CountedObject // //-------------------------------------------------------------------------- - explicit operator bool() const noexcept; + explicit + operator bool() const noexcept; STAmount& operator+=(STAmount const&); @@ -388,7 +389,8 @@ inline STAmount::operator Number() const return iou(); } -inline STAmount& STAmount::operator=(beast::Zero) +inline STAmount& +STAmount::operator=(beast::Zero) { clear(); return *this; diff --git a/include/xrpl/protocol/STBase.h b/include/xrpl/protocol/STBase.h index e13ef6c5b3e..097341384f3 100644 --- a/include/xrpl/protocol/STBase.h +++ b/include/xrpl/protocol/STBase.h @@ -52,11 +52,13 @@ struct JsonOptions { } - [[nodiscard]] constexpr explicit operator underlying_t() const noexcept + [[nodiscard]] constexpr explicit + operator underlying_t() const noexcept { return value; } - [[nodiscard]] constexpr explicit operator bool() const noexcept + [[nodiscard]] constexpr explicit + operator bool() const noexcept { return value != 0u; } diff --git a/include/xrpl/protocol/STObject.h b/include/xrpl/protocol/STObject.h index b3cef83de5f..a226733e986 100644 --- a/include/xrpl/protocol/STObject.h +++ b/include/xrpl/protocol/STObject.h @@ -539,7 +539,8 @@ class STObject::OptionalProxy : private Proxy Fields with soeDEFAULT and set to the default value will return `true` */ - explicit operator bool() const noexcept; + explicit + operator bool() const noexcept; /** Return the contained value diff --git a/include/xrpl/protocol/STVector256.h b/include/xrpl/protocol/STVector256.h index e70297a40bf..d81ddf977ff 100644 --- a/include/xrpl/protocol/STVector256.h +++ b/include/xrpl/protocol/STVector256.h @@ -65,7 +65,8 @@ class STVector256 : public STBase, public CountedObject setValue(const STVector256& v); /** Retrieve a copy of the vector we contain */ - explicit operator std::vector() const; + explicit + operator std::vector() const; std::size_t size() const; diff --git a/include/xrpl/protocol/TER.h b/include/xrpl/protocol/TER.h index aae3c7107bd..5b659249dfd 100644 --- a/include/xrpl/protocol/TER.h +++ b/include/xrpl/protocol/TER.h @@ -434,7 +434,8 @@ class TERSubset } // Conversion to bool. - explicit operator bool() const + explicit + operator bool() const { return code_ != tesSUCCESS; } @@ -480,60 +481,66 @@ class TERSubset // Only enabled if both arguments return int if TERtiInt is called with them. template constexpr auto -operator==(L const& lhs, R const& rhs) -> std::enable_if_t< - std::is_same::value && - std::is_same::value, - bool> +operator==(L const& lhs, R const& rhs) + -> std::enable_if_t< + std::is_same::value && + std::is_same::value, + bool> { return TERtoInt(lhs) == TERtoInt(rhs); } template constexpr auto -operator!=(L const& lhs, R const& rhs) -> std::enable_if_t< - std::is_same::value && - std::is_same::value, - bool> +operator!=(L const& lhs, R const& rhs) + -> std::enable_if_t< + std::is_same::value && + std::is_same::value, + bool> { return TERtoInt(lhs) != TERtoInt(rhs); } template constexpr auto -operator<(L const& lhs, R const& rhs) -> std::enable_if_t< - std::is_same::value && - std::is_same::value, - bool> +operator<(L const& lhs, R const& rhs) + -> std::enable_if_t< + std::is_same::value && + std::is_same::value, + bool> { return TERtoInt(lhs) < TERtoInt(rhs); } template constexpr auto -operator<=(L const& lhs, R const& rhs) -> std::enable_if_t< - std::is_same::value && - std::is_same::value, - bool> +operator<=(L const& lhs, R const& rhs) + -> std::enable_if_t< + std::is_same::value && + std::is_same::value, + bool> { return TERtoInt(lhs) <= TERtoInt(rhs); } template constexpr auto -operator>(L const& lhs, R const& rhs) -> std::enable_if_t< - std::is_same::value && - std::is_same::value, - bool> +operator>(L const& lhs, R const& rhs) + -> std::enable_if_t< + std::is_same::value && + std::is_same::value, + bool> { return TERtoInt(lhs) > TERtoInt(rhs); } template constexpr auto -operator>=(L const& lhs, R const& rhs) -> std::enable_if_t< - std::is_same::value && - std::is_same::value, - bool> +operator>=(L const& lhs, R const& rhs) + -> std::enable_if_t< + std::is_same::value && + std::is_same::value, + bool> { return TERtoInt(lhs) >= TERtoInt(rhs); } diff --git a/include/xrpl/protocol/digest.h b/include/xrpl/protocol/digest.h index f3fc2ea5c5d..b3c7a014100 100644 --- a/include/xrpl/protocol/digest.h +++ b/include/xrpl/protocol/digest.h @@ -55,7 +55,8 @@ struct openssl_ripemd160_hasher void operator()(void const* data, std::size_t size) noexcept; - explicit operator result_type() noexcept; + explicit + operator result_type() noexcept; private: char ctx_[96]; @@ -77,7 +78,8 @@ struct openssl_sha512_hasher void operator()(void const* data, std::size_t size) noexcept; - explicit operator result_type() noexcept; + explicit + operator result_type() noexcept; private: char ctx_[216]; @@ -99,7 +101,8 @@ struct openssl_sha256_hasher void operator()(void const* data, std::size_t size) noexcept; - explicit operator result_type() noexcept; + explicit + operator result_type() noexcept; private: char ctx_[112]; @@ -144,7 +147,8 @@ struct ripesha_hasher h_(data, size); } - explicit operator result_type() noexcept + explicit + operator result_type() noexcept { auto const d0 = sha256_hasher::result_type(h_); ripemd160_hasher rh; @@ -184,18 +188,21 @@ struct basic_sha512_half_hasher h_(data, size); } - explicit operator result_type() noexcept + explicit + operator result_type() noexcept { auto const digest = sha512_hasher::result_type(h_); return result_type::fromVoid(digest.data()); } private: - inline void erase(std::false_type) + inline void + erase(std::false_type) { } - inline void erase(std::true_type) + inline void + erase(std::true_type) { secure_erase(&h_, sizeof(h_)); } diff --git a/include/xrpl/server/detail/BaseHTTPPeer.h b/include/xrpl/server/detail/BaseHTTPPeer.h index 171eb7134e1..32ec4d3009d 100644 --- a/include/xrpl/server/detail/BaseHTTPPeer.h +++ b/include/xrpl/server/detail/BaseHTTPPeer.h @@ -244,7 +244,7 @@ BaseHTTPPeer::close() return post( strand_, std::bind( - (void (BaseHTTPPeer::*)(void)) & BaseHTTPPeer::close, + (void(BaseHTTPPeer::*)(void)) & BaseHTTPPeer::close, impl().shared_from_this())); boost::beast::get_lowest_layer(impl().stream_).close(); } @@ -507,7 +507,7 @@ BaseHTTPPeer::close(bool graceful) return post( strand_, std::bind( - (void (BaseHTTPPeer::*)(bool)) & + (void(BaseHTTPPeer::*)(bool)) & BaseHTTPPeer::close, impl().shared_from_this(), graceful)); diff --git a/src/libxrpl/basics/ResolverAsio.cpp b/src/libxrpl/basics/ResolverAsio.cpp index 53530da9d8f..7105eb12a74 100644 --- a/src/libxrpl/basics/ResolverAsio.cpp +++ b/src/libxrpl/basics/ResolverAsio.cpp @@ -232,7 +232,8 @@ class ResolverAsioImpl : public ResolverAsio, //------------------------------------------------------------------------- // Resolver - void do_stop(CompletionCounter) + void + do_stop(CompletionCounter) { assert(m_stop_called == true); @@ -330,7 +331,8 @@ class ResolverAsioImpl : public ResolverAsio, std::string(port_first, port_last)); } - void do_work(CompletionCounter) + void + do_work(CompletionCounter) { if (m_stop_called == true) return; diff --git a/src/libxrpl/beast/insight/NullCollector.cpp b/src/libxrpl/beast/insight/NullCollector.cpp index 637cd06ec3b..12ea817014e 100644 --- a/src/libxrpl/beast/insight/NullCollector.cpp +++ b/src/libxrpl/beast/insight/NullCollector.cpp @@ -41,7 +41,8 @@ class NullCounterImpl : public CounterImpl public: explicit NullCounterImpl() = default; - void increment(value_type) override + void + increment(value_type) override { } @@ -74,11 +75,13 @@ class NullGaugeImpl : public GaugeImpl public: explicit NullGaugeImpl() = default; - void set(value_type) override + void + set(value_type) override { } - void increment(difference_type) override + void + increment(difference_type) override { } @@ -94,7 +97,8 @@ class NullMeterImpl : public MeterImpl public: explicit NullMeterImpl() = default; - void increment(value_type) override + void + increment(value_type) override { } diff --git a/src/libxrpl/beast/utility/src/beast_Journal.cpp b/src/libxrpl/beast/utility/src/beast_Journal.cpp index 261e1f6ccab..8ce7ea8d47c 100644 --- a/src/libxrpl/beast/utility/src/beast_Journal.cpp +++ b/src/libxrpl/beast/utility/src/beast_Journal.cpp @@ -34,7 +34,8 @@ class NullJournalSink : public Journal::Sink ~NullJournalSink() override = default; - bool active(severities::Severity) const override + bool + active(severities::Severity) const override { return false; } @@ -56,7 +57,8 @@ class NullJournalSink : public Journal::Sink return severities::kDisabled; } - void threshold(severities::Severity) override + void + threshold(severities::Severity) override { } diff --git a/src/libxrpl/json/Writer.cpp b/src/libxrpl/json/Writer.cpp index ba7336209e6..2f7c0b523c6 100644 --- a/src/libxrpl/json/Writer.cpp +++ b/src/libxrpl/json/Writer.cpp @@ -285,7 +285,8 @@ Writer::output(double f) impl_->output({s.data(), lengthWithoutTrailingZeros(s)}); } -void Writer::output(std::nullptr_t) +void +Writer::output(std::nullptr_t) { impl_->output("null"); } diff --git a/src/libxrpl/protocol/STAmount.cpp b/src/libxrpl/protocol/STAmount.cpp index 236603d6cb8..bb9a24c1271 100644 --- a/src/libxrpl/protocol/STAmount.cpp +++ b/src/libxrpl/protocol/STAmount.cpp @@ -650,7 +650,8 @@ STAmount::getText() const return ret; } -Json::Value STAmount::getJson(JsonOptions) const +Json::Value +STAmount::getJson(JsonOptions) const { Json::Value elem; setJson(elem); diff --git a/src/libxrpl/protocol/STBase.cpp b/src/libxrpl/protocol/STBase.cpp index b7e9c94ca24..73565cbf765 100644 --- a/src/libxrpl/protocol/STBase.cpp +++ b/src/libxrpl/protocol/STBase.cpp @@ -96,7 +96,8 @@ STBase::getText() const return std::string(); } -Json::Value STBase::getJson(JsonOptions /*options*/) const +Json::Value +STBase::getJson(JsonOptions /*options*/) const { return getText(); } diff --git a/src/libxrpl/protocol/STCurrency.cpp b/src/libxrpl/protocol/STCurrency.cpp index c8fc650135a..56ac19da114 100644 --- a/src/libxrpl/protocol/STCurrency.cpp +++ b/src/libxrpl/protocol/STCurrency.cpp @@ -50,7 +50,8 @@ STCurrency::getText() const return to_string(currency_); } -Json::Value STCurrency::getJson(JsonOptions) const +Json::Value +STCurrency::getJson(JsonOptions) const { return to_string(currency_); } diff --git a/src/libxrpl/protocol/STInteger.cpp b/src/libxrpl/protocol/STInteger.cpp index 7b7420006f9..af0c18a5155 100644 --- a/src/libxrpl/protocol/STInteger.cpp +++ b/src/libxrpl/protocol/STInteger.cpp @@ -61,7 +61,8 @@ STUInt8::getText() const } template <> -Json::Value STUInt8::getJson(JsonOptions) const +Json::Value +STUInt8::getJson(JsonOptions) const { if (getFName() == sfTransactionResult) { @@ -118,7 +119,8 @@ STUInt16::getText() const } template <> -Json::Value STUInt16::getJson(JsonOptions) const +Json::Value +STUInt16::getJson(JsonOptions) const { if (getFName() == sfLedgerEntryType) { @@ -164,7 +166,8 @@ STUInt32::getText() const } template <> -Json::Value STUInt32::getJson(JsonOptions) const +Json::Value +STUInt32::getJson(JsonOptions) const { return value_; } @@ -192,7 +195,8 @@ STUInt64::getText() const } template <> -Json::Value STUInt64::getJson(JsonOptions) const +Json::Value +STUInt64::getJson(JsonOptions) const { std::string str(16, 0); auto ret = std::to_chars(str.data(), str.data() + str.size(), value_, 16); diff --git a/src/libxrpl/protocol/STIssue.cpp b/src/libxrpl/protocol/STIssue.cpp index 9dcee6498ab..00fe86b3287 100644 --- a/src/libxrpl/protocol/STIssue.cpp +++ b/src/libxrpl/protocol/STIssue.cpp @@ -65,7 +65,8 @@ STIssue::getSType() const return STI_ISSUE; } -Json::Value STIssue::getJson(JsonOptions) const +Json::Value +STIssue::getJson(JsonOptions) const { return to_json(issue_); } diff --git a/src/libxrpl/protocol/STParsedJSON.cpp b/src/libxrpl/protocol/STParsedJSON.cpp index dec5e87eaee..327b9ee31c4 100644 --- a/src/libxrpl/protocol/STParsedJSON.cpp +++ b/src/libxrpl/protocol/STParsedJSON.cpp @@ -967,8 +967,7 @@ parseArray( Json::Value const objectFields(json[i][objectName]); std::stringstream ss; - ss << json_name << "." - << "[" << i << "]." << objectName; + ss << json_name << "." << "[" << i << "]." << objectName; auto ret = parseObject( ss.str(), objectFields, nameField, depth + 1, error); diff --git a/src/libxrpl/protocol/STPathSet.cpp b/src/libxrpl/protocol/STPathSet.cpp index b658465272e..78c47cadc66 100644 --- a/src/libxrpl/protocol/STPathSet.cpp +++ b/src/libxrpl/protocol/STPathSet.cpp @@ -163,7 +163,8 @@ STPath::hasSeen( return false; } -Json::Value STPath::getJson(JsonOptions) const +Json::Value +STPath::getJson(JsonOptions) const { Json::Value ret(Json::arrayValue); diff --git a/src/libxrpl/protocol/STVector256.cpp b/src/libxrpl/protocol/STVector256.cpp index 2d8bc4ee225..385c0ef76db 100644 --- a/src/libxrpl/protocol/STVector256.cpp +++ b/src/libxrpl/protocol/STVector256.cpp @@ -80,7 +80,8 @@ STVector256::isEquivalent(const STBase& t) const return v && (mValue == v->mValue); } -Json::Value STVector256::getJson(JsonOptions) const +Json::Value +STVector256::getJson(JsonOptions) const { Json::Value ret(Json::arrayValue); diff --git a/src/test/app/NFTokenBurn_test.cpp b/src/test/app/NFTokenBurn_test.cpp index 35a8858f868..a84ac63da9d 100644 --- a/src/test/app/NFTokenBurn_test.cpp +++ b/src/test/app/NFTokenBurn_test.cpp @@ -323,7 +323,8 @@ class NFTokenBurnBaseUtil_test : public beast::unit_test::suite // Otherwise either alice or minter can burn. AcctStat& burner = owner.acct == becky.acct ? *(stats[acctDist(engine)]) - : mintDist(engine) ? alice : minter; + : mintDist(engine) ? alice + : minter; if (owner.acct == burner.acct) env(token::burn(burner, nft)); diff --git a/src/test/app/ValidatorSite_test.cpp b/src/test/app/ValidatorSite_test.cpp index 4bc7f2f270d..1ec302efef8 100644 --- a/src/test/app/ValidatorSite_test.cpp +++ b/src/test/app/ValidatorSite_test.cpp @@ -78,20 +78,21 @@ class ValidatorSite_test : public beast::unit_test::suite BEAST_EXPECT(trustedSites->load(emptyCfgSites)); // load should accept valid validator site uris - std::vector cfgSites({ - "http://ripple.com/", "http://ripple.com/validators", - "http://ripple.com:8080/validators", - "http://207.261.33.37/validators", - "http://207.261.33.37:8080/validators", - "https://ripple.com/validators", - "https://ripple.com:443/validators", - "file:///etc/opt/ripple/validators.txt", - "file:///C:/Lib/validators.txt" + std::vector cfgSites( + {"http://ripple.com/", + "http://ripple.com/validators", + "http://ripple.com:8080/validators", + "http://207.261.33.37/validators", + "http://207.261.33.37:8080/validators", + "https://ripple.com/validators", + "https://ripple.com:443/validators", + "file:///etc/opt/ripple/validators.txt", + "file:///C:/Lib/validators.txt" #if !_MSC_VER - , - "file:///" + , + "file:///" #endif - }); + }); BEAST_EXPECT(trustedSites->load(cfgSites)); // load should reject validator site uris with invalid schemes diff --git a/src/test/basics/IOUAmount_test.cpp b/src/test/basics/IOUAmount_test.cpp index 6e7c662635f..e588a08dc02 100644 --- a/src/test/basics/IOUAmount_test.cpp +++ b/src/test/basics/IOUAmount_test.cpp @@ -219,55 +219,56 @@ class IOUAmount_test : public beast::unit_test::suite tinyNeg == mulRatio(tinyNeg, maxUInt - 1, maxUInt, false)); } - {// rounding - {IOUAmount one(1, 0); - auto const rup = mulRatio(one, maxUInt - 1, maxUInt, true); - auto const rdown = mulRatio(one, maxUInt - 1, maxUInt, false); - BEAST_EXPECT(rup.mantissa() - rdown.mantissa() == 1); - } - { - IOUAmount big(maxMantissa, maxExponent); - auto const rup = mulRatio(big, maxUInt - 1, maxUInt, true); - auto const rdown = mulRatio(big, maxUInt - 1, maxUInt, false); - BEAST_EXPECT(rup.mantissa() - rdown.mantissa() == 1); - } - - { - IOUAmount negOne(-1, 0); - auto const rup = mulRatio(negOne, maxUInt - 1, maxUInt, true); - auto const rdown = mulRatio(negOne, maxUInt - 1, maxUInt, false); - BEAST_EXPECT(rup.mantissa() - rdown.mantissa() == 1); - } -} + { // rounding + { + IOUAmount one(1, 0); + auto const rup = mulRatio(one, maxUInt - 1, maxUInt, true); + auto const rdown = mulRatio(one, maxUInt - 1, maxUInt, false); + BEAST_EXPECT(rup.mantissa() - rdown.mantissa() == 1); + } + { + IOUAmount big(maxMantissa, maxExponent); + auto const rup = mulRatio(big, maxUInt - 1, maxUInt, true); + auto const rdown = mulRatio(big, maxUInt - 1, maxUInt, false); + BEAST_EXPECT(rup.mantissa() - rdown.mantissa() == 1); + } + + { + IOUAmount negOne(-1, 0); + auto const rup = mulRatio(negOne, maxUInt - 1, maxUInt, true); + auto const rdown = + mulRatio(negOne, maxUInt - 1, maxUInt, false); + BEAST_EXPECT(rup.mantissa() - rdown.mantissa() == 1); + } + } -{ - // division by zero - IOUAmount one(1, 0); - except([&] { mulRatio(one, 1, 0, true); }); -} + { + // division by zero + IOUAmount one(1, 0); + except([&] { mulRatio(one, 1, 0, true); }); + } -{ - // overflow - IOUAmount big(maxMantissa, maxExponent); - except([&] { mulRatio(big, 2, 0, true); }); -} -} // namespace ripple + { + // overflow + IOUAmount big(maxMantissa, maxExponent); + except([&] { mulRatio(big, 2, 0, true); }); + } + } // namespace ripple -//-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- -void -run() override -{ - testZero(); - testSigNum(); - testBeastZero(); - testComparisons(); - testToString(); - testMulRatio(); -} -} -; + void + run() override + { + testZero(); + testSigNum(); + testBeastZero(); + testComparisons(); + testToString(); + testMulRatio(); + } +}; BEAST_DEFINE_TESTSUITE(IOUAmount, protocol, ripple); -} // ripple +} // namespace ripple diff --git a/src/test/basics/XRPAmount_test.cpp b/src/test/basics/XRPAmount_test.cpp index c4c96dbfbde..c57890fcfa5 100644 --- a/src/test/basics/XRPAmount_test.cpp +++ b/src/test/basics/XRPAmount_test.cpp @@ -283,63 +283,67 @@ class XRPAmount_test : public beast::unit_test::suite tinyNeg == mulRatio(tinyNeg, maxUInt32 - 1, maxUInt32, false)); } - {// rounding - {XRPAmount one(1); - auto const rup = mulRatio(one, maxUInt32 - 1, maxUInt32, true); - auto const rdown = mulRatio(one, maxUInt32 - 1, maxUInt32, false); - BEAST_EXPECT(rup.drops() - rdown.drops() == 1); - } + { // rounding + { + XRPAmount one(1); + auto const rup = mulRatio(one, maxUInt32 - 1, maxUInt32, true); + auto const rdown = + mulRatio(one, maxUInt32 - 1, maxUInt32, false); + BEAST_EXPECT(rup.drops() - rdown.drops() == 1); + } - { - XRPAmount big(maxXRP); - auto const rup = mulRatio(big, maxUInt32 - 1, maxUInt32, true); - auto const rdown = mulRatio(big, maxUInt32 - 1, maxUInt32, false); - BEAST_EXPECT(rup.drops() - rdown.drops() == 1); - } + { + XRPAmount big(maxXRP); + auto const rup = mulRatio(big, maxUInt32 - 1, maxUInt32, true); + auto const rdown = + mulRatio(big, maxUInt32 - 1, maxUInt32, false); + BEAST_EXPECT(rup.drops() - rdown.drops() == 1); + } - { - XRPAmount negOne(-1); - auto const rup = mulRatio(negOne, maxUInt32 - 1, maxUInt32, true); - auto const rdown = mulRatio(negOne, maxUInt32 - 1, maxUInt32, false); - BEAST_EXPECT(rup.drops() - rdown.drops() == 1); - } -} + { + XRPAmount negOne(-1); + auto const rup = + mulRatio(negOne, maxUInt32 - 1, maxUInt32, true); + auto const rdown = + mulRatio(negOne, maxUInt32 - 1, maxUInt32, false); + BEAST_EXPECT(rup.drops() - rdown.drops() == 1); + } + } -{ - // division by zero - XRPAmount one(1); - except([&] { mulRatio(one, 1, 0, true); }); -} + { + // division by zero + XRPAmount one(1); + except([&] { mulRatio(one, 1, 0, true); }); + } -{ - // overflow - XRPAmount big(maxXRP); - except([&] { mulRatio(big, 2, 1, true); }); -} + { + // overflow + XRPAmount big(maxXRP); + except([&] { mulRatio(big, 2, 1, true); }); + } -{ - // underflow - XRPAmount bigNegative(minXRP + 10); - BEAST_EXPECT(mulRatio(bigNegative, 2, 1, true) == minXRP); -} -} // namespace ripple + { + // underflow + XRPAmount bigNegative(minXRP + 10); + BEAST_EXPECT(mulRatio(bigNegative, 2, 1, true) == minXRP); + } + } // namespace ripple -//-------------------------------------------------------------------------- + //-------------------------------------------------------------------------- -void -run() override -{ - testSigNum(); - testBeastZero(); - testComparisons(); - testAddSub(); - testDecimal(); - testFunctions(); - testMulRatio(); -} -} -; + void + run() override + { + testSigNum(); + testBeastZero(); + testComparisons(); + testAddSub(); + testDecimal(); + testFunctions(); + testMulRatio(); + } +}; BEAST_DEFINE_TESTSUITE(XRPAmount, protocol, ripple); -} // ripple +} // namespace ripple diff --git a/src/test/basics/base_uint_test.cpp b/src/test/basics/base_uint_test.cpp index 43000a1128c..9f3194f4fbc 100644 --- a/src/test/basics/base_uint_test.cpp +++ b/src/test/basics/base_uint_test.cpp @@ -48,7 +48,8 @@ struct nonhash memcpy(data_.data(), key, len); } - explicit operator std::size_t() noexcept + explicit + operator std::size_t() noexcept { return WIDTH; } diff --git a/src/test/beast/beast_Zero_test.cpp b/src/test/beast/beast_Zero_test.cpp index b6071636255..8fd16a4d51f 100644 --- a/src/test/beast/beast_Zero_test.cpp +++ b/src/test/beast/beast_Zero_test.cpp @@ -27,7 +27,8 @@ struct adl_tester { }; -int signum(adl_tester) +int +signum(adl_tester) { return 0; } @@ -38,7 +39,8 @@ struct adl_tester2 { }; -int signum(adl_tester2) +int +signum(adl_tester2) { return 0; } diff --git a/src/test/consensus/ByzantineFailureSim_test.cpp b/src/test/consensus/ByzantineFailureSim_test.cpp index ce59adbe9f0..92dbfc0174d 100644 --- a/src/test/consensus/ByzantineFailureSim_test.cpp +++ b/src/test/consensus/ByzantineFailureSim_test.cpp @@ -66,8 +66,8 @@ class ByzantineFailureSim_test : public beast::unit_test::suite for (TrustGraph::ForkInfo const& fi : sim.trustGraph.forkablePairs(0.8)) { - std::cout << "Can fork " << PeerGroup{fi.unlA} << " " - << " " << PeerGroup{fi.unlB} << " overlap " << fi.overlap + std::cout << "Can fork " << PeerGroup{fi.unlA} << " " << " " + << PeerGroup{fi.unlB} << " overlap " << fi.overlap << " required " << fi.required << "\n"; }; diff --git a/src/test/csf/Peer.h b/src/test/csf/Peer.h index 5eed78569f6..2f3b460e02f 100644 --- a/src/test/csf/Peer.h +++ b/src/test/csf/Peer.h @@ -644,7 +644,8 @@ struct Peer } // Not interested in tracking consensus mode changes for now - void onModeChange(ConsensusMode, ConsensusMode) + void + onModeChange(ConsensusMode, ConsensusMode) { } diff --git a/src/test/csf/collectors.h b/src/test/csf/collectors.h index 511fb2c4b0f..8dcaa035314 100644 --- a/src/test/csf/collectors.h +++ b/src/test/csf/collectors.h @@ -281,66 +281,62 @@ struct TxCollector if (printBreakline) { - log << std::setw(11) << std::setfill('-') << "-" - << "-" << std::setw(7) << std::setfill('-') << "-" - << "-" << std::setw(7) << std::setfill('-') << "-" - << "-" << std::setw(36) << std::setfill('-') << "-" - << std::endl; + log << std::setw(11) << std::setfill('-') << "-" << "-" + << std::setw(7) << std::setfill('-') << "-" << "-" + << std::setw(7) << std::setfill('-') << "-" << "-" + << std::setw(36) << std::setfill('-') << "-" << std::endl; log << std::setfill(' '); } - log << std::left << std::setw(11) << "TxStats" - << "|" << std::setw(7) << "Count" - << "|" << std::setw(7) << "Per Sec" - << "|" << std::setw(15) << "Latency (sec)" << std::right - << std::setw(7) << "10-ile" << std::setw(7) << "50-ile" - << std::setw(7) << "90-ile" << std::left << std::endl; + log << std::left << std::setw(11) << "TxStats" << "|" << std::setw(7) + << "Count" << "|" << std::setw(7) << "Per Sec" << "|" + << std::setw(15) << "Latency (sec)" << std::right << std::setw(7) + << "10-ile" << std::setw(7) << "50-ile" << std::setw(7) << "90-ile" + << std::left << std::endl; - log << std::setw(11) << std::setfill('-') << "-" - << "|" << std::setw(7) << std::setfill('-') << "-" - << "|" << std::setw(7) << std::setfill('-') << "-" - << "|" << std::setw(36) << std::setfill('-') << "-" << std::endl; + log << std::setw(11) << std::setfill('-') << "-" << "|" << std::setw(7) + << std::setfill('-') << "-" << "|" << std::setw(7) + << std::setfill('-') << "-" << "|" << std::setw(36) + << std::setfill('-') << "-" << std::endl; log << std::setfill(' '); - log << std::left << std::setw(11) << "Submit " - << "|" << std::right << std::setw(7) << submitted << "|" - << std::setw(7) << std::setprecision(2) << perSec(submitted) << "|" - << std::setw(36) << "" << std::endl; + log << std::left << std::setw(11) << "Submit " << "|" << std::right + << std::setw(7) << submitted << "|" << std::setw(7) + << std::setprecision(2) << perSec(submitted) << "|" << std::setw(36) + << "" << std::endl; - log << std::left << std::setw(11) << "Accept " - << "|" << std::right << std::setw(7) << accepted << "|" - << std::setw(7) << std::setprecision(2) << perSec(accepted) << "|" - << std::setw(15) << std::left << "From Submit" << std::right - << std::setw(7) << std::setprecision(2) - << fmtS(submitToAccept.percentile(0.1f)) << std::setw(7) - << std::setprecision(2) << fmtS(submitToAccept.percentile(0.5f)) + log << std::left << std::setw(11) << "Accept " << "|" << std::right + << std::setw(7) << accepted << "|" << std::setw(7) + << std::setprecision(2) << perSec(accepted) << "|" << std::setw(15) + << std::left << "From Submit" << std::right << std::setw(7) + << std::setprecision(2) << fmtS(submitToAccept.percentile(0.1f)) << std::setw(7) << std::setprecision(2) - << fmtS(submitToAccept.percentile(0.9f)) << std::endl; + << fmtS(submitToAccept.percentile(0.5f)) << std::setw(7) + << std::setprecision(2) << fmtS(submitToAccept.percentile(0.9f)) + << std::endl; - log << std::left << std::setw(11) << "Validate " - << "|" << std::right << std::setw(7) << validated << "|" - << std::setw(7) << std::setprecision(2) << perSec(validated) << "|" - << std::setw(15) << std::left << "From Submit" << std::right - << std::setw(7) << std::setprecision(2) - << fmtS(submitToValidate.percentile(0.1f)) << std::setw(7) - << std::setprecision(2) << fmtS(submitToValidate.percentile(0.5f)) + log << std::left << std::setw(11) << "Validate " << "|" << std::right + << std::setw(7) << validated << "|" << std::setw(7) + << std::setprecision(2) << perSec(validated) << "|" << std::setw(15) + << std::left << "From Submit" << std::right << std::setw(7) + << std::setprecision(2) << fmtS(submitToValidate.percentile(0.1f)) << std::setw(7) << std::setprecision(2) - << fmtS(submitToValidate.percentile(0.9f)) << std::endl; - - log << std::left << std::setw(11) << "Orphan" - << "|" << std::right << std::setw(7) << orphaned() << "|" - << std::setw(7) << "" - << "|" << std::setw(36) << std::endl; - - log << std::left << std::setw(11) << "Unvalidated" - << "|" << std::right << std::setw(7) << unvalidated() << "|" - << std::setw(7) << "" - << "|" << std::setw(43) << std::endl; - - log << std::setw(11) << std::setfill('-') << "-" - << "-" << std::setw(7) << std::setfill('-') << "-" - << "-" << std::setw(7) << std::setfill('-') << "-" - << "-" << std::setw(36) << std::setfill('-') << "-" << std::endl; + << fmtS(submitToValidate.percentile(0.5f)) << std::setw(7) + << std::setprecision(2) << fmtS(submitToValidate.percentile(0.9f)) + << std::endl; + + log << std::left << std::setw(11) << "Orphan" << "|" << std::right + << std::setw(7) << orphaned() << "|" << std::setw(7) << "" << "|" + << std::setw(36) << std::endl; + + log << std::left << std::setw(11) << "Unvalidated" << "|" << std::right + << std::setw(7) << unvalidated() << "|" << std::setw(7) << "" << "|" + << std::setw(43) << std::endl; + + log << std::setw(11) << std::setfill('-') << "-" << "-" << std::setw(7) + << std::setfill('-') << "-" << "-" << std::setw(7) + << std::setfill('-') << "-" << "-" << std::setw(36) + << std::setfill('-') << "-" << std::endl; log << std::setfill(' '); } @@ -362,34 +358,15 @@ struct TxCollector if (printHeaders) { - log << "tag" - << "," - << "txNumSubmitted" - << "," - << "txNumAccepted" - << "," - << "txNumValidated" - << "," - << "txNumOrphaned" - << "," - << "txUnvalidated" - << "," - << "txRateSumbitted" - << "," - << "txRateAccepted" - << "," - << "txRateValidated" - << "," - << "txLatencySubmitToAccept10Pctl" - << "," - << "txLatencySubmitToAccept50Pctl" - << "," - << "txLatencySubmitToAccept90Pctl" - << "," - << "txLatencySubmitToValidatet10Pctl" - << "," - << "txLatencySubmitToValidatet50Pctl" - << "," + log << "tag" << "," << "txNumSubmitted" << "," << "txNumAccepted" + << "," << "txNumValidated" << "," << "txNumOrphaned" << "," + << "txUnvalidated" << "," << "txRateSumbitted" << "," + << "txRateAccepted" << "," << "txRateValidated" << "," + << "txLatencySubmitToAccept10Pctl" << "," + << "txLatencySubmitToAccept50Pctl" << "," + << "txLatencySubmitToAccept90Pctl" << "," + << "txLatencySubmitToValidatet10Pctl" << "," + << "txLatencySubmitToValidatet50Pctl" << "," << "txLatencySubmitToValidatet90Pctl" << std::endl; } @@ -548,52 +525,50 @@ struct LedgerCollector if (printBreakline) { - log << std::setw(11) << std::setfill('-') << "-" - << "-" << std::setw(7) << std::setfill('-') << "-" - << "-" << std::setw(7) << std::setfill('-') << "-" - << "-" << std::setw(36) << std::setfill('-') << "-" - << std::endl; + log << std::setw(11) << std::setfill('-') << "-" << "-" + << std::setw(7) << std::setfill('-') << "-" << "-" + << std::setw(7) << std::setfill('-') << "-" << "-" + << std::setw(36) << std::setfill('-') << "-" << std::endl; log << std::setfill(' '); } - log << std::left << std::setw(11) << "LedgerStats" - << "|" << std::setw(7) << "Count" - << "|" << std::setw(7) << "Per Sec" + log << std::left << std::setw(11) << "LedgerStats" << "|" + << std::setw(7) << "Count" << "|" << std::setw(7) << "Per Sec" << "|" << std::setw(15) << "Latency (sec)" << std::right << std::setw(7) << "10-ile" << std::setw(7) << "50-ile" << std::setw(7) << "90-ile" << std::left << std::endl; - log << std::setw(11) << std::setfill('-') << "-" - << "|" << std::setw(7) << std::setfill('-') << "-" - << "|" << std::setw(7) << std::setfill('-') << "-" - << "|" << std::setw(36) << std::setfill('-') << "-" << std::endl; + log << std::setw(11) << std::setfill('-') << "-" << "|" << std::setw(7) + << std::setfill('-') << "-" << "|" << std::setw(7) + << std::setfill('-') << "-" << "|" << std::setw(36) + << std::setfill('-') << "-" << std::endl; log << std::setfill(' '); - log << std::left << std::setw(11) << "Accept " - << "|" << std::right << std::setw(7) << accepted << "|" - << std::setw(7) << std::setprecision(2) << perSec(accepted) << "|" - << std::setw(15) << std::left << "From Accept" << std::right - << std::setw(7) << std::setprecision(2) - << fmtS(acceptToAccept.percentile(0.1f)) << std::setw(7) - << std::setprecision(2) << fmtS(acceptToAccept.percentile(0.5f)) + log << std::left << std::setw(11) << "Accept " << "|" << std::right + << std::setw(7) << accepted << "|" << std::setw(7) + << std::setprecision(2) << perSec(accepted) << "|" << std::setw(15) + << std::left << "From Accept" << std::right << std::setw(7) + << std::setprecision(2) << fmtS(acceptToAccept.percentile(0.1f)) << std::setw(7) << std::setprecision(2) - << fmtS(acceptToAccept.percentile(0.9f)) << std::endl; + << fmtS(acceptToAccept.percentile(0.5f)) << std::setw(7) + << std::setprecision(2) << fmtS(acceptToAccept.percentile(0.9f)) + << std::endl; - log << std::left << std::setw(11) << "Validate " - << "|" << std::right << std::setw(7) << fullyValidated << "|" - << std::setw(7) << std::setprecision(2) << perSec(fullyValidated) - << "|" << std::setw(15) << std::left << "From Validate " - << std::right << std::setw(7) << std::setprecision(2) + log << std::left << std::setw(11) << "Validate " << "|" << std::right + << std::setw(7) << fullyValidated << "|" << std::setw(7) + << std::setprecision(2) << perSec(fullyValidated) << "|" + << std::setw(15) << std::left << "From Validate " << std::right + << std::setw(7) << std::setprecision(2) << fmtS(fullyValidToFullyValid.percentile(0.1f)) << std::setw(7) << std::setprecision(2) << fmtS(fullyValidToFullyValid.percentile(0.5f)) << std::setw(7) << std::setprecision(2) << fmtS(fullyValidToFullyValid.percentile(0.9f)) << std::endl; - log << std::setw(11) << std::setfill('-') << "-" - << "-" << std::setw(7) << std::setfill('-') << "-" - << "-" << std::setw(7) << std::setfill('-') << "-" - << "-" << std::setw(36) << std::setfill('-') << "-" << std::endl; + log << std::setw(11) << std::setfill('-') << "-" << "-" << std::setw(7) + << std::setfill('-') << "-" << "-" << std::setw(7) + << std::setfill('-') << "-" << "-" << std::setw(36) + << std::setfill('-') << "-" << std::endl; log << std::setfill(' '); } @@ -615,26 +590,14 @@ struct LedgerCollector if (printHeaders) { - log << "tag" - << "," - << "ledgerNumAccepted" - << "," - << "ledgerNumFullyValidated" - << "," - << "ledgerRateAccepted" - << "," - << "ledgerRateFullyValidated" - << "," - << "ledgerLatencyAcceptToAccept10Pctl" - << "," - << "ledgerLatencyAcceptToAccept50Pctl" - << "," - << "ledgerLatencyAcceptToAccept90Pctl" - << "," - << "ledgerLatencyFullyValidToFullyValid10Pctl" - << "," - << "ledgerLatencyFullyValidToFullyValid50Pctl" - << "," + log << "tag" << "," << "ledgerNumAccepted" << "," + << "ledgerNumFullyValidated" << "," << "ledgerRateAccepted" + << "," << "ledgerRateFullyValidated" << "," + << "ledgerLatencyAcceptToAccept10Pctl" << "," + << "ledgerLatencyAcceptToAccept50Pctl" << "," + << "ledgerLatencyAcceptToAccept90Pctl" << "," + << "ledgerLatencyFullyValidToFullyValid10Pctl" << "," + << "ledgerLatencyFullyValidToFullyValid50Pctl" << "," << "ledgerLatencyFullyValidToFullyValid90Pctl" << std::endl; } @@ -695,16 +658,16 @@ struct StreamCollector on(PeerID who, SimTime when, AcceptLedger const& e) { out << when.time_since_epoch().count() << ": Node " << who - << " accepted " - << "L" << e.ledger.id() << " " << e.ledger.txs() << "\n"; + << " accepted " << "L" << e.ledger.id() << " " << e.ledger.txs() + << "\n"; } void on(PeerID who, SimTime when, FullyValidateLedger const& e) { out << when.time_since_epoch().count() << ": Node " << who - << " fully-validated " - << "L" << e.ledger.id() << " " << e.ledger.txs() << "\n"; + << " fully-validated " << "L" << e.ledger.id() << " " + << e.ledger.txs() << "\n"; } }; diff --git a/src/test/jtx/TestHelpers.h b/src/test/jtx/TestHelpers.h index 800662aa05b..7165bc26970 100644 --- a/src/test/jtx/TestHelpers.h +++ b/src/test/jtx/TestHelpers.h @@ -39,11 +39,11 @@ namespace jtx { // when we have moved to better compilers. template auto -make_vector(Input const& input) requires requires(Input& v) -{ - std::begin(v); - std::end(v); -} +make_vector(Input const& input) + requires requires(Input& v) { + std::begin(v); + std::end(v); + } { return std::vector(std::begin(input), std::end(input)); } diff --git a/src/test/jtx/TrustedPublisherServer.h b/src/test/jtx/TrustedPublisherServer.h index a10b9999ad2..b786cae2846 100644 --- a/src/test/jtx/TrustedPublisherServer.h +++ b/src/test/jtx/TrustedPublisherServer.h @@ -217,9 +217,8 @@ class TrustedPublisherServer getList_ = [blob = blob, sig, manifest, version](int interval) { // Build the contents of a version 1 format UNL file std::stringstream l; - l << "{\"blob\":\"" << blob << "\"" - << ",\"signature\":\"" << sig << "\"" - << ",\"manifest\":\"" << manifest << "\"" + l << "{\"blob\":\"" << blob << "\"" << ",\"signature\":\"" << sig + << "\"" << ",\"manifest\":\"" << manifest << "\"" << ",\"refresh_interval\": " << interval << ",\"version\":" << version << '}'; return l.str(); @@ -254,15 +253,14 @@ class TrustedPublisherServer std::stringstream l; for (auto const& info : blobInfo) { - l << "{\"blob\":\"" << info.blob << "\"" - << ",\"signature\":\"" << info.signature << "\"},"; + l << "{\"blob\":\"" << info.blob << "\"" << ",\"signature\":\"" + << info.signature << "\"},"; } std::string blobs = l.str(); blobs.pop_back(); l.str(std::string()); l << "{\"blobs_v2\": [ " << blobs << "],\"manifest\":\"" << manifest - << "\"" - << ",\"refresh_interval\": " << interval + << "\"" << ",\"refresh_interval\": " << interval << ",\"version\":" << (version + 1) << '}'; return l.str(); }; diff --git a/src/test/jtx/amount.h b/src/test/jtx/amount.h index c8e0d0c3701..459ec5b5c65 100644 --- a/src/test/jtx/amount.h +++ b/src/test/jtx/amount.h @@ -126,7 +126,7 @@ struct PrettyAmount return amount_; } - operator STAmount const &() const + operator STAmount const&() const { return amount_; } @@ -211,7 +211,8 @@ struct XRP_t /** @} */ /** Returns None-of-XRP */ - None operator()(none_t) const + None + operator()(none_t) const { return {xrpIssue()}; } @@ -327,14 +328,17 @@ class IOU return {amountFromString(issue(), std::to_string(v)), account.name()}; } - PrettyAmount operator()(epsilon_t) const; - PrettyAmount operator()(detail::epsilon_multiple) const; + PrettyAmount + operator()(epsilon_t) const; + PrettyAmount + operator()(detail::epsilon_multiple) const; // VFALCO TODO // STAmount operator()(char const* s) const; /** Returns None-of-Issue */ - None operator()(none_t) const + None + operator()(none_t) const { return {issue()}; } diff --git a/src/test/jtx/impl/AMM.cpp b/src/test/jtx/impl/AMM.cpp index c083b6df35c..8c369e68527 100644 --- a/src/test/jtx/impl/AMM.cpp +++ b/src/test/jtx/impl/AMM.cpp @@ -42,8 +42,8 @@ static IOUAmount initialTokens(STAmount const& asset1, STAmount const& asset2) { auto const product = number(asset1) * number(asset2); - return (IOUAmount)( - product.mantissa() >= 0 ? root2(product) : root2(-product)); + return (IOUAmount)(product.mantissa() >= 0 ? root2(product) + : root2(-product)); } AMM::AMM( diff --git a/src/test/jtx/impl/amount.cpp b/src/test/jtx/impl/amount.cpp index 01fa5369592..9f374c2cb58 100644 --- a/src/test/jtx/impl/amount.cpp +++ b/src/test/jtx/impl/amount.cpp @@ -104,7 +104,8 @@ operator<<(std::ostream& os, PrettyAmount const& amount) XRP_t const XRP{}; -PrettyAmount IOU::operator()(epsilon_t) const +PrettyAmount +IOU::operator()(epsilon_t) const { return {STAmount(issue(), 1, -81), account.name()}; } diff --git a/src/test/jtx/multisign.h b/src/test/jtx/multisign.h index 3946ea14b26..44cee17b7bf 100644 --- a/src/test/jtx/multisign.h +++ b/src/test/jtx/multisign.h @@ -100,9 +100,8 @@ class msig msig(std::vector signers_); template - requires std::convertible_to explicit msig( - AccountType&& a0, - Accounts&&... aN) + requires std::convertible_to + explicit msig(AccountType&& a0, Accounts&&... aN) : msig{std::vector{ std::forward(a0), std::forward(aN)...}} diff --git a/src/test/overlay/reduce_relay_test.cpp b/src/test/overlay/reduce_relay_test.cpp index 4d9086dab10..e0b0d006a2f 100644 --- a/src/test/overlay/reduce_relay_test.cpp +++ b/src/test/overlay/reduce_relay_test.cpp @@ -888,9 +888,8 @@ class reduce_relay_test : public beast::unit_test::suite printPeers(const std::string& msg, std::uint16_t validator = 0) { auto peers = network_.overlay().getPeers(network_.validator(validator)); - std::cout << msg << " " - << "num peers " << (int)network_.overlay().getNumPeers() - << std::endl; + std::cout << msg << " " << "num peers " + << (int)network_.overlay().getNumPeers() << std::endl; for (auto& [k, v] : peers) std::cout << k << ":" << (int)std::get(v) << " "; diff --git a/src/test/protocol/MultiApiJson_test.cpp b/src/test/protocol/MultiApiJson_test.cpp index 2c0b410f899..a5c37d257c4 100644 --- a/src/test/protocol/MultiApiJson_test.cpp +++ b/src/test/protocol/MultiApiJson_test.cpp @@ -105,8 +105,8 @@ struct MultiApiJson_test : beast::unit_test::suite BEAST_EXPECT(!s1.valid(0)); BEAST_EXPECT(!s1.valid(RPC::apiMaximumValidVersion + 1)); BEAST_EXPECT( - !s1.valid(std::numeric_limits::max())); + !s1.valid(std::numeric_limits< + decltype(RPC::apiMaximumValidVersion.value)>::max())); int result = 1; static_assert( @@ -165,32 +165,28 @@ struct MultiApiJson_test : beast::unit_test::suite // Several overloads we want to fail static_assert([](auto&& v) { - return !requires - { + return !requires { forAllApiVersions( std::forward(v).visit(), // [](Json::Value&, auto) {}); // missing const }; }(std::as_const(s1))); static_assert([](auto&& v) { - return !requires - { + return !requires { forAllApiVersions( std::forward(v).visit(), // [](Json::Value&) {}); // missing const }; }(std::as_const(s1))); static_assert([](auto&& v) { - return !requires - { + return !requires { forAllApiVersions( std::forward(v).visit(), // []() {}); // missing parameters }; }(std::as_const(s1))); static_assert([](auto&& v) { - return !requires - { + return !requires { forAllApiVersions( std::forward(v).visit(), // [](auto) {}, @@ -198,8 +194,7 @@ struct MultiApiJson_test : beast::unit_test::suite }; }(std::as_const(s1))); static_assert([](auto&& v) { - return !requires - { + return !requires { forAllApiVersions( std::forward(v).visit(), // [](auto, auto) {}, @@ -207,8 +202,7 @@ struct MultiApiJson_test : beast::unit_test::suite }; }(std::as_const(s1))); static_assert([](auto&& v) { - return !requires - { + return !requires { forAllApiVersions( std::forward(v).visit(), // [](auto, auto, const char*) {}, @@ -218,40 +212,35 @@ struct MultiApiJson_test : beast::unit_test::suite // Sanity checks static_assert([](auto&& v) { - return requires - { + return requires { forAllApiVersions( std::forward(v).visit(), // [](auto) {}); }; }(s1)); static_assert([](auto&& v) { - return requires - { + return requires { forAllApiVersions( std::forward(v).visit(), // [](Json::Value const&) {}); }; }(std::as_const(s1))); static_assert([](auto&& v) { - return requires - { + return requires { forAllApiVersions( std::forward(v).visit(), // [](auto...) {}); }; }(s1)); static_assert([](auto&& v) { - return requires - { + return requires { forAllApiVersions( std::forward(v).visit(), // [](Json::Value const&, auto...) {}); }; }(std::as_const(s1))); static_assert([](auto&& v) { - return requires - { + return requires { forAllApiVersions( std::forward(v).visit(), // [](Json::Value&, auto, auto, auto...) {}, @@ -260,8 +249,7 @@ struct MultiApiJson_test : beast::unit_test::suite }; }(s1)); static_assert([](auto&& v) { - return requires - { + return requires { forAllApiVersions( std::forward(v).visit(), // []( @@ -274,16 +262,14 @@ struct MultiApiJson_test : beast::unit_test::suite }; }(std::as_const(s1))); static_assert([](auto&& v) { - return requires - { + return requires { forAllApiVersions( std::forward(v).visit(), // [](auto...) {}); }; }(std::move(s1))); static_assert([](auto&& v) { - return requires - { + return requires { forAllApiVersions( std::forward(v).visit(), // [](auto...) {}); @@ -342,45 +328,25 @@ struct MultiApiJson_test : beast::unit_test::suite // Tests of requires clause - these are expected to match static_assert([](auto&& v) { - return requires - { - v.set("name", Json::nullValue); - }; + return requires { v.set("name", Json::nullValue); }; }(x)); static_assert([](auto&& v) { - return requires - { - v.set("name", "value"); - }; - }(x)); - static_assert([](auto&& v) { - return requires - { - v.set("name", true); - }; - }(x)); - static_assert([](auto&& v) { - return requires - { - v.set("name", 42); - }; + return requires { v.set("name", "value"); }; }(x)); + static_assert( + [](auto&& v) { return requires { v.set("name", true); }; }(x)); + static_assert( + [](auto&& v) { return requires { v.set("name", 42); }; }(x)); // Tests of requires clause - these are expected NOT to match struct foo_t final { }; static_assert([](auto&& v) { - return !requires - { - v.set("name", foo_t{}); - }; + return !requires { v.set("name", foo_t{}); }; }(x)); static_assert([](auto&& v) { - return !requires - { - v.set("name", std::nullopt); - }; + return !requires { v.set("name", std::nullopt); }; }(x)); } @@ -436,8 +402,7 @@ struct MultiApiJson_test : beast::unit_test::suite // Test different overloads static_assert([](auto&& v) { - return requires - { + return requires { v.visitor( v, std::integral_constant{}, @@ -458,8 +423,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](auto, auto) { return 0; }}) == 2); static_assert([](auto&& v) { - return requires - { + return requires { v.visitor( v, std::integral_constant{}, @@ -476,8 +440,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](auto...) { return 0; }}) == 2); static_assert([](auto&& v) { - return requires - { + return requires { v.visitor( v, std::integral_constant{}, @@ -498,8 +461,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](auto, auto) { return 0; }}) == 3); static_assert([](auto&& v) { - return requires - { + return requires { v.visitor( v, std::integral_constant{}, @@ -516,8 +478,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](auto...) { return 0; }}) == 3); static_assert([](auto&& v) { - return requires - { + return requires { v.visitor(v, 1, [](Json::Value&, unsigned) {}); }; }(s1)); @@ -533,10 +494,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](auto, auto) { return 0; }}) == 5); static_assert([](auto&& v) { - return requires - { - v.visitor(v, 1, [](Json::Value&) {}); - }; + return requires { v.visitor(v, 1, [](Json::Value&) {}); }; }(s1)); BEAST_EXPECT( s1.visitor( @@ -548,8 +506,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](auto...) { return 0; }}) == 5); static_assert([](auto&& v) { - return requires - { + return requires { v.visitor(v, 1, [](Json::Value const&, unsigned) {}); }; }(std::as_const(s1))); @@ -565,10 +522,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](auto, auto) { return 0; }}) == 3); static_assert([](auto&& v) { - return requires - { - v.visitor(v, 1, [](Json::Value const&) {}); - }; + return requires { v.visitor(v, 1, [](Json::Value const&) {}); }; }(std::as_const(s1))); BEAST_EXPECT( s1.visitor( @@ -671,8 +625,7 @@ struct MultiApiJson_test : beast::unit_test::suite // Several overloads we want to fail static_assert([](auto&& v) { - return !requires - { + return !requires { v.visitor( v, 1, // @@ -681,8 +634,7 @@ struct MultiApiJson_test : beast::unit_test::suite }(std::as_const(s1))); static_assert([](auto&& v) { - return !requires - { + return !requires { v.visitor( std::move(v), // cannot bind rvalue 1, @@ -691,8 +643,7 @@ struct MultiApiJson_test : beast::unit_test::suite }(s1)); static_assert([](auto&& v) { - return !requires - { + return !requires { v.visitor( v, 1, // @@ -701,8 +652,7 @@ struct MultiApiJson_test : beast::unit_test::suite }(s1)); static_assert([](auto&& v) { - return !requires - { + return !requires { v.visitor( v, 1, // @@ -712,74 +662,52 @@ struct MultiApiJson_test : beast::unit_test::suite // Want these to be unambiguous static_assert([](auto&& v) { - return requires - { - v.visitor(v, 1, [](auto) {}); - }; + return requires { v.visitor(v, 1, [](auto) {}); }; }(s1)); static_assert([](auto&& v) { - return requires - { - v.visitor(v, 1, [](Json::Value&) {}); - }; + return requires { v.visitor(v, 1, [](Json::Value&) {}); }; }(s1)); static_assert([](auto&& v) { - return requires - { + return requires { v.visitor(v, 1, [](Json::Value&, auto...) {}); }; }(s1)); static_assert([](auto&& v) { - return requires - { - v.visitor(v, 1, [](Json::Value const&) {}); - }; + return requires { v.visitor(v, 1, [](Json::Value const&) {}); }; }(s1)); static_assert([](auto&& v) { - return requires - { + return requires { v.visitor(v, 1, [](Json::Value const&, auto...) {}); }; }(s1)); static_assert([](auto&& v) { - return requires - { - v.visitor(v, 1, [](auto...) {}); - }; + return requires { v.visitor(v, 1, [](auto...) {}); }; }(s1)); static_assert([](auto&& v) { - return requires - { - v.visitor(v, 1, [](auto, auto...) {}); - }; + return requires { v.visitor(v, 1, [](auto, auto...) {}); }; }(s1)); static_assert([](auto&& v) { - return requires - { + return requires { v.visitor(v, 1, [](auto, auto, auto...) {}); }; }(s1)); static_assert([](auto&& v) { - return requires - { - v.visitor( - v, 1, [](auto, auto, auto...) {}, ""); + return requires { + v.visitor(v, 1, [](auto, auto, auto...) {}, ""); }; }(s1)); static_assert([](auto&& v) { - return requires - { - v.visitor( - v, 1, [](auto, auto, auto, auto...) {}, ""); + return requires { + v.visitor(v, 1, [](auto, auto, auto, auto...) {}, ""); }; }(s1)); } @@ -794,8 +722,7 @@ struct MultiApiJson_test : beast::unit_test::suite // Test different overloads static_assert([](auto&& v) { - return requires - { + return requires { v.visit( std::integral_constant{}, [](Json::Value&, std::integral_constant) { @@ -813,8 +740,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](Json::Value const&, auto) { return 0; }, [](auto, auto) { return 0; }}) == 2); static_assert([](auto&& v) { - return requires - { + return requires { v.visit()( std::integral_constant{}, [](Json::Value&, std::integral_constant) { @@ -833,8 +759,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](auto, auto) { return 0; }}) == 2); static_assert([](auto&& v) { - return requires - { + return requires { v.visit( std::integral_constant{}, [](Json::Value&) {}); @@ -848,8 +773,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](Json::Value const&) { return 0; }, [](auto...) { return 0; }}) == 2); static_assert([](auto&& v) { - return requires - { + return requires { v.visit()( std::integral_constant{}, [](Json::Value&) {}); @@ -864,8 +788,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](auto...) { return 0; }}) == 2); static_assert([](auto&& v) { - return requires - { + return requires { v.visit( std::integral_constant{}, [](Json::Value const&, @@ -883,8 +806,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](Json::Value&, auto) { return 0; }, [](auto, auto) { return 0; }}) == 3); static_assert([](auto&& v) { - return requires - { + return requires { v.visit()( std::integral_constant{}, [](Json::Value const&, @@ -903,8 +825,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](auto, auto) { return 0; }}) == 3); static_assert([](auto&& v) { - return requires - { + return requires { v.visit( std::integral_constant{}, [](Json::Value const&) {}); @@ -918,8 +839,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](Json::Value&) { return 0; }, [](auto...) { return 0; }}) == 3); static_assert([](auto&& v) { - return requires - { + return requires { v.visit()( std::integral_constant{}, [](Json::Value const&) {}); @@ -934,10 +854,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](auto...) { return 0; }}) == 3); static_assert([](auto&& v) { - return requires - { - v.visit(1, [](Json::Value&, unsigned) {}); - }; + return requires { v.visit(1, [](Json::Value&, unsigned) {}); }; }(s1)); BEAST_EXPECT( s1.visit( @@ -950,8 +867,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](Json::Value&, auto) { return 0; }, [](auto, auto) { return 0; }}) == 5); static_assert([](auto&& v) { - return requires - { + return requires { v.visit()(1, [](Json::Value&, unsigned) {}); }; }(s1)); @@ -967,10 +883,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](auto, auto) { return 0; }}) == 5); static_assert([](auto&& v) { - return requires - { - v.visit(1, [](Json::Value&) {}); - }; + return requires { v.visit(1, [](Json::Value&) {}); }; }(s1)); BEAST_EXPECT( s1.visit( @@ -980,10 +893,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](Json::Value const&) { return 0; }, [](auto...) { return 0; }}) == 5); static_assert([](auto&& v) { - return requires - { - v.visit()(1, [](Json::Value&) {}); - }; + return requires { v.visit()(1, [](Json::Value&) {}); }; }(s1)); BEAST_EXPECT( s1.visit()( @@ -994,8 +904,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](auto...) { return 0; }}) == 5); static_assert([](auto&& v) { - return requires - { + return requires { v.visit(1, [](Json::Value const&, unsigned) {}); }; }(std::as_const(s1))); @@ -1010,8 +919,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](Json::Value&, unsigned) { return 0; }, [](auto, auto) { return 0; }}) == 3); static_assert([](auto&& v) { - return requires - { + return requires { v.visit()(1, [](Json::Value const&, unsigned) {}); }; }(std::as_const(s1))); @@ -1027,10 +935,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](auto, auto) { return 0; }}) == 3); static_assert([](auto&& v) { - return requires - { - v.visit(1, [](Json::Value const&) {}); - }; + return requires { v.visit(1, [](Json::Value const&) {}); }; }(std::as_const(s1))); BEAST_EXPECT( std::as_const(s1).visit( @@ -1040,10 +945,7 @@ struct MultiApiJson_test : beast::unit_test::suite [](Json::Value&) { return 0; }, [](auto...) { return 0; }}) == 3); static_assert([](auto&& v) { - return requires - { - v.visit()(1, [](Json::Value const&) {}); - }; + return requires { v.visit()(1, [](Json::Value const&) {}); }; }(std::as_const(s1))); BEAST_EXPECT( std::as_const(s1).visit()( @@ -1055,83 +957,71 @@ struct MultiApiJson_test : beast::unit_test::suite // Rvalue MultivarJson visitor only binds to regular reference static_assert([](auto&& v) { - return !requires - { + return !requires { std::forward(v).visit(1, [](Json::Value&&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { - return !requires - { + return !requires { std::forward(v).visit( 1, [](Json::Value const&&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { - return requires - { + return requires { std::forward(v).visit(1, [](Json::Value&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { - return requires - { + return requires { std::forward(v).visit( 1, [](Json::Value const&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { - return !requires - { + return !requires { std::forward(v).visit()( 1, [](Json::Value&&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { - return !requires - { + return !requires { std::forward(v).visit()( 1, [](Json::Value const&&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { - return requires - { + return requires { std::forward(v).visit()( 1, [](Json::Value&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { - return requires - { + return requires { std::forward(v).visit()( 1, [](Json::Value const&) {}); }; }(std::move(s1))); static_assert([](auto&& v) { - return !requires - { + return !requires { std::forward(v).visit( 1, [](Json::Value const&&) {}); }; }(std::move(std::as_const(s1)))); static_assert([](auto&& v) { - return requires - { + return requires { std::forward(v).visit( 1, [](Json::Value const&) {}); }; }(std::move(std::as_const(s1)))); static_assert([](auto&& v) { - return !requires - { + return !requires { std::forward(v).visit()( 1, [](Json::Value const&&) {}); }; }(std::move(std::as_const(s1)))); static_assert([](auto&& v) { - return requires - { + return requires { std::forward(v).visit()( 1, [](Json::Value const&) {}); }; @@ -1139,15 +1029,13 @@ struct MultiApiJson_test : beast::unit_test::suite // Missing const static_assert([](auto&& v) { - return !requires - { + return !requires { std::forward(v).visit( 1, [](Json::Value&, auto) {}); }; }(std::as_const(s1))); static_assert([](auto&& v) { - return !requires - { + return !requires { std::forward(v).visit()( 1, [](Json::Value&, auto) {}); }; @@ -1155,28 +1043,24 @@ struct MultiApiJson_test : beast::unit_test::suite // Missing parameter static_assert([](auto&& v) { - return !requires - { + return !requires { std::forward(v).visit(1, []() {}); }; }(s1)); static_assert([](auto&& v) { - return !requires - { + return !requires { std::forward(v).visit()(1, []() {}); }; }(s1)); // Sanity checks static_assert([](auto&& v) { - return requires - { + return requires { std::forward(v).visit(1, [](auto...) {}); }; }(std::as_const(s1))); static_assert([](auto&& v) { - return requires - { + return requires { std::forward(v).visit()(1, [](auto...) {}); }; }(std::as_const(s1))); diff --git a/src/test/protocol/STObject_test.cpp b/src/test/protocol/STObject_test.cpp index 39a5b9c2f65..41c3800bce4 100644 --- a/src/test/protocol/STObject_test.cpp +++ b/src/test/protocol/STObject_test.cpp @@ -243,9 +243,8 @@ class STObject_test : public beast::unit_test::suite unexpected(sfGeneric.isUseful(), "sfGeneric must not be useful"); { // Try to put sfGeneric in an SOTemplate. - except([&]() { - SOTemplate elements{{sfGeneric, soeREQUIRED}}; - }); + except( + [&]() { SOTemplate elements{{sfGeneric, soeREQUIRED}}; }); } unexpected(sfInvalid.isUseful(), "sfInvalid must not be useful"); @@ -263,9 +262,8 @@ class STObject_test : public beast::unit_test::suite } { // Try to put sfInvalid in an SOTemplate. - except([&]() { - SOTemplate elements{{sfInvalid, soeREQUIRED}}; - }); + except( + [&]() { SOTemplate elements{{sfInvalid, soeREQUIRED}}; }); } { // Try to put the same SField into an SOTemplate twice. @@ -570,150 +568,152 @@ class STObject_test : public beast::unit_test::suite // STBlob and slice - {{STObject st(sfGeneric); - Buffer b(1); - BEAST_EXPECT(!b.empty()); - st[sf4] = std::move(b); - BEAST_EXPECT(b.empty()); - BEAST_EXPECT(Slice(st[sf4]).size() == 1); - st[~sf4] = std::nullopt; - BEAST_EXPECT(!~st[~sf4]); - b = Buffer{2}; - st[sf4] = Slice(b); - BEAST_EXPECT(b.size() == 2); - BEAST_EXPECT(Slice(st[sf4]).size() == 2); - st[sf5] = st[sf4]; - BEAST_EXPECT(Slice(st[sf4]).size() == 2); - BEAST_EXPECT(Slice(st[sf5]).size() == 2); - } - { - STObject st(sotOuter, sfGeneric); - BEAST_EXPECT(st[sf5] == Slice{}); - BEAST_EXPECT(!!st[~sf5]); - BEAST_EXPECT(!!~st[~sf5]); - Buffer b(1); - st[sf5] = std::move(b); - BEAST_EXPECT(b.empty()); - BEAST_EXPECT(Slice(st[sf5]).size() == 1); - st[~sf4] = std::nullopt; - BEAST_EXPECT(!~st[~sf4]); - } -} + { + { + STObject st(sfGeneric); + Buffer b(1); + BEAST_EXPECT(!b.empty()); + st[sf4] = std::move(b); + BEAST_EXPECT(b.empty()); + BEAST_EXPECT(Slice(st[sf4]).size() == 1); + st[~sf4] = std::nullopt; + BEAST_EXPECT(!~st[~sf4]); + b = Buffer{2}; + st[sf4] = Slice(b); + BEAST_EXPECT(b.size() == 2); + BEAST_EXPECT(Slice(st[sf4]).size() == 2); + st[sf5] = st[sf4]; + BEAST_EXPECT(Slice(st[sf4]).size() == 2); + BEAST_EXPECT(Slice(st[sf5]).size() == 2); + } + { + STObject st(sotOuter, sfGeneric); + BEAST_EXPECT(st[sf5] == Slice{}); + BEAST_EXPECT(!!st[~sf5]); + BEAST_EXPECT(!!~st[~sf5]); + Buffer b(1); + st[sf5] = std::move(b); + BEAST_EXPECT(b.empty()); + BEAST_EXPECT(Slice(st[sf5]).size() == 1); + st[~sf4] = std::nullopt; + BEAST_EXPECT(!~st[~sf4]); + } + } -// UDT blobs + // UDT blobs -{ - STObject st(sfGeneric); - BEAST_EXPECT(!st[~sf5]); - auto const kp = - generateKeyPair(KeyType::secp256k1, generateSeed("masterpassphrase")); - st[sf5] = kp.first; - st[~sf5] = std::nullopt; -} + { + STObject st(sfGeneric); + BEAST_EXPECT(!st[~sf5]); + auto const kp = generateKeyPair( + KeyType::secp256k1, generateSeed("masterpassphrase")); + st[sf5] = kp.first; + st[~sf5] = std::nullopt; + } -// By reference fields + // By reference fields -{ - auto const& sf = sfIndexes; - STObject st(sfGeneric); - std::vector v; - v.emplace_back(1); - v.emplace_back(2); - st[sf] = v; - st[sf] = std::move(v); - auto const& cst = st; - BEAST_EXPECT(cst[sf].size() == 2); - BEAST_EXPECT(cst[~sf]->size() == 2); - BEAST_EXPECT(cst[sf][0] == 1); - BEAST_EXPECT(cst[sf][1] == 2); - static_assert( - std::is_same const&>:: - value, - ""); -} - -// Default by reference field + { + auto const& sf = sfIndexes; + STObject st(sfGeneric); + std::vector v; + v.emplace_back(1); + v.emplace_back(2); + st[sf] = v; + st[sf] = std::move(v); + auto const& cst = st; + BEAST_EXPECT(cst[sf].size() == 2); + BEAST_EXPECT(cst[~sf]->size() == 2); + BEAST_EXPECT(cst[sf][0] == 1); + BEAST_EXPECT(cst[sf][1] == 2); + static_assert( + std::is_same< + decltype(cst[sfIndexes]), + std::vector const&>::value, + ""); + } -{ - auto const& sf1 = sfIndexes; - auto const& sf2 = sfHashes; - auto const& sf3 = sfAmendments; - SOTemplate const sot{ - {sf1, soeREQUIRED}, - {sf2, soeOPTIONAL}, - {sf3, soeDEFAULT}, - }; - - STObject st(sot, sfGeneric); - auto const& cst(st); - BEAST_EXPECT(cst[sf1].size() == 0); - BEAST_EXPECT(!cst[~sf2]); - BEAST_EXPECT(cst[sf3].size() == 0); - std::vector v; - v.emplace_back(1); - st[sf1] = v; - BEAST_EXPECT(cst[sf1].size() == 1); - BEAST_EXPECT(cst[sf1][0] == uint256{1}); - st[sf2] = v; - BEAST_EXPECT(cst[sf2].size() == 1); - BEAST_EXPECT(cst[sf2][0] == uint256{1}); - st[~sf2] = std::nullopt; - BEAST_EXPECT(!st[~sf2]); - st[sf3] = v; - BEAST_EXPECT(cst[sf3].size() == 1); - BEAST_EXPECT(cst[sf3][0] == uint256{1}); - st[sf3] = std::vector{}; - BEAST_EXPECT(cst[sf3].size() == 0); -} -} // namespace ripple + // Default by reference field -void -testMalformed() -{ - testcase("Malformed serialized forms"); + { + auto const& sf1 = sfIndexes; + auto const& sf2 = sfHashes; + auto const& sf3 = sfAmendments; + SOTemplate const sot{ + {sf1, soeREQUIRED}, + {sf2, soeOPTIONAL}, + {sf3, soeDEFAULT}, + }; - try - { - std::array const payload{ - {0xe9, 0x12, 0xab, 0xcd, 0x12, 0xfe, 0xdc}}; - SerialIter sit{makeSlice(payload)}; - auto obj = std::make_shared(sit, sfMetadata); - BEAST_EXPECT(!obj); - } - catch (std::exception const& e) - { - BEAST_EXPECT(strcmp(e.what(), "Duplicate field detected") == 0); - } + STObject st(sot, sfGeneric); + auto const& cst(st); + BEAST_EXPECT(cst[sf1].size() == 0); + BEAST_EXPECT(!cst[~sf2]); + BEAST_EXPECT(cst[sf3].size() == 0); + std::vector v; + v.emplace_back(1); + st[sf1] = v; + BEAST_EXPECT(cst[sf1].size() == 1); + BEAST_EXPECT(cst[sf1][0] == uint256{1}); + st[sf2] = v; + BEAST_EXPECT(cst[sf2].size() == 1); + BEAST_EXPECT(cst[sf2][0] == uint256{1}); + st[~sf2] = std::nullopt; + BEAST_EXPECT(!st[~sf2]); + st[sf3] = v; + BEAST_EXPECT(cst[sf3].size() == 1); + BEAST_EXPECT(cst[sf3][0] == uint256{1}); + st[sf3] = std::vector{}; + BEAST_EXPECT(cst[sf3].size() == 0); + } + } // namespace ripple - try + void + testMalformed() { - std::array const payload{{0xe2, 0xe1, 0xe2}}; - SerialIter sit{makeSlice(payload)}; - auto obj = std::make_shared(sit, sfMetadata); - BEAST_EXPECT(!obj); + testcase("Malformed serialized forms"); + + try + { + std::array const payload{ + {0xe9, 0x12, 0xab, 0xcd, 0x12, 0xfe, 0xdc}}; + SerialIter sit{makeSlice(payload)}; + auto obj = std::make_shared(sit, sfMetadata); + BEAST_EXPECT(!obj); + } + catch (std::exception const& e) + { + BEAST_EXPECT(strcmp(e.what(), "Duplicate field detected") == 0); + } + + try + { + std::array const payload{{0xe2, 0xe1, 0xe2}}; + SerialIter sit{makeSlice(payload)}; + auto obj = std::make_shared(sit, sfMetadata); + BEAST_EXPECT(!obj); + } + catch (std::exception const& e) + { + BEAST_EXPECT(strcmp(e.what(), "Duplicate field detected") == 0); + } } - catch (std::exception const& e) + + void + run() override { - BEAST_EXPECT(strcmp(e.what(), "Duplicate field detected") == 0); + // Instantiate a jtx::Env so debugLog writes are exercised. + test::jtx::Env env(*this); + + testFields(); + testSerialization(); + testParseJSONArray(); + testParseJSONArrayWithInvalidChildrenObjects(); + testParseJSONEdgeCases(); + testMalformed(); } -} - -void -run() override -{ - // Instantiate a jtx::Env so debugLog writes are exercised. - test::jtx::Env env(*this); - - testFields(); - testSerialization(); - testParseJSONArray(); - testParseJSONArrayWithInvalidChildrenObjects(); - testParseJSONEdgeCases(); - testMalformed(); -} -} -; +}; BEAST_DEFINE_TESTSUITE(STObject, protocol, ripple); -} // ripple +} // namespace ripple diff --git a/src/xrpld/app/ledger/LedgerHistory.cpp b/src/xrpld/app/ledger/LedgerHistory.cpp index 30139e2155f..b63cd84772a 100644 --- a/src/xrpld/app/ledger/LedgerHistory.cpp +++ b/src/xrpld/app/ledger/LedgerHistory.cpp @@ -204,30 +204,30 @@ log_metadata_difference( { JLOG(j.debug()) << "MISMATCH on TX " << tx << ": Different result and index!"; - JLOG(j.debug()) << " Built:" - << " Result: " << builtMetaData->getResult() - << " Index: " << builtMetaData->getIndex(); - JLOG(j.debug()) << " Valid:" - << " Result: " << validMetaData->getResult() - << " Index: " << validMetaData->getIndex(); + JLOG(j.debug()) + << " Built:" << " Result: " << builtMetaData->getResult() + << " Index: " << builtMetaData->getIndex(); + JLOG(j.debug()) + << " Valid:" << " Result: " << validMetaData->getResult() + << " Index: " << validMetaData->getIndex(); } else if (result_diff) { JLOG(j.debug()) << "MISMATCH on TX " << tx << ": Different result!"; - JLOG(j.debug()) << " Built:" - << " Result: " << builtMetaData->getResult(); - JLOG(j.debug()) << " Valid:" - << " Result: " << validMetaData->getResult(); + JLOG(j.debug()) + << " Built:" << " Result: " << builtMetaData->getResult(); + JLOG(j.debug()) + << " Valid:" << " Result: " << validMetaData->getResult(); } else if (index_diff) { JLOG(j.debug()) << "MISMATCH on TX " << tx << ": Different index!"; - JLOG(j.debug()) << " Built:" - << " Index: " << builtMetaData->getIndex(); - JLOG(j.debug()) << " Valid:" - << " Index: " << validMetaData->getIndex(); + JLOG(j.debug()) + << " Built:" << " Index: " << builtMetaData->getIndex(); + JLOG(j.debug()) + << " Valid:" << " Index: " << validMetaData->getIndex(); } } else @@ -246,12 +246,12 @@ log_metadata_difference( JLOG(j.debug()) << "MISMATCH on TX " << tx << ": Different result and nodes!"; JLOG(j.debug()) - << " Built:" - << " Result: " << builtMetaData->getResult() << " Nodes:\n" + << " Built:" << " Result: " << builtMetaData->getResult() + << " Nodes:\n" << builtNodes.getJson(JsonOptions::none); JLOG(j.debug()) - << " Valid:" - << " Result: " << validMetaData->getResult() << " Nodes:\n" + << " Valid:" << " Result: " << validMetaData->getResult() + << " Nodes:\n" << validNodes.getJson(JsonOptions::none); } else if (index_diff) @@ -259,23 +259,21 @@ log_metadata_difference( JLOG(j.debug()) << "MISMATCH on TX " << tx << ": Different index and nodes!"; JLOG(j.debug()) - << " Built:" - << " Index: " << builtMetaData->getIndex() << " Nodes:\n" + << " Built:" << " Index: " << builtMetaData->getIndex() + << " Nodes:\n" << builtNodes.getJson(JsonOptions::none); JLOG(j.debug()) - << " Valid:" - << " Index: " << validMetaData->getIndex() << " Nodes:\n" + << " Valid:" << " Index: " << validMetaData->getIndex() + << " Nodes:\n" << validNodes.getJson(JsonOptions::none); } else // nodes_diff { JLOG(j.debug()) << "MISMATCH on TX " << tx << ": Different nodes!"; - JLOG(j.debug()) << " Built:" - << " Nodes:\n" + JLOG(j.debug()) << " Built:" << " Nodes:\n" << builtNodes.getJson(JsonOptions::none); - JLOG(j.debug()) << " Valid:" - << " Nodes:\n" + JLOG(j.debug()) << " Valid:" << " Nodes:\n" << validNodes.getJson(JsonOptions::none); } } @@ -330,10 +328,10 @@ LedgerHistory::handleMismatch( if (!builtLedger || !validLedger) { - JLOG(j_.error()) << "MISMATCH cannot be analyzed:" - << " builtLedger: " << to_string(built) << " -> " - << builtLedger << " validLedger: " << to_string(valid) - << " -> " << validLedger; + JLOG(j_.error()) << "MISMATCH cannot be analyzed:" << " builtLedger: " + << to_string(built) << " -> " << builtLedger + << " validLedger: " << to_string(valid) << " -> " + << validLedger; return; } diff --git a/src/xrpld/app/ledger/detail/TimeoutCounter.cpp b/src/xrpld/app/ledger/detail/TimeoutCounter.cpp index 9d677dbe5a1..f70e54f8cd4 100644 --- a/src/xrpld/app/ledger/detail/TimeoutCounter.cpp +++ b/src/xrpld/app/ledger/detail/TimeoutCounter.cpp @@ -100,8 +100,8 @@ TimeoutCounter::invokeOnTimer() if (!progress_) { ++timeouts_; - JLOG(journal_.debug()) << "Timeout(" << timeouts_ << ") " - << " acquiring " << hash_; + JLOG(journal_.debug()) + << "Timeout(" << timeouts_ << ") " << " acquiring " << hash_; onTimer(false, sl); } else diff --git a/src/xrpld/app/main/GRPCServer.cpp b/src/xrpld/app/main/GRPCServer.cpp index 89c3d813caa..5a231dfc9e6 100644 --- a/src/xrpld/app/main/GRPCServer.cpp +++ b/src/xrpld/app/main/GRPCServer.cpp @@ -447,8 +447,8 @@ GRPCServerImpl::handleRpcs() if (!ok) { - JLOG(journal_.debug()) << "Request listener cancelled. " - << "Destroying object"; + JLOG(journal_.debug()) + << "Request listener cancelled. " << "Destroying object"; erase(ptr); } else diff --git a/src/xrpld/app/misc/AMMHelpers.h b/src/xrpld/app/misc/AMMHelpers.h index 8bf5a5c5f12..7ad0093a2e4 100644 --- a/src/xrpld/app/misc/AMMHelpers.h +++ b/src/xrpld/app/misc/AMMHelpers.h @@ -385,9 +385,9 @@ changeSpotPriceQuality( { JLOG(j.error()) << "changeSpotPriceQuality failed: " << to_string(pool.in) - << " " << to_string(pool.out) << " " - << " " << quality << " " << tfee << " " - << to_string(amounts.in) << " " << to_string(amounts.out); + << " " << to_string(pool.out) << " " << " " << quality + << " " << tfee << " " << to_string(amounts.in) << " " + << to_string(amounts.out); Throw("changeSpotPriceQuality failed"); } else diff --git a/src/xrpld/app/misc/NetworkOPs.cpp b/src/xrpld/app/misc/NetworkOPs.cpp index 02eb0435b57..a95afd56933 100644 --- a/src/xrpld/app/misc/NetworkOPs.cpp +++ b/src/xrpld/app/misc/NetworkOPs.cpp @@ -3177,8 +3177,8 @@ NetworkOPsImp::pubAccountTransaction( } JLOG(m_journal.trace()) - << "pubAccountTransaction: " - << "proposed=" << iProposed << ", accepted=" << iAccepted; + << "pubAccountTransaction: " << "proposed=" << iProposed + << ", accepted=" << iAccepted; if (!notify.empty() || !accountHistoryNotify.empty()) { diff --git a/src/xrpld/app/misc/detail/TxQ.cpp b/src/xrpld/app/misc/detail/TxQ.cpp index 159a700cc3f..a4e62b382a7 100644 --- a/src/xrpld/app/misc/detail/TxQ.cpp +++ b/src/xrpld/app/misc/detail/TxQ.cpp @@ -1485,11 +1485,11 @@ TxQ::accept(Application& app, OpenView& view) } else { - JLOG(j_.debug()) << "Queued transaction " << candidateIter->txID - << " failed with " << transToken(txnResult) - << ". Leave in queue." - << " Applied: " << didApply - << ". Flags: " << candidateIter->flags; + JLOG(j_.debug()) + << "Queued transaction " << candidateIter->txID + << " failed with " << transToken(txnResult) + << ". Leave in queue." << " Applied: " << didApply + << ". Flags: " << candidateIter->flags; if (account.retryPenalty && candidateIter->retriesRemaining > 2) candidateIter->retriesRemaining = 1; else diff --git a/src/xrpld/app/misc/detail/ValidatorList.cpp b/src/xrpld/app/misc/detail/ValidatorList.cpp index a3854106a1c..9a323e0116b 100644 --- a/src/xrpld/app/misc/detail/ValidatorList.cpp +++ b/src/xrpld/app/misc/detail/ValidatorList.cpp @@ -689,8 +689,7 @@ ValidatorList::sendValidatorList( beast::Journal j) { std::size_t const messageVersion = - peer.supportsFeature(ProtocolFeature::ValidatorList2Propagation) - ? 2 + peer.supportsFeature(ProtocolFeature::ValidatorList2Propagation) ? 2 : peer.supportsFeature(ProtocolFeature::ValidatorListPropagation) ? 1 : 0; if (!messageVersion) diff --git a/src/xrpld/app/paths/Pathfinder.cpp b/src/xrpld/app/paths/Pathfinder.cpp index 885a8ae9b47..a2c1be4cc7c 100644 --- a/src/xrpld/app/paths/Pathfinder.cpp +++ b/src/xrpld/app/paths/Pathfinder.cpp @@ -233,8 +233,7 @@ Pathfinder::findPaths( mSource = STPathElement(account, mSrcCurrency, issuer); auto issuerString = mSrcIssuer ? to_string(*mSrcIssuer) : std::string("none"); - JLOG(j_.trace()) << "findPaths>" - << " mSrcAccount=" << mSrcAccount + JLOG(j_.trace()) << "findPaths>" << " mSrcAccount=" << mSrcAccount << " mDstAccount=" << mDstAccount << " mDstAmount=" << mDstAmount.getFullText() << " mSrcCurrency=" << mSrcCurrency diff --git a/src/xrpld/app/paths/detail/BookStep.cpp b/src/xrpld/app/paths/detail/BookStep.cpp index 96971a516fc..b22102119df 100644 --- a/src/xrpld/app/paths/detail/BookStep.cpp +++ b/src/xrpld/app/paths/detail/BookStep.cpp @@ -188,8 +188,7 @@ class BookStep : public StepImp> logStringImpl(char const* name) const { std::ostringstream ostr; - ostr << name << ": " - << "\ninIss: " << book_.in.account + ostr << name << ": " << "\ninIss: " << book_.in.account << "\noutIss: " << book_.out.account << "\ninCur: " << book_.in.currency << "\noutCur: " << book_.out.currency; diff --git a/src/xrpld/app/paths/detail/DirectStep.cpp b/src/xrpld/app/paths/detail/DirectStep.cpp index 25e78e9c47e..7df06751140 100644 --- a/src/xrpld/app/paths/detail/DirectStep.cpp +++ b/src/xrpld/app/paths/detail/DirectStep.cpp @@ -204,8 +204,7 @@ class DirectStepI : public StepImp> logStringImpl(char const* name) const { std::ostringstream ostr; - ostr << name << ": " - << "\nSrc: " << src_ << "\nDst: " << dst_; + ostr << name << ": " << "\nSrc: " << src_ << "\nDst: " << dst_; return ostr.str(); } @@ -236,7 +235,8 @@ class DirectIPaymentStep : public DirectStepI using DirectStepI::DirectStepI; using DirectStepI::check; - bool verifyPrevStepDebtDirection(DebtDirection) const + bool + verifyPrevStepDebtDirection(DebtDirection) const { // A payment doesn't care whether or not prevStepRedeems. return true; diff --git a/src/xrpld/app/paths/detail/XRPEndpointStep.cpp b/src/xrpld/app/paths/detail/XRPEndpointStep.cpp index ac88152c9dd..ac178cbe2f2 100644 --- a/src/xrpld/app/paths/detail/XRPEndpointStep.cpp +++ b/src/xrpld/app/paths/detail/XRPEndpointStep.cpp @@ -132,8 +132,7 @@ class XRPEndpointStep logStringImpl(char const* name) const { std::ostringstream ostr; - ostr << name << ": " - << "\nAcc: " << acc_; + ostr << name << ": " << "\nAcc: " << acc_; return ostr.str(); } diff --git a/src/xrpld/app/rdb/RelationalDatabase.h b/src/xrpld/app/rdb/RelationalDatabase.h index 00e236f20db..5b06aa24d0e 100644 --- a/src/xrpld/app/rdb/RelationalDatabase.h +++ b/src/xrpld/app/rdb/RelationalDatabase.h @@ -237,8 +237,8 @@ rangeCheckedCast(C c) /* This should never happen */ assert(0); JLOG(debugLog().error()) - << "rangeCheckedCast domain error:" - << " value = " << c << " min = " << std::numeric_limits::lowest() + << "rangeCheckedCast domain error:" << " value = " << c + << " min = " << std::numeric_limits::lowest() << " max: " << std::numeric_limits::max(); } diff --git a/src/xrpld/app/tx/detail/CancelOffer.cpp b/src/xrpld/app/tx/detail/CancelOffer.cpp index 11b07f06df3..30e955a8282 100644 --- a/src/xrpld/app/tx/detail/CancelOffer.cpp +++ b/src/xrpld/app/tx/detail/CancelOffer.cpp @@ -34,8 +34,8 @@ CancelOffer::preflight(PreflightContext const& ctx) if (uTxFlags & tfUniversalMask) { - JLOG(ctx.j.trace()) << "Malformed transaction: " - << "Invalid flags set."; + JLOG(ctx.j.trace()) + << "Malformed transaction: " << "Invalid flags set."; return temINVALID_FLAG; } @@ -62,8 +62,8 @@ CancelOffer::preclaim(PreclaimContext const& ctx) if ((*sle)[sfSequence] <= offerSequence) { - JLOG(ctx.j.trace()) << "Malformed transaction: " - << "Sequence " << offerSequence << " is invalid."; + JLOG(ctx.j.trace()) << "Malformed transaction: " << "Sequence " + << offerSequence << " is invalid."; return temBAD_SEQUENCE; } diff --git a/src/xrpld/app/tx/detail/Payment.cpp b/src/xrpld/app/tx/detail/Payment.cpp index 309e9d4a498..46a76bffc28 100644 --- a/src/xrpld/app/tx/detail/Payment.cpp +++ b/src/xrpld/app/tx/detail/Payment.cpp @@ -56,8 +56,7 @@ Payment::preflight(PreflightContext const& ctx) if (uTxFlags & tfPaymentMask) { - JLOG(j.trace()) << "Malformed transaction: " - << "Invalid flags set."; + JLOG(j.trace()) << "Malformed transaction: " << "Invalid flags set."; return temINVALID_FLAG; } @@ -102,20 +101,19 @@ Payment::preflight(PreflightContext const& ctx) } if (bMax && maxSourceAmount <= beast::zero) { - JLOG(j.trace()) << "Malformed transaction: " - << "bad max amount: " << maxSourceAmount.getFullText(); + JLOG(j.trace()) << "Malformed transaction: " << "bad max amount: " + << maxSourceAmount.getFullText(); return temBAD_AMOUNT; } if (saDstAmount <= beast::zero) { - JLOG(j.trace()) << "Malformed transaction: " - << "bad dst amount: " << saDstAmount.getFullText(); + JLOG(j.trace()) << "Malformed transaction: " << "bad dst amount: " + << saDstAmount.getFullText(); return temBAD_AMOUNT; } if (badCurrency() == uSrcCurrency || badCurrency() == uDstCurrency) { - JLOG(j.trace()) << "Malformed transaction: " - << "Bad currency."; + JLOG(j.trace()) << "Malformed transaction: " << "Bad currency."; return temBAD_CURRENCY; } if (account == uDstAccountID && uSrcCurrency == uDstCurrency && !bPaths) @@ -445,8 +443,8 @@ Payment::doApply() { // Vote no. However the transaction might succeed, if applied in // a different order. - JLOG(j_.trace()) << "Delay transaction: Insufficient funds: " - << " " << to_string(mPriorBalance) << " / " + JLOG(j_.trace()) << "Delay transaction: Insufficient funds: " << " " + << to_string(mPriorBalance) << " / " << to_string(saDstAmount.xrp() + mmm) << " (" << to_string(reserve) << ")"; diff --git a/src/xrpld/app/tx/detail/Transactor.cpp b/src/xrpld/app/tx/detail/Transactor.cpp index 18e11415c0a..7ea024ee6dc 100644 --- a/src/xrpld/app/tx/detail/Transactor.cpp +++ b/src/xrpld/app/tx/detail/Transactor.cpp @@ -226,9 +226,9 @@ Transactor::checkFee(PreclaimContext const& ctx, XRPAmount baseFee) if (balance < feePaid) { - JLOG(ctx.j.trace()) << "Insufficient balance:" - << " balance=" << to_string(balance) - << " paid=" << to_string(feePaid); + JLOG(ctx.j.trace()) + << "Insufficient balance:" << " balance=" << to_string(balance) + << " paid=" << to_string(feePaid); if ((balance > beast::zero) && !ctx.view.open()) { diff --git a/src/xrpld/conditions/detail/PreimageSha256.h b/src/xrpld/conditions/detail/PreimageSha256.h index c0eca96b066..5185ded7a67 100644 --- a/src/xrpld/conditions/detail/PreimageSha256.h +++ b/src/xrpld/conditions/detail/PreimageSha256.h @@ -137,7 +137,8 @@ class PreimageSha256 final : public Fulfillment return {type(), cost(), fingerprint()}; } - bool validate(Slice) const override + bool + validate(Slice) const override { // Perhaps counterintuitively, the message isn't // relevant. diff --git a/src/xrpld/consensus/Consensus.h b/src/xrpld/consensus/Consensus.h index fd3560b1744..06c12b4f150 100644 --- a/src/xrpld/consensus/Consensus.h +++ b/src/xrpld/consensus/Consensus.h @@ -1060,8 +1060,7 @@ Consensus::checkLedger() { JLOG(j_.warn()) << "View of consensus changed during " << to_string(phase_) << " status=" << to_string(phase_) - << ", " - << " mode=" << to_string(mode_.get()); + << ", " << " mode=" << to_string(mode_.get()); JLOG(j_.warn()) << prevLedgerID_ << " to " << netLgr; JLOG(j_.warn()) << Json::Compact{previousLedger_.getJson()}; JLOG(j_.debug()) << "State on consensus change " @@ -1164,8 +1163,7 @@ Consensus::shouldPause() const << "roundTime: " << result_->roundTime.read().count() << ", " << "max consensus time: " << parms.ledgerMAX_CONSENSUS.count() << ", " << "validators: " << totalValidators << ", " - << "laggards: " << laggards << ", " - << "offline: " << offline << ", " + << "laggards: " << laggards << ", " << "offline: " << offline << ", " << "quorum: " << quorum << ")"; if (!ahead || !laggards || !totalValidators || !adaptor_.validator() || @@ -1491,8 +1489,8 @@ Consensus::updateOurPositions() if (!haveCloseTimeConsensus_) { JLOG(j_.debug()) - << "No CT consensus:" - << " Proposers:" << currPeerPositions_.size() + << "No CT consensus:" << " Proposers:" + << currPeerPositions_.size() << " Mode:" << to_string(mode_.get()) << " Thresh:" << threshConsensus << " Pos:" << consensusCloseTime.time_since_epoch().count(); diff --git a/src/xrpld/consensus/Validations.h b/src/xrpld/consensus/Validations.h index ed07858d321..a1171effb56 100644 --- a/src/xrpld/consensus/Validations.h +++ b/src/xrpld/consensus/Validations.h @@ -482,8 +482,7 @@ class Validations withTrie(std::lock_guard const& lock, F&& f) { // Call current to flush any stale validations - current( - lock, [](auto) {}, [](auto, auto) {}); + current(lock, [](auto) {}, [](auto, auto) {}); checkAcquired(lock); return f(trie_); } diff --git a/src/xrpld/core/DatabaseCon.h b/src/xrpld/core/DatabaseCon.h index 935147815ca..c8c40dec662 100644 --- a/src/xrpld/core/DatabaseCon.h +++ b/src/xrpld/core/DatabaseCon.h @@ -73,7 +73,8 @@ class LockedSociSession { return session_.get(); } - explicit operator bool() const + explicit + operator bool() const { return bool(session_); } diff --git a/src/xrpld/ledger/detail/View.cpp b/src/xrpld/ledger/detail/View.cpp index 13ac07e5e74..55baeadff66 100644 --- a/src/xrpld/ledger/detail/View.cpp +++ b/src/xrpld/ledger/detail/View.cpp @@ -259,8 +259,7 @@ accountHolds( } amount.setIssuer(issuer); } - JLOG(j.trace()) << "accountHolds:" - << " account=" << to_string(account) + JLOG(j.trace()) << "accountHolds:" << " account=" << to_string(account) << " amount=" << amount.getFullText(); return view.balanceHook(account, issuer, amount); @@ -369,8 +368,7 @@ xrpLiquid( STAmount const amount = (balance < reserve) ? STAmount{0} : balance - reserve; - JLOG(j.trace()) << "accountHolds:" - << " account=" << to_string(id) + JLOG(j.trace()) << "accountHolds:" << " account=" << to_string(id) << " amount=" << amount.getFullText() << " fullBalance=" << fullBalance.getFullText() << " balance=" << balance.getFullText() diff --git a/src/xrpld/nodestore/detail/DatabaseNodeImp.h b/src/xrpld/nodestore/detail/DatabaseNodeImp.h index b8a9a3fa2b4..326db38a661 100644 --- a/src/xrpld/nodestore/detail/DatabaseNodeImp.h +++ b/src/xrpld/nodestore/detail/DatabaseNodeImp.h @@ -106,7 +106,8 @@ class DatabaseNodeImp : public Database store(NodeObjectType type, Blob&& data, uint256 const& hash, std::uint32_t) override; - bool isSameDB(std::uint32_t, std::uint32_t) override + bool + isSameDB(std::uint32_t, std::uint32_t) override { // only one database return true; diff --git a/src/xrpld/nodestore/detail/DatabaseRotatingImp.h b/src/xrpld/nodestore/detail/DatabaseRotatingImp.h index 0c17dc59ceb..5183aa1e2e4 100644 --- a/src/xrpld/nodestore/detail/DatabaseRotatingImp.h +++ b/src/xrpld/nodestore/detail/DatabaseRotatingImp.h @@ -62,7 +62,8 @@ class DatabaseRotatingImp : public DatabaseRotating void importDatabase(Database& source) override; - bool isSameDB(std::uint32_t, std::uint32_t) override + bool + isSameDB(std::uint32_t, std::uint32_t) override { // rotating store acts as one logical database return true; diff --git a/src/xrpld/overlay/detail/PeerImp.cpp b/src/xrpld/overlay/detail/PeerImp.cpp index 308a4e8b284..4f5f1470f8e 100644 --- a/src/xrpld/overlay/detail/PeerImp.cpp +++ b/src/xrpld/overlay/detail/PeerImp.cpp @@ -591,7 +591,7 @@ PeerImp::fail(std::string const& reason) return post( strand_, std::bind( - (void (Peer::*)(std::string const&)) & PeerImp::fail, + (void(Peer::*)(std::string const&)) & PeerImp::fail, shared_from_this(), reason)); if (journal_.active(beast::severities::kWarning) && socket_.is_open()) @@ -1226,8 +1226,8 @@ PeerImp::handleTransaction( { // If we've never been in synch, there's nothing we can do // with a transaction - JLOG(p_journal_.debug()) << "Ignoring incoming transaction: " - << "Need network ledger"; + JLOG(p_journal_.debug()) + << "Ignoring incoming transaction: " << "Need network ledger"; return; } diff --git a/src/xrpld/overlay/detail/ProtocolVersion.cpp b/src/xrpld/overlay/detail/ProtocolVersion.cpp index bd2effa6341..0fecb301f7f 100644 --- a/src/xrpld/overlay/detail/ProtocolVersion.cpp +++ b/src/xrpld/overlay/detail/ProtocolVersion.cpp @@ -45,7 +45,7 @@ constexpr ProtocolVersion const supportedProtocolList[] // ascending order and doesn't contain any duplicates. // FIXME: With C++20 we can use std::is_sorted with an appropriate comparator static_assert( - []() constexpr->bool { + []() constexpr -> bool { auto const len = std::distance( std::begin(supportedProtocolList), std::end(supportedProtocolList)); diff --git a/src/xrpld/peerfinder/detail/Logic.h b/src/xrpld/peerfinder/detail/Logic.h index 0403530ecf2..3bfb9942c3a 100644 --- a/src/xrpld/peerfinder/detail/Logic.h +++ b/src/xrpld/peerfinder/detail/Logic.h @@ -1109,9 +1109,9 @@ class Logic } else { - JLOG(m_journal.error()) << beast::leftw(18) << "Logic failed " - << "'" << source->name() << "' fetch, " - << results.error.message(); + JLOG(m_journal.error()) + << beast::leftw(18) << "Logic failed " << "'" << source->name() + << "' fetch, " << results.error.message(); } } diff --git a/src/xrpld/rpc/detail/ServerHandler.cpp b/src/xrpld/rpc/detail/ServerHandler.cpp index c006111894b..ccf0c12b5ad 100644 --- a/src/xrpld/rpc/detail/ServerHandler.cpp +++ b/src/xrpld/rpc/detail/ServerHandler.cpp @@ -388,9 +388,9 @@ logDuration( beast::Journal& journal) { using namespace std::chrono_literals; - auto const level = (duration >= 10s) - ? journal.error() - : (duration >= 1s) ? journal.warn() : journal.debug(); + auto const level = (duration >= 10s) ? journal.error() + : (duration >= 1s) ? journal.warn() + : journal.debug(); JLOG(level) << "RPC request processing duration = " << std::chrono::duration_cast( diff --git a/src/xrpld/shamap/detail/TaggedPointer.ipp b/src/xrpld/shamap/detail/TaggedPointer.ipp index 309913c79c0..487b88e3461 100644 --- a/src/xrpld/shamap/detail/TaggedPointer.ipp +++ b/src/xrpld/shamap/detail/TaggedPointer.ipp @@ -55,8 +55,8 @@ constexpr size_t elementSizeBytes = constexpr size_t blockSizeBytes = kilobytes(512); template -constexpr std::array initArrayChunkSizeBytes( - std::index_sequence) +constexpr std::array +initArrayChunkSizeBytes(std::index_sequence) { return std::array{ boundaries[I] * elementSizeBytes..., @@ -66,8 +66,8 @@ constexpr auto arrayChunkSizeBytes = initArrayChunkSizeBytes(std::make_index_sequence{}); template -constexpr std::array initArrayChunksPerBlock( - std::index_sequence) +constexpr std::array +initArrayChunksPerBlock(std::index_sequence) { return std::array{ blockSizeBytes / arrayChunkSizeBytes[I]..., @@ -93,8 +93,8 @@ boundariesIndex(std::uint8_t numChildren) } template -std::array, boundaries.size()> initAllocateArrayFuns( - std::index_sequence) +std::array, boundaries.size()> +initAllocateArrayFuns(std::index_sequence) { return std::array, boundaries.size()>{ boost::singleton_pool< @@ -110,8 +110,8 @@ std::array, boundaries.size()> const allocateArrayFuns = initAllocateArrayFuns(std::make_index_sequence{}); template -std::array, boundaries.size()> initFreeArrayFuns( - std::index_sequence) +std::array, boundaries.size()> +initFreeArrayFuns(std::index_sequence) { return std::array, boundaries.size()>{ static_cast(boost::singleton_pool< @@ -127,8 +127,8 @@ std::array, boundaries.size()> const freeArrayFuns = initFreeArrayFuns(std::make_index_sequence{}); template -std::array, boundaries.size()> initIsFromArrayFuns( - std::index_sequence) +std::array, boundaries.size()> +initIsFromArrayFuns(std::index_sequence) { return std::array, boundaries.size()>{ boost::singleton_pool< diff --git a/src/xrpld/unity/rocksdb.h b/src/xrpld/unity/rocksdb.h index 06ccb116da1..4a71dc4b57f 100644 --- a/src/xrpld/unity/rocksdb.h +++ b/src/xrpld/unity/rocksdb.h @@ -21,7 +21,7 @@ #define RIPPLE_UNITY_ROCKSDB_H_INCLUDED #if RIPPLE_ROCKSDB_AVAILABLE -//#include +// #include #include #include #include From f0dabd14460d11d31b9d79a44a73d264d1e003ec Mon Sep 17 00:00:00 2001 From: John Freeman Date: Tue, 15 Oct 2024 18:28:43 -0500 Subject: [PATCH 61/82] Ignore reformat when blaming --- .git-blame-ignore-revs | 1 + 1 file changed, 1 insertion(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 514f90fc5f5..a72fc4afd83 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -10,3 +10,4 @@ e2384885f5f630c8f0ffe4bf21a169b433a16858 b9d007813378ad0ff45660dc07285b823c7e9855 fe9a5365b8a52d4acc42eb27369247e6f238a4f9 9a93577314e6a8d4b4a8368cc9d2b15a5d8303e8 +552377c76f55b403a1c876df873a23d780fcc81c From 63209c2646717db4c330c92ed435e8c7e6d4a35b Mon Sep 17 00:00:00 2001 From: John Freeman Date: Wed, 16 Oct 2024 14:02:29 -0500 Subject: [PATCH 62/82] Consolidate definitions of fields, objects, transactions, and features (#5122) --- include/xrpl/protocol/Feature.h | 78 +-- include/xrpl/protocol/LedgerFormats.h | 146 +----- include/xrpl/protocol/SField.h | 342 +------------ include/xrpl/protocol/TxFormats.h | 152 +----- include/xrpl/protocol/detail/features.macro | 112 +++++ .../xrpl/protocol/detail/ledger_entries.macro | 394 +++++++++++++++ include/xrpl/protocol/detail/sfields.macro | 357 +++++++++++++ .../xrpl/protocol/detail/transactions.macro | 423 ++++++++++++++++ include/xrpl/protocol/jss.h | 60 +-- src/libxrpl/protocol/Feature.cpp | 125 +---- src/libxrpl/protocol/LedgerFormats.cpp | 349 +------------ src/libxrpl/protocol/SField.cpp | 397 +-------------- src/libxrpl/protocol/TxFormats.cpp | 475 +----------------- src/test/jtx/impl/AMM.cpp | 2 +- src/xrpld/app/tx/detail/CancelCheck.h | 2 + src/xrpld/app/tx/detail/CancelOffer.h | 2 + src/xrpld/app/tx/detail/CashCheck.h | 2 + src/xrpld/app/tx/detail/Change.h | 4 + src/xrpld/app/tx/detail/CreateCheck.h | 2 + src/xrpld/app/tx/detail/CreateOffer.h | 2 + src/xrpld/app/tx/detail/CreateTicket.h | 2 + src/xrpld/app/tx/detail/DeleteAccount.h | 2 + src/xrpld/app/tx/detail/DeleteOracle.h | 2 + src/xrpld/app/tx/detail/PayChan.h | 6 + src/xrpld/app/tx/detail/SetAccount.h | 2 + src/xrpld/app/tx/detail/SetOracle.h | 2 + src/xrpld/app/tx/detail/SetSignerList.h | 2 + src/xrpld/app/tx/detail/SetTrust.h | 2 + src/xrpld/app/tx/detail/XChainBridge.h | 5 + src/xrpld/app/tx/detail/applySteps.cpp | 104 +--- 30 files changed, 1466 insertions(+), 2089 deletions(-) create mode 100644 include/xrpl/protocol/detail/features.macro create mode 100644 include/xrpl/protocol/detail/ledger_entries.macro create mode 100644 include/xrpl/protocol/detail/sfields.macro create mode 100644 include/xrpl/protocol/detail/transactions.macro diff --git a/include/xrpl/protocol/Feature.h b/include/xrpl/protocol/Feature.h index a00d6b85c1b..5537c543d6f 100644 --- a/include/xrpl/protocol/Feature.h +++ b/include/xrpl/protocol/Feature.h @@ -308,70 +308,20 @@ foreachFeature(FeatureBitset bs, F&& f) f(bitsetIndexToFeature(i)); } -extern uint256 const featureOwnerPaysFee; -extern uint256 const featureFlow; -extern uint256 const featureFlowCross; -extern uint256 const featureCryptoConditionsSuite; -extern uint256 const fix1513; -extern uint256 const featureDepositAuth; -extern uint256 const featureChecks; -extern uint256 const fix1571; -extern uint256 const fix1543; -extern uint256 const fix1623; -extern uint256 const featureDepositPreauth; -extern uint256 const fix1515; -extern uint256 const fix1578; -extern uint256 const featureMultiSignReserve; -extern uint256 const fixTakerDryOfferRemoval; -extern uint256 const fixMasterKeyAsRegularKey; -extern uint256 const fixCheckThreading; -extern uint256 const fixPayChanRecipientOwnerDir; -extern uint256 const featureDeletableAccounts; -extern uint256 const fixQualityUpperBound; -extern uint256 const featureRequireFullyCanonicalSig; -extern uint256 const fix1781; -extern uint256 const featureHardenedValidations; -extern uint256 const fixAmendmentMajorityCalc; -extern uint256 const featureNegativeUNL; -extern uint256 const featureTicketBatch; -extern uint256 const featureFlowSortStrands; -extern uint256 const fixSTAmountCanonicalize; -extern uint256 const fixRmSmallIncreasedQOffers; -extern uint256 const featureCheckCashMakesTrustLine; -extern uint256 const featureNonFungibleTokensV1; -extern uint256 const featureExpandedSignerList; -extern uint256 const fixNFTokenDirV1; -extern uint256 const fixNFTokenNegOffer; -extern uint256 const featureNonFungibleTokensV1_1; -extern uint256 const fixTrustLinesToSelf; -extern uint256 const fixRemoveNFTokenAutoTrustLine; -extern uint256 const featureImmediateOfferKilled; -extern uint256 const featureDisallowIncoming; -extern uint256 const featureXRPFees; -extern uint256 const featureAMM; -extern uint256 const fixUniversalNumber; -extern uint256 const fixNonFungibleTokensV1_2; -extern uint256 const fixNFTokenRemint; -extern uint256 const fixReducedOffersV1; -extern uint256 const featureClawback; -extern uint256 const featureXChainBridge; -extern uint256 const fixDisallowIncomingV1; -extern uint256 const featureDID; -extern uint256 const fixFillOrKill; -extern uint256 const fixNFTokenReserve; -extern uint256 const fixInnerObjTemplate; -extern uint256 const fixAMMOverflowOffer; -extern uint256 const featurePriceOracle; -extern uint256 const fixEmptyDID; -extern uint256 const fixXChainRewardRounding; -extern uint256 const fixPreviousTxnID; -extern uint256 const fixAMMv1_1; -extern uint256 const featureNFTokenMintOffer; -extern uint256 const fixReducedOffersV2; -extern uint256 const fixEnforceNFTokenTrustline; -extern uint256 const fixInnerObjTemplate2; -extern uint256 const featureInvariantsV1_1; -extern uint256 const fixNFTokenPageLinks; +#pragma push_macro("XRPL_FEATURE") +#undef XRPL_FEATURE +#pragma push_macro("XRPL_FIX") +#undef XRPL_FIX + +#define XRPL_FEATURE(name, supported, vote) extern uint256 const feature##name; +#define XRPL_FIX(name, supported, vote) extern uint256 const fix##name; + +#include + +#undef XRPL_FIX +#pragma pop_macro("XRPL_FIX") +#undef XRPL_FEATURE +#pragma pop_macro("XRPL_FEATURE") } // namespace ripple diff --git a/include/xrpl/protocol/LedgerFormats.h b/include/xrpl/protocol/LedgerFormats.h index 0ee6c992d8d..14fcaa673ab 100644 --- a/include/xrpl/protocol/LedgerFormats.h +++ b/include/xrpl/protocol/LedgerFormats.h @@ -52,150 +52,16 @@ namespace ripple { // clang-format off enum LedgerEntryType : std::uint16_t { - /** A ledger object which describes an account. - \sa keylet::account - */ - ltACCOUNT_ROOT = 0x0061, - - /** A ledger object which contains a list of object identifiers. - - \sa keylet::page, keylet::quality, keylet::book, keylet::next and - keylet::ownerDir - */ - ltDIR_NODE = 0x0064, - - /** A ledger object which describes a bidirectional trust line. - - @note Per Vinnie Falco this should be renamed to ltTRUST_LINE - - \sa keylet::line - */ - ltRIPPLE_STATE = 0x0072, - - /** A ledger object which describes a ticket. - - \sa keylet::ticket - */ - ltTICKET = 0x0054, - - /** A ledger object which contains a signer list for an account. - - \sa keylet::signers - */ - ltSIGNER_LIST = 0x0053, - - /** A ledger object which describes an offer on the DEX. - - \sa keylet::offer - */ - ltOFFER = 0x006f, - - - /** The ledger object which lists details about sidechains. - - \sa keylet::bridge - */ - ltBRIDGE = 0x0069, - - /** A ledger object that contains a list of ledger hashes. - - This type is used to store the ledger hashes which the protocol uses - to implement skip lists that allow for efficient backwards (and, in - theory, forward) forward iteration across large ledger ranges. - - \sa keylet::skip - */ - ltLEDGER_HASHES = 0x0068, - - /** The ledger object which lists details about amendments on the network. - - \note This is a singleton: only one such object exists in the ledger. - - \sa keylet::amendments - */ - ltAMENDMENTS = 0x0066, - - /** A claim id for a cross chain transaction. - - \sa keylet::xChainClaimID - */ - ltXCHAIN_OWNED_CLAIM_ID = 0x0071, - - /** A claim id for a cross chain create account transaction. +#pragma push_macro("LEDGER_ENTRY") +#undef LEDGER_ENTRY - \sa keylet::xChainCreateAccountClaimID - */ - ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID = 0x0074, - - /** The ledger object which lists the network's fee settings. - - \note This is a singleton: only one such object exists in the ledger. - - \sa keylet::fees - */ - ltFEE_SETTINGS = 0x0073, - - /** A ledger object describing a single escrow. - - \sa keylet::escrow - */ - ltESCROW = 0x0075, - - /** A ledger object describing a single unidirectional XRP payment channel. - - \sa keylet::payChan - */ - ltPAYCHAN = 0x0078, - - /** A ledger object which describes a check. - - \sa keylet::check - */ - ltCHECK = 0x0043, - - /** A ledger object which describes a deposit preauthorization. - - \sa keylet::depositPreauth - */ - ltDEPOSIT_PREAUTH = 0x0070, +#define LEDGER_ENTRY(tag, value, name, fields) tag = value, - /** The ledger object which tracks the current negative UNL state. +#include - \note This is a singleton: only one such object exists in the ledger. - - \sa keylet::negativeUNL - */ - ltNEGATIVE_UNL = 0x004e, - - /** A ledger object which contains a list of NFTs - - \sa keylet::nftpage_min, keylet::nftpage_max, keylet::nftpage - */ - ltNFTOKEN_PAGE = 0x0050, - - /** A ledger object which identifies an offer to buy or sell an NFT. - - \sa keylet::nftoffer - */ - ltNFTOKEN_OFFER = 0x0037, - - /** The ledger object which tracks the AMM. - - \sa keylet::amm - */ - ltAMM = 0x0079, - - /** The ledger object which tracks the DID. - - \sa keylet::did - */ - ltDID = 0x0049, - - /** A ledger object which tracks Oracle - \sa keylet::oracle - */ - ltORACLE = 0x0080, +#undef LEDGER_ENTRY +#pragma pop_macro("LEDGER_ENTRY") //--------------------------------------------------------------------------- /** A special type, matching any ledger entry type. diff --git a/include/xrpl/protocol/SField.h b/include/xrpl/protocol/SField.h index 7f54201a4b8..c370239ca19 100644 --- a/include/xrpl/protocol/SField.h +++ b/include/xrpl/protocol/SField.h @@ -218,6 +218,11 @@ class SField return jsonName; } + operator Json::StaticString const&() const + { + return jsonName; + } + bool isInvalid() const { @@ -355,329 +360,26 @@ using SF_XCHAIN_BRIDGE = TypedField; //------------------------------------------------------------------------------ +// Use macros for most SField construction to enforce naming conventions. +#pragma push_macro("UNTYPED_SFIELD") +#undef UNTYPED_SFIELD +#pragma push_macro("TYPED_SFIELD") +#undef TYPED_SFIELD + +#define UNTYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) \ + extern SField const sfName; +#define TYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) \ + extern SF_##stiSuffix const sfName; + extern SField const sfInvalid; extern SField const sfGeneric; -extern SField const sfLedgerEntry; -extern SField const sfTransaction; -extern SField const sfValidation; -extern SField const sfMetadata; - -// 8-bit integers (common) -extern SF_UINT8 const sfCloseResolution; -extern SF_UINT8 const sfMethod; -extern SF_UINT8 const sfTransactionResult; -extern SF_UINT8 const sfWasLockingChainSend; -extern SF_UINT8 const sfScale; - -// 8-bit integers (uncommon) -extern SF_UINT8 const sfTickSize; -extern SF_UINT8 const sfUNLModifyDisabling; -extern SF_UINT8 const sfHookResult; - -// 16-bit integers (common) -extern SF_UINT16 const sfLedgerEntryType; -extern SF_UINT16 const sfTransactionType; -extern SF_UINT16 const sfSignerWeight; -extern SF_UINT16 const sfTransferFee; -extern SF_UINT16 const sfTradingFee; - -// 16-bit integers (uncommon) -extern SF_UINT16 const sfVersion; -extern SF_UINT16 const sfHookStateChangeCount; -extern SF_UINT16 const sfHookEmitCount; -extern SF_UINT16 const sfHookExecutionIndex; -extern SF_UINT16 const sfHookApiVersion; -extern SF_UINT16 const sfDiscountedFee; -extern SF_UINT16 const sfLedgerFixType; - -// 32-bit integers (common) -extern SF_UINT32 const sfNetworkID; -extern SF_UINT32 const sfFlags; -extern SF_UINT32 const sfSourceTag; -extern SF_UINT32 const sfSequence; -extern SF_UINT32 const sfPreviousTxnLgrSeq; -extern SF_UINT32 const sfLedgerSequence; -extern SF_UINT32 const sfCloseTime; -extern SF_UINT32 const sfParentCloseTime; -extern SF_UINT32 const sfSigningTime; -extern SF_UINT32 const sfExpiration; -extern SF_UINT32 const sfTransferRate; -extern SF_UINT32 const sfWalletSize; -extern SF_UINT32 const sfOwnerCount; -extern SF_UINT32 const sfDestinationTag; -extern SF_UINT32 const sfLastUpdateTime; - -// 32-bit integers (uncommon) -extern SF_UINT32 const sfHighQualityIn; -extern SF_UINT32 const sfHighQualityOut; -extern SF_UINT32 const sfLowQualityIn; -extern SF_UINT32 const sfLowQualityOut; -extern SF_UINT32 const sfQualityIn; -extern SF_UINT32 const sfQualityOut; -extern SF_UINT32 const sfStampEscrow; -extern SF_UINT32 const sfBondAmount; -extern SF_UINT32 const sfLoadFee; -extern SF_UINT32 const sfOfferSequence; -extern SF_UINT32 const sfFirstLedgerSequence; -extern SF_UINT32 const sfLastLedgerSequence; -extern SF_UINT32 const sfTransactionIndex; -extern SF_UINT32 const sfOperationLimit; -extern SF_UINT32 const sfReferenceFeeUnits; -extern SF_UINT32 const sfReserveBase; -extern SF_UINT32 const sfReserveIncrement; -extern SF_UINT32 const sfSetFlag; -extern SF_UINT32 const sfClearFlag; -extern SF_UINT32 const sfSignerQuorum; -extern SF_UINT32 const sfCancelAfter; -extern SF_UINT32 const sfFinishAfter; -extern SF_UINT32 const sfSignerListID; -extern SF_UINT32 const sfSettleDelay; -extern SF_UINT32 const sfTicketCount; -extern SF_UINT32 const sfTicketSequence; -extern SF_UINT32 const sfNFTokenTaxon; -extern SF_UINT32 const sfMintedNFTokens; -extern SF_UINT32 const sfBurnedNFTokens; -extern SF_UINT32 const sfHookStateCount; -extern SF_UINT32 const sfEmitGeneration; -extern SF_UINT32 const sfVoteWeight; -extern SF_UINT32 const sfFirstNFTokenSequence; -extern SF_UINT32 const sfOracleDocumentID; - -// 64-bit integers (common) -extern SF_UINT64 const sfIndexNext; -extern SF_UINT64 const sfIndexPrevious; -extern SF_UINT64 const sfBookNode; -extern SF_UINT64 const sfOwnerNode; -extern SF_UINT64 const sfBaseFee; -extern SF_UINT64 const sfExchangeRate; -extern SF_UINT64 const sfLowNode; -extern SF_UINT64 const sfHighNode; -extern SF_UINT64 const sfDestinationNode; -extern SF_UINT64 const sfCookie; -extern SF_UINT64 const sfServerVersion; -extern SF_UINT64 const sfNFTokenOfferNode; -extern SF_UINT64 const sfEmitBurden; - -// 64-bit integers (uncommon) -extern SF_UINT64 const sfHookOn; -extern SF_UINT64 const sfHookInstructionCount; -extern SF_UINT64 const sfHookReturnCode; -extern SF_UINT64 const sfReferenceCount; -extern SF_UINT64 const sfXChainClaimID; -extern SF_UINT64 const sfXChainAccountCreateCount; -extern SF_UINT64 const sfXChainAccountClaimCount; -extern SF_UINT64 const sfAssetPrice; - -// 128-bit -extern SF_UINT128 const sfEmailHash; - -// 160-bit (common) -extern SF_UINT160 const sfTakerPaysCurrency; -extern SF_UINT160 const sfTakerPaysIssuer; -extern SF_UINT160 const sfTakerGetsCurrency; -extern SF_UINT160 const sfTakerGetsIssuer; - -// 256-bit (common) -extern SF_UINT256 const sfLedgerHash; -extern SF_UINT256 const sfParentHash; -extern SF_UINT256 const sfTransactionHash; -extern SF_UINT256 const sfAccountHash; -extern SF_UINT256 const sfPreviousTxnID; -extern SF_UINT256 const sfLedgerIndex; -extern SF_UINT256 const sfWalletLocator; -extern SF_UINT256 const sfRootIndex; -extern SF_UINT256 const sfAccountTxnID; -extern SF_UINT256 const sfNFTokenID; -extern SF_UINT256 const sfEmitParentTxnID; -extern SF_UINT256 const sfEmitNonce; -extern SF_UINT256 const sfEmitHookHash; -extern SF_UINT256 const sfAMMID; - -// 256-bit (uncommon) -extern SF_UINT256 const sfBookDirectory; -extern SF_UINT256 const sfInvoiceID; -extern SF_UINT256 const sfNickname; -extern SF_UINT256 const sfAmendment; -extern SF_UINT256 const sfDigest; -extern SF_UINT256 const sfChannel; -extern SF_UINT256 const sfConsensusHash; -extern SF_UINT256 const sfCheckID; -extern SF_UINT256 const sfValidatedHash; -extern SF_UINT256 const sfPreviousPageMin; -extern SF_UINT256 const sfNextPageMin; -extern SF_UINT256 const sfNFTokenBuyOffer; -extern SF_UINT256 const sfNFTokenSellOffer; -extern SF_UINT256 const sfHookStateKey; -extern SF_UINT256 const sfHookHash; -extern SF_UINT256 const sfHookNamespace; -extern SF_UINT256 const sfHookSetTxnID; - -// currency amount (common) -extern SF_AMOUNT const sfAmount; -extern SF_AMOUNT const sfBalance; -extern SF_AMOUNT const sfLimitAmount; -extern SF_AMOUNT const sfTakerPays; -extern SF_AMOUNT const sfTakerGets; -extern SF_AMOUNT const sfLowLimit; -extern SF_AMOUNT const sfHighLimit; -extern SF_AMOUNT const sfFee; -extern SF_AMOUNT const sfSendMax; -extern SF_AMOUNT const sfDeliverMin; -extern SF_AMOUNT const sfAmount2; -extern SF_AMOUNT const sfEPrice; -extern SF_AMOUNT const sfBidMin; -extern SF_AMOUNT const sfBidMax; -extern SF_AMOUNT const sfPrice; -extern SF_AMOUNT const sfLPTokenBalance; - -// currency amount (uncommon) -extern SF_AMOUNT const sfMinimumOffer; -extern SF_AMOUNT const sfRippleEscrow; -extern SF_AMOUNT const sfDeliveredAmount; -extern SF_AMOUNT const sfNFTokenBrokerFee; -extern SF_AMOUNT const sfLPTokenOut; -extern SF_AMOUNT const sfLPTokenIn; - -// currency amount (fees) -extern SF_AMOUNT const sfBaseFeeDrops; -extern SF_AMOUNT const sfReserveBaseDrops; -extern SF_AMOUNT const sfReserveIncrementDrops; -extern SF_AMOUNT const sfSignatureReward; -extern SF_AMOUNT const sfMinAccountCreateAmount; - -// variable length (common) -extern SF_VL const sfPublicKey; -extern SF_VL const sfMessageKey; -extern SF_VL const sfSigningPubKey; -extern SF_VL const sfTxnSignature; -extern SF_VL const sfURI; -extern SF_VL const sfSignature; -extern SF_VL const sfDomain; -extern SF_VL const sfFundCode; -extern SF_VL const sfRemoveCode; -extern SF_VL const sfExpireCode; -extern SF_VL const sfCreateCode; -extern SF_VL const sfMemoType; -extern SF_VL const sfMemoData; -extern SF_VL const sfMemoFormat; -extern SF_VL const sfDIDDocument; -extern SF_VL const sfData; -extern SF_VL const sfAssetClass; -extern SF_VL const sfProvider; - -// variable length (uncommon) -extern SF_VL const sfFulfillment; -extern SF_VL const sfCondition; -extern SF_VL const sfMasterSignature; -extern SF_VL const sfUNLModifyValidator; -extern SF_VL const sfValidatorToDisable; -extern SF_VL const sfValidatorToReEnable; -extern SF_VL const sfHookStateData; -extern SF_VL const sfHookReturnString; -extern SF_VL const sfHookParameterName; -extern SF_VL const sfHookParameterValue; - -// account -extern SF_ACCOUNT const sfAccount; -extern SF_ACCOUNT const sfOwner; -extern SF_ACCOUNT const sfDestination; -extern SF_ACCOUNT const sfIssuer; -extern SF_ACCOUNT const sfAuthorize; -extern SF_ACCOUNT const sfUnauthorize; -extern SF_ACCOUNT const sfRegularKey; -extern SF_ACCOUNT const sfNFTokenMinter; -extern SF_ACCOUNT const sfEmitCallback; - -// account (uncommon) -extern SF_ACCOUNT const sfHookAccount; -extern SF_ACCOUNT const sfOtherChainSource; -extern SF_ACCOUNT const sfOtherChainDestination; -extern SF_ACCOUNT const sfAttestationSignerAccount; -extern SF_ACCOUNT const sfAttestationRewardAccount; -extern SF_ACCOUNT const sfLockingChainDoor; -extern SF_ACCOUNT const sfIssuingChainDoor; - -// path set -extern SField const sfPaths; - -// currency -extern SF_CURRENCY const sfBaseAsset; -extern SF_CURRENCY const sfQuoteAsset; - -// issue -extern SF_ISSUE const sfAsset; -extern SF_ISSUE const sfAsset2; -extern SF_ISSUE const sfLockingChainIssue; -extern SF_ISSUE const sfIssuingChainIssue; - -// bridge -extern SF_XCHAIN_BRIDGE const sfXChainBridge; - -// vector of 256-bit -extern SF_VECTOR256 const sfIndexes; -extern SF_VECTOR256 const sfHashes; -extern SF_VECTOR256 const sfAmendments; -extern SF_VECTOR256 const sfNFTokenOffers; - -// inner object -// OBJECT/1 is reserved for end of object -extern SField const sfTransactionMetaData; -extern SField const sfCreatedNode; -extern SField const sfDeletedNode; -extern SField const sfModifiedNode; -extern SField const sfPreviousFields; -extern SField const sfFinalFields; -extern SField const sfNewFields; -extern SField const sfTemplateEntry; -extern SField const sfMemo; -extern SField const sfSignerEntry; -extern SField const sfNFToken; -extern SField const sfEmitDetails; -extern SField const sfHook; -extern SField const sfVoteEntry; -extern SField const sfAuctionSlot; -extern SField const sfAuthAccount; -extern SField const sfPriceData; - -extern SField const sfSigner; -extern SField const sfMajority; -extern SField const sfDisabledValidator; -extern SField const sfEmittedTxn; -extern SField const sfHookExecution; -extern SField const sfHookDefinition; -extern SField const sfHookParameter; -extern SField const sfHookGrant; -extern SField const sfXChainClaimProofSig; -extern SField const sfXChainCreateAccountProofSig; -extern SField const sfXChainClaimAttestationCollectionElement; -extern SField const sfXChainCreateAccountAttestationCollectionElement; - -// array of objects (common) -// ARRAY/1 is reserved for end of array -// extern SField const sfSigningAccounts; // Never been used. -extern SField const sfSigners; -extern SField const sfSignerEntries; -extern SField const sfTemplate; -extern SField const sfNecessary; -extern SField const sfSufficient; -extern SField const sfAffectedNodes; -extern SField const sfMemos; -extern SField const sfNFTokens; -extern SField const sfHooks; -extern SField const sfVoteSlots; -extern SField const sfAuthAccounts; -extern SField const sfPriceDataSeries; - -// array of objects (uncommon) -extern SField const sfMajorities; -extern SField const sfDisabledValidators; -extern SField const sfHookExecutions; -extern SField const sfHookParameters; -extern SField const sfHookGrants; -extern SField const sfXChainClaimAttestations; -extern SField const sfXChainCreateAccountAttestations; -//------------------------------------------------------------------------------ +#include + +#undef TYPED_SFIELD +#pragma pop_macro("TYPED_SFIELD") +#undef UNTYPED_SFIELD +#pragma pop_macro("UNTYPED_SFIELD") } // namespace ripple diff --git a/include/xrpl/protocol/TxFormats.h b/include/xrpl/protocol/TxFormats.h index a3f5cca108c..2f9121cecb4 100644 --- a/include/xrpl/protocol/TxFormats.h +++ b/include/xrpl/protocol/TxFormats.h @@ -55,168 +55,28 @@ namespace ripple { // clang-format off enum TxType : std::uint16_t { - /** This transaction type executes a payment. */ - ttPAYMENT = 0, - /** This transaction type creates an escrow object. */ - ttESCROW_CREATE = 1, +#pragma push_macro("TRANSACTION") +#undef TRANSACTION - /** This transaction type completes an existing escrow. */ - ttESCROW_FINISH = 2, +#define TRANSACTION(tag, value, name, fields) tag = value, - /** This transaction type adjusts various account settings. */ - ttACCOUNT_SET = 3, +#include - /** This transaction type cancels an existing escrow. */ - ttESCROW_CANCEL = 4, - - /** This transaction type sets or clears an account's "regular key". */ - ttREGULAR_KEY_SET = 5, +#undef TRANSACTION +#pragma pop_macro("TRANSACTION") /** This transaction type is deprecated; it is retained for historical purposes. */ ttNICKNAME_SET [[deprecated("This transaction type is not supported and should not be used.")]] = 6, - /** This transaction type creates an offer to trade one asset for another. */ - ttOFFER_CREATE = 7, - - /** This transaction type cancels existing offers to trade one asset for another. */ - ttOFFER_CANCEL = 8, - /** This transaction type is deprecated; it is retained for historical purposes. */ ttCONTRACT [[deprecated("This transaction type is not supported and should not be used.")]] = 9, - /** This transaction type creates a new set of tickets. */ - ttTICKET_CREATE = 10, - /** This identifier was never used, but the slot is reserved for historical purposes. */ ttSPINAL_TAP [[deprecated("This transaction type is not supported and should not be used.")]] = 11, - /** This transaction type modifies the signer list associated with an account. */ - ttSIGNER_LIST_SET = 12, - - /** This transaction type creates a new unidirectional XRP payment channel. */ - ttPAYCHAN_CREATE = 13, - - /** This transaction type funds an existing unidirectional XRP payment channel. */ - ttPAYCHAN_FUND = 14, - - /** This transaction type submits a claim against an existing unidirectional payment channel. */ - ttPAYCHAN_CLAIM = 15, - - /** This transaction type creates a new check. */ - ttCHECK_CREATE = 16, - - /** This transaction type cashes an existing check. */ - ttCHECK_CASH = 17, - - /** This transaction type cancels an existing check. */ - ttCHECK_CANCEL = 18, - - /** This transaction type grants or revokes authorization to transfer funds. */ - ttDEPOSIT_PREAUTH = 19, - - /** This transaction type modifies a trustline between two accounts. */ - ttTRUST_SET = 20, - - /** This transaction type deletes an existing account. */ - ttACCOUNT_DELETE = 21, - /** This transaction type installs a hook. */ ttHOOK_SET [[maybe_unused]] = 22, - - /** This transaction mints a new NFT. */ - ttNFTOKEN_MINT = 25, - - /** This transaction burns (i.e. destroys) an existing NFT. */ - ttNFTOKEN_BURN = 26, - - /** This transaction creates a new offer to buy or sell an NFT. */ - ttNFTOKEN_CREATE_OFFER = 27, - - /** This transaction cancels an existing offer to buy or sell an existing NFT. */ - ttNFTOKEN_CANCEL_OFFER = 28, - - /** This transaction accepts an existing offer to buy or sell an existing NFT. */ - ttNFTOKEN_ACCEPT_OFFER = 29, - - /** This transaction claws back issued tokens. */ - ttCLAWBACK = 30, - - /** This transaction type creates an AMM instance */ - ttAMM_CREATE = 35, - - /** This transaction type deposits into an AMM instance */ - ttAMM_DEPOSIT = 36, - - /** This transaction type withdraws from an AMM instance */ - ttAMM_WITHDRAW = 37, - - /** This transaction type votes for the trading fee */ - ttAMM_VOTE = 38, - - /** This transaction type bids for the auction slot */ - ttAMM_BID = 39, - - /** This transaction type deletes AMM in the empty state */ - ttAMM_DELETE = 40, - - /** This transactions creates a crosschain sequence number */ - ttXCHAIN_CREATE_CLAIM_ID = 41, - - /** This transactions initiates a crosschain transaction */ - ttXCHAIN_COMMIT = 42, - - /** This transaction completes a crosschain transaction */ - ttXCHAIN_CLAIM = 43, - - /** This transaction initiates a crosschain account create transaction */ - ttXCHAIN_ACCOUNT_CREATE_COMMIT = 44, - - /** This transaction adds an attestation to a claimid*/ - ttXCHAIN_ADD_CLAIM_ATTESTATION = 45, - - /** This transaction adds an attestation to a claimid*/ - ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION = 46, - - /** This transaction modifies a sidechain */ - ttXCHAIN_MODIFY_BRIDGE = 47, - - /** This transactions creates a sidechain */ - ttXCHAIN_CREATE_BRIDGE = 48, - - /** This transaction type creates or updates a DID */ - ttDID_SET = 49, - - /** This transaction type deletes a DID */ - ttDID_DELETE = 50, - - /** This transaction type creates an Oracle instance */ - ttORACLE_SET = 51, - - /** This transaction type deletes an Oracle instance */ - ttORACLE_DELETE = 52, - - /** This transaction type fixes a problem in the ledger state */ - ttLEDGER_STATE_FIX = 53, - - - /** This system-generated transaction type is used to update the status of the various amendments. - - For details, see: https://xrpl.org/amendments.html - */ - ttAMENDMENT = 100, - - /** This system-generated transaction type is used to update the network's fee settings. - - For details, see: https://xrpl.org/fee-voting.html - */ - ttFEE = 101, - - /** This system-generated transaction type is used to update the network's negative UNL - - For details, see: https://xrpl.org/negative-unl.html - */ - ttUNL_MODIFY = 102, }; // clang-format on diff --git a/include/xrpl/protocol/detail/features.macro b/include/xrpl/protocol/detail/features.macro new file mode 100644 index 00000000000..159bc3720b7 --- /dev/null +++ b/include/xrpl/protocol/detail/features.macro @@ -0,0 +1,112 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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. +*/ +//============================================================================== + +#if !defined(XRPL_FEATURE) +#error "undefined macro: XRPL_FEATURE" +#endif +#if !defined(XRPL_FIX) +#error "undefined macro: XRPL_FIX" +#endif + +// Add new amendments to the top of this list. +// Keep it sorted in reverse chronological order. +// If you add an amendment here, then do not forget to increment `numFeatures` +// in include/xrpl/protocol/Feature.h. + +// InvariantsV1_1 will be changes to Supported::yes when all the +// invariants expected to be included under it are complete. +XRPL_FEATURE(InvariantsV1_1, Supported::no, VoteBehavior::DefaultNo) +XRPL_FIX (NFTokenPageLinks, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (InnerObjTemplate2, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (EnforceNFTokenTrustline, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (ReducedOffersV2, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(NFTokenMintOffer, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (AMMv1_1, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (PreviousTxnID, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (XChainRewardRounding, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (EmptyDID, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(PriceOracle, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (AMMOverflowOffer, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FIX (InnerObjTemplate, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (NFTokenReserve, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (FillOrKill, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(DID, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (DisallowIncomingV1, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(XChainBridge, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(AMM, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(Clawback, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (ReducedOffersV1, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (NFTokenRemint, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (NonFungibleTokensV1_2, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (UniversalNumber, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(XRPFees, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(DisallowIncoming, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(ImmediateOfferKilled, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (RemoveNFTokenAutoTrustLine, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FIX (TrustLinesToSelf, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(NonFungibleTokensV1_1, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(ExpandedSignerList, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(CheckCashMakesTrustLine, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FIX (RmSmallIncreasedQOffers, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FIX (STAmountCanonicalize, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FEATURE(FlowSortStrands, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FEATURE(TicketBatch, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FEATURE(NegativeUNL, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FIX (AmendmentMajorityCalc, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FEATURE(HardenedValidations, Supported::yes, VoteBehavior::DefaultYes) +// fix1781: XRPEndpointSteps should be included in the circular payment check +XRPL_FIX (1781, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FEATURE(RequireFullyCanonicalSig, Supported::yes, VoteBehavior::DefaultYes) +// fixQualityUpperBound should be activated before FlowCross +XRPL_FIX (QualityUpperBound, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FEATURE(DeletableAccounts, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FIX (PayChanRecipientOwnerDir, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FIX (CheckThreading, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FIX (MasterKeyAsRegularKey, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FIX (TakerDryOfferRemoval, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FEATURE(MultiSignReserve, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FIX (1578, Supported::yes, VoteBehavior::DefaultYes) +// fix1515: Use liquidity from strands that consume max offers, but mark as dry +XRPL_FIX (1515, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FEATURE(DepositPreauth, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FIX (1623, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FIX (1543, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FIX (1571, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FEATURE(Checks, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FEATURE(DepositAuth, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FIX (1513, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FEATURE(FlowCross, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FEATURE(Flow, Supported::yes, VoteBehavior::DefaultYes) +XRPL_FEATURE(OwnerPaysFee, Supported::no, VoteBehavior::DefaultNo) + +// The following amendments are obsolete, but must remain supported +// because they could potentially get enabled. +// +// Obsolete features are (usually) not in the ledger, and may have code +// controlled by the feature. They need to be supported because at some +// time in the past, the feature was supported and votable, but never +// passed. So the feature needs to be supported in case it is ever +// enabled (added to the ledger). +// +// If a feature remains obsolete for long enough that no clients are able +// to vote for it, the feature can be removed (entirely?) from the code. +XRPL_FIX (NFTokenNegOffer, Supported::yes, VoteBehavior::Obsolete) +XRPL_FIX (NFTokenDirV1, Supported::yes, VoteBehavior::Obsolete) +XRPL_FEATURE(NonFungibleTokensV1, Supported::yes, VoteBehavior::Obsolete) +XRPL_FEATURE(CryptoConditionsSuite, Supported::yes, VoteBehavior::Obsolete) diff --git a/include/xrpl/protocol/detail/ledger_entries.macro b/include/xrpl/protocol/detail/ledger_entries.macro new file mode 100644 index 00000000000..359000cbbf3 --- /dev/null +++ b/include/xrpl/protocol/detail/ledger_entries.macro @@ -0,0 +1,394 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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. +*/ +//============================================================================== + +#if !defined(LEDGER_ENTRY) +#error "undefined macro: LEDGER_ENTRY" +#endif + +/** + * These objects are listed in order of increasing ledger type ID. + * There are many gaps between these IDs. + * You are welcome to fill them with new object types. + */ + +/** A ledger object which identifies an offer to buy or sell an NFT. + + \sa keylet::nftoffer + */ +LEDGER_ENTRY(ltNFTOKEN_OFFER, 0x0037, NFTokenOffer, ({ + {sfOwner, soeREQUIRED}, + {sfNFTokenID, soeREQUIRED}, + {sfAmount, soeREQUIRED}, + {sfOwnerNode, soeREQUIRED}, + {sfNFTokenOfferNode, soeREQUIRED}, + {sfDestination, soeOPTIONAL}, + {sfExpiration, soeOPTIONAL}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, +})) + +/** A ledger object which describes a check. + + \sa keylet::check + */ +LEDGER_ENTRY(ltCHECK, 0x0043, Check, ({ + {sfAccount, soeREQUIRED}, + {sfDestination, soeREQUIRED}, + {sfSendMax, soeREQUIRED}, + {sfSequence, soeREQUIRED}, + {sfOwnerNode, soeREQUIRED}, + {sfDestinationNode, soeREQUIRED}, + {sfExpiration, soeOPTIONAL}, + {sfInvoiceID, soeOPTIONAL}, + {sfSourceTag, soeOPTIONAL}, + {sfDestinationTag, soeOPTIONAL}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, +})) + +/** The ledger object which tracks the DID. + + \sa keylet::did +*/ +LEDGER_ENTRY(ltDID, 0x0049, DID, ({ + {sfAccount, soeREQUIRED}, + {sfDIDDocument, soeOPTIONAL}, + {sfURI, soeOPTIONAL}, + {sfData, soeOPTIONAL}, + {sfOwnerNode, soeREQUIRED}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, +})) + +/** The ledger object which tracks the current negative UNL state. + + \note This is a singleton: only one such object exists in the ledger. + + \sa keylet::negativeUNL + */ +LEDGER_ENTRY(ltNEGATIVE_UNL, 0x004e, NegativeUNL, ({ + {sfDisabledValidators, soeOPTIONAL}, + {sfValidatorToDisable, soeOPTIONAL}, + {sfValidatorToReEnable, soeOPTIONAL}, + {sfPreviousTxnID, soeOPTIONAL}, + {sfPreviousTxnLgrSeq, soeOPTIONAL}, +})) + +/** A ledger object which contains a list of NFTs + + \sa keylet::nftpage_min, keylet::nftpage_max, keylet::nftpage + */ +LEDGER_ENTRY(ltNFTOKEN_PAGE, 0x0050, NFTokenPage, ({ + {sfPreviousPageMin, soeOPTIONAL}, + {sfNextPageMin, soeOPTIONAL}, + {sfNFTokens, soeREQUIRED}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, +})) + +/** A ledger object which contains a signer list for an account. + + \sa keylet::signers + */ +// All fields are soeREQUIRED because there is always a SignerEntries. +// If there are no SignerEntries the node is deleted. +LEDGER_ENTRY(ltSIGNER_LIST, 0x0053, SignerList, ({ + {sfOwnerNode, soeREQUIRED}, + {sfSignerQuorum, soeREQUIRED}, + {sfSignerEntries, soeREQUIRED}, + {sfSignerListID, soeREQUIRED}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, +})) + +/** A ledger object which describes a ticket. + + \sa keylet::ticket + */ +LEDGER_ENTRY(ltTICKET, 0x0054, Ticket, ({ + {sfAccount, soeREQUIRED}, + {sfOwnerNode, soeREQUIRED}, + {sfTicketSequence, soeREQUIRED}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, +})) + +/** A ledger object which describes an account. + + \sa keylet::account + */ +LEDGER_ENTRY(ltACCOUNT_ROOT, 0x0061, AccountRoot, ({ + {sfAccount, soeREQUIRED}, + {sfSequence, soeREQUIRED}, + {sfBalance, soeREQUIRED}, + {sfOwnerCount, soeREQUIRED}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, + {sfAccountTxnID, soeOPTIONAL}, + {sfRegularKey, soeOPTIONAL}, + {sfEmailHash, soeOPTIONAL}, + {sfWalletLocator, soeOPTIONAL}, + {sfWalletSize, soeOPTIONAL}, + {sfMessageKey, soeOPTIONAL}, + {sfTransferRate, soeOPTIONAL}, + {sfDomain, soeOPTIONAL}, + {sfTickSize, soeOPTIONAL}, + {sfTicketCount, soeOPTIONAL}, + {sfNFTokenMinter, soeOPTIONAL}, + {sfMintedNFTokens, soeDEFAULT}, + {sfBurnedNFTokens, soeDEFAULT}, + {sfFirstNFTokenSequence, soeOPTIONAL}, + {sfAMMID, soeOPTIONAL}, +})) + +/** A ledger object which contains a list of object identifiers. + + \sa keylet::page, keylet::quality, keylet::book, keylet::next and + keylet::ownerDir + */ +LEDGER_ENTRY(ltDIR_NODE, 0x0064, DirectoryNode, ({ + {sfOwner, soeOPTIONAL}, // for owner directories + {sfTakerPaysCurrency, soeOPTIONAL}, // order book directories + {sfTakerPaysIssuer, soeOPTIONAL}, // order book directories + {sfTakerGetsCurrency, soeOPTIONAL}, // order book directories + {sfTakerGetsIssuer, soeOPTIONAL}, // order book directories + {sfExchangeRate, soeOPTIONAL}, // order book directories + {sfIndexes, soeREQUIRED}, + {sfRootIndex, soeREQUIRED}, + {sfIndexNext, soeOPTIONAL}, + {sfIndexPrevious, soeOPTIONAL}, + {sfNFTokenID, soeOPTIONAL}, + {sfPreviousTxnID, soeOPTIONAL}, + {sfPreviousTxnLgrSeq, soeOPTIONAL}, +})) + +/** The ledger object which lists details about amendments on the network. + + \note This is a singleton: only one such object exists in the ledger. + + \sa keylet::amendments + */ +LEDGER_ENTRY(ltAMENDMENTS, 0x0066, Amendments, ({ + {sfAmendments, soeOPTIONAL}, // Enabled + {sfMajorities, soeOPTIONAL}, + {sfPreviousTxnID, soeOPTIONAL}, + {sfPreviousTxnLgrSeq, soeOPTIONAL}, +})) + +/** A ledger object that contains a list of ledger hashes. + + This type is used to store the ledger hashes which the protocol uses + to implement skip lists that allow for efficient backwards (and, in + theory, forward) forward iteration across large ledger ranges. + + \sa keylet::skip + */ +LEDGER_ENTRY(ltLEDGER_HASHES, 0x0068, LedgerHashes, ({ + {sfFirstLedgerSequence, soeOPTIONAL}, + {sfLastLedgerSequence, soeOPTIONAL}, + {sfHashes, soeREQUIRED}, +})) + +/** The ledger object which lists details about sidechains. + + \sa keylet::bridge +*/ +LEDGER_ENTRY(ltBRIDGE, 0x0069, Bridge, ({ + {sfAccount, soeREQUIRED}, + {sfSignatureReward, soeREQUIRED}, + {sfMinAccountCreateAmount, soeOPTIONAL}, + {sfXChainBridge, soeREQUIRED}, + {sfXChainClaimID, soeREQUIRED}, + {sfXChainAccountCreateCount, soeREQUIRED}, + {sfXChainAccountClaimCount, soeREQUIRED}, + {sfOwnerNode, soeREQUIRED}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, +})) + +/** A ledger object which describes an offer on the DEX. + + \sa keylet::offer + */ +LEDGER_ENTRY(ltOFFER, 0x006f, Offer, ({ + {sfAccount, soeREQUIRED}, + {sfSequence, soeREQUIRED}, + {sfTakerPays, soeREQUIRED}, + {sfTakerGets, soeREQUIRED}, + {sfBookDirectory, soeREQUIRED}, + {sfBookNode, soeREQUIRED}, + {sfOwnerNode, soeREQUIRED}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, + {sfExpiration, soeOPTIONAL}, +})) + +/** A ledger object which describes a deposit preauthorization. + + \sa keylet::depositPreauth + */ +LEDGER_ENTRY(ltDEPOSIT_PREAUTH, 0x0070, DepositPreauth, ({ + {sfAccount, soeREQUIRED}, + {sfAuthorize, soeREQUIRED}, + {sfOwnerNode, soeREQUIRED}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, +})) + +/** A claim id for a cross chain transaction. + + \sa keylet::xChainClaimID +*/ +LEDGER_ENTRY(ltXCHAIN_OWNED_CLAIM_ID, 0x0071, XChainOwnedClaimID, ({ + {sfAccount, soeREQUIRED}, + {sfXChainBridge, soeREQUIRED}, + {sfXChainClaimID, soeREQUIRED}, + {sfOtherChainSource, soeREQUIRED}, + {sfXChainClaimAttestations, soeREQUIRED}, + {sfSignatureReward, soeREQUIRED}, + {sfOwnerNode, soeREQUIRED}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, +})) + +/** A ledger object which describes a bidirectional trust line. + + @note Per Vinnie Falco this should be renamed to ltTRUST_LINE + + \sa keylet::line + */ +LEDGER_ENTRY(ltRIPPLE_STATE, 0x0072, RippleState, ({ + {sfBalance, soeREQUIRED}, + {sfLowLimit, soeREQUIRED}, + {sfHighLimit, soeREQUIRED}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, + {sfLowNode, soeOPTIONAL}, + {sfLowQualityIn, soeOPTIONAL}, + {sfLowQualityOut, soeOPTIONAL}, + {sfHighNode, soeOPTIONAL}, + {sfHighQualityIn, soeOPTIONAL}, + {sfHighQualityOut, soeOPTIONAL}, +})) + +/** The ledger object which lists the network's fee settings. + + \note This is a singleton: only one such object exists in the ledger. + + \sa keylet::fees + */ +LEDGER_ENTRY(ltFEE_SETTINGS, 0x0073, FeeSettings, ({ + // Old version uses raw numbers + {sfBaseFee, soeOPTIONAL}, + {sfReferenceFeeUnits, soeOPTIONAL}, + {sfReserveBase, soeOPTIONAL}, + {sfReserveIncrement, soeOPTIONAL}, + // New version uses Amounts + {sfBaseFeeDrops, soeOPTIONAL}, + {sfReserveBaseDrops, soeOPTIONAL}, + {sfReserveIncrementDrops, soeOPTIONAL}, + {sfPreviousTxnID, soeOPTIONAL}, + {sfPreviousTxnLgrSeq, soeOPTIONAL}, +})) + +/** A claim id for a cross chain create account transaction. + + \sa keylet::xChainCreateAccountClaimID +*/ +LEDGER_ENTRY(ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID, 0x0074, XChainOwnedCreateAccountClaimID, ({ + {sfAccount, soeREQUIRED}, + {sfXChainBridge, soeREQUIRED}, + {sfXChainAccountCreateCount, soeREQUIRED}, + {sfXChainCreateAccountAttestations, soeREQUIRED}, + {sfOwnerNode, soeREQUIRED}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, +})) + +/** A ledger object describing a single escrow. + + \sa keylet::escrow + */ +LEDGER_ENTRY(ltESCROW, 0x0075, Escrow, ({ + {sfAccount, soeREQUIRED}, + {sfDestination, soeREQUIRED}, + {sfAmount, soeREQUIRED}, + {sfCondition, soeOPTIONAL}, + {sfCancelAfter, soeOPTIONAL}, + {sfFinishAfter, soeOPTIONAL}, + {sfSourceTag, soeOPTIONAL}, + {sfDestinationTag, soeOPTIONAL}, + {sfOwnerNode, soeREQUIRED}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, + {sfDestinationNode, soeOPTIONAL}, +})) + +/** A ledger object describing a single unidirectional XRP payment channel. + + \sa keylet::payChan + */ +LEDGER_ENTRY(ltPAYCHAN, 0x0078, PayChannel, ({ + {sfAccount, soeREQUIRED}, + {sfDestination, soeREQUIRED}, + {sfAmount, soeREQUIRED}, + {sfBalance, soeREQUIRED}, + {sfPublicKey, soeREQUIRED}, + {sfSettleDelay, soeREQUIRED}, + {sfExpiration, soeOPTIONAL}, + {sfCancelAfter, soeOPTIONAL}, + {sfSourceTag, soeOPTIONAL}, + {sfDestinationTag, soeOPTIONAL}, + {sfOwnerNode, soeREQUIRED}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, + {sfDestinationNode, soeOPTIONAL}, +})) + +/** The ledger object which tracks the AMM. + + \sa keylet::amm +*/ +LEDGER_ENTRY(ltAMM, 0x0079, AMM, ({ + {sfAccount, soeREQUIRED}, + {sfTradingFee, soeDEFAULT}, + {sfVoteSlots, soeOPTIONAL}, + {sfAuctionSlot, soeOPTIONAL}, + {sfLPTokenBalance, soeREQUIRED}, + {sfAsset, soeREQUIRED}, + {sfAsset2, soeREQUIRED}, + {sfOwnerNode, soeREQUIRED}, + {sfPreviousTxnID, soeOPTIONAL}, + {sfPreviousTxnLgrSeq, soeOPTIONAL}, +})) + +/** A ledger object which tracks Oracle + \sa keylet::oracle + */ +LEDGER_ENTRY(ltORACLE, 0x0080, Oracle, ({ + {sfOwner, soeREQUIRED}, + {sfProvider, soeREQUIRED}, + {sfPriceDataSeries, soeREQUIRED}, + {sfAssetClass, soeREQUIRED}, + {sfLastUpdateTime, soeREQUIRED}, + {sfURI, soeOPTIONAL}, + {sfOwnerNode, soeREQUIRED}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, +})) diff --git a/include/xrpl/protocol/detail/sfields.macro b/include/xrpl/protocol/detail/sfields.macro new file mode 100644 index 00000000000..bdfcf5dfafd --- /dev/null +++ b/include/xrpl/protocol/detail/sfields.macro @@ -0,0 +1,357 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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. +*/ +//============================================================================== + +#if !defined(UNTYPED_SFIELD) +#error "undefined macro: UNTYPED_SFIELD" +#endif +#if !defined(TYPED_SFIELD) +#error "undefined macro: TYPED_SFIELD" +#endif + +// untyped +UNTYPED_SFIELD(sfLedgerEntry, LEDGERENTRY, 257) +UNTYPED_SFIELD(sfTransaction, TRANSACTION, 257) +UNTYPED_SFIELD(sfValidation, VALIDATION, 257) +UNTYPED_SFIELD(sfMetadata, METADATA, 257) + +// 8-bit integers (common) +TYPED_SFIELD(sfCloseResolution, UINT8, 1) +TYPED_SFIELD(sfMethod, UINT8, 2) +TYPED_SFIELD(sfTransactionResult, UINT8, 3) +TYPED_SFIELD(sfScale, UINT8, 4) + +// 8-bit integers (uncommon) +TYPED_SFIELD(sfTickSize, UINT8, 16) +TYPED_SFIELD(sfUNLModifyDisabling, UINT8, 17) +TYPED_SFIELD(sfHookResult, UINT8, 18) +TYPED_SFIELD(sfWasLockingChainSend, UINT8, 19) + +// 16-bit integers (common) +TYPED_SFIELD(sfLedgerEntryType, UINT16, 1, SField::sMD_Never) +TYPED_SFIELD(sfTransactionType, UINT16, 2) +TYPED_SFIELD(sfSignerWeight, UINT16, 3) +TYPED_SFIELD(sfTransferFee, UINT16, 4) +TYPED_SFIELD(sfTradingFee, UINT16, 5) +TYPED_SFIELD(sfDiscountedFee, UINT16, 6) + +// 16-bit integers (uncommon) +TYPED_SFIELD(sfVersion, UINT16, 16) +TYPED_SFIELD(sfHookStateChangeCount, UINT16, 17) +TYPED_SFIELD(sfHookEmitCount, UINT16, 18) +TYPED_SFIELD(sfHookExecutionIndex, UINT16, 19) +TYPED_SFIELD(sfHookApiVersion, UINT16, 20) +TYPED_SFIELD(sfLedgerFixType, UINT16, 21) + +// 32-bit integers (common) +TYPED_SFIELD(sfNetworkID, UINT32, 1) +TYPED_SFIELD(sfFlags, UINT32, 2) +TYPED_SFIELD(sfSourceTag, UINT32, 3) +TYPED_SFIELD(sfSequence, UINT32, 4) +TYPED_SFIELD(sfPreviousTxnLgrSeq, UINT32, 5, SField::sMD_DeleteFinal) +TYPED_SFIELD(sfLedgerSequence, UINT32, 6) +TYPED_SFIELD(sfCloseTime, UINT32, 7) +TYPED_SFIELD(sfParentCloseTime, UINT32, 8) +TYPED_SFIELD(sfSigningTime, UINT32, 9) +TYPED_SFIELD(sfExpiration, UINT32, 10) +TYPED_SFIELD(sfTransferRate, UINT32, 11) +TYPED_SFIELD(sfWalletSize, UINT32, 12) +TYPED_SFIELD(sfOwnerCount, UINT32, 13) +TYPED_SFIELD(sfDestinationTag, UINT32, 14) +TYPED_SFIELD(sfLastUpdateTime, UINT32, 15) + +// 32-bit integers (uncommon) +TYPED_SFIELD(sfHighQualityIn, UINT32, 16) +TYPED_SFIELD(sfHighQualityOut, UINT32, 17) +TYPED_SFIELD(sfLowQualityIn, UINT32, 18) +TYPED_SFIELD(sfLowQualityOut, UINT32, 19) +TYPED_SFIELD(sfQualityIn, UINT32, 20) +TYPED_SFIELD(sfQualityOut, UINT32, 21) +TYPED_SFIELD(sfStampEscrow, UINT32, 22) +TYPED_SFIELD(sfBondAmount, UINT32, 23) +TYPED_SFIELD(sfLoadFee, UINT32, 24) +TYPED_SFIELD(sfOfferSequence, UINT32, 25) +TYPED_SFIELD(sfFirstLedgerSequence, UINT32, 26) +TYPED_SFIELD(sfLastLedgerSequence, UINT32, 27) +TYPED_SFIELD(sfTransactionIndex, UINT32, 28) +TYPED_SFIELD(sfOperationLimit, UINT32, 29) +TYPED_SFIELD(sfReferenceFeeUnits, UINT32, 30) +TYPED_SFIELD(sfReserveBase, UINT32, 31) +TYPED_SFIELD(sfReserveIncrement, UINT32, 32) +TYPED_SFIELD(sfSetFlag, UINT32, 33) +TYPED_SFIELD(sfClearFlag, UINT32, 34) +TYPED_SFIELD(sfSignerQuorum, UINT32, 35) +TYPED_SFIELD(sfCancelAfter, UINT32, 36) +TYPED_SFIELD(sfFinishAfter, UINT32, 37) +TYPED_SFIELD(sfSignerListID, UINT32, 38) +TYPED_SFIELD(sfSettleDelay, UINT32, 39) +TYPED_SFIELD(sfTicketCount, UINT32, 40) +TYPED_SFIELD(sfTicketSequence, UINT32, 41) +TYPED_SFIELD(sfNFTokenTaxon, UINT32, 42) +TYPED_SFIELD(sfMintedNFTokens, UINT32, 43) +TYPED_SFIELD(sfBurnedNFTokens, UINT32, 44) +TYPED_SFIELD(sfHookStateCount, UINT32, 45) +TYPED_SFIELD(sfEmitGeneration, UINT32, 46) +// 47 reserved for Hooks +TYPED_SFIELD(sfVoteWeight, UINT32, 48) +TYPED_SFIELD(sfFirstNFTokenSequence, UINT32, 50) +TYPED_SFIELD(sfOracleDocumentID, UINT32, 51) + +// 64-bit integers (common) +TYPED_SFIELD(sfIndexNext, UINT64, 1) +TYPED_SFIELD(sfIndexPrevious, UINT64, 2) +TYPED_SFIELD(sfBookNode, UINT64, 3) +TYPED_SFIELD(sfOwnerNode, UINT64, 4) +TYPED_SFIELD(sfBaseFee, UINT64, 5) +TYPED_SFIELD(sfExchangeRate, UINT64, 6) +TYPED_SFIELD(sfLowNode, UINT64, 7) +TYPED_SFIELD(sfHighNode, UINT64, 8) +TYPED_SFIELD(sfDestinationNode, UINT64, 9) +TYPED_SFIELD(sfCookie, UINT64, 10) +TYPED_SFIELD(sfServerVersion, UINT64, 11) +TYPED_SFIELD(sfNFTokenOfferNode, UINT64, 12) +TYPED_SFIELD(sfEmitBurden, UINT64, 13) + +// 64-bit integers (uncommon) +TYPED_SFIELD(sfHookOn, UINT64, 16) +TYPED_SFIELD(sfHookInstructionCount, UINT64, 17) +TYPED_SFIELD(sfHookReturnCode, UINT64, 18) +TYPED_SFIELD(sfReferenceCount, UINT64, 19) +TYPED_SFIELD(sfXChainClaimID, UINT64, 20) +TYPED_SFIELD(sfXChainAccountCreateCount, UINT64, 21) +TYPED_SFIELD(sfXChainAccountClaimCount, UINT64, 22) +TYPED_SFIELD(sfAssetPrice, UINT64, 23) + +// 128-bit +TYPED_SFIELD(sfEmailHash, UINT128, 1) + +// 160-bit (common) +TYPED_SFIELD(sfTakerPaysCurrency, UINT160, 1) +TYPED_SFIELD(sfTakerPaysIssuer, UINT160, 2) +TYPED_SFIELD(sfTakerGetsCurrency, UINT160, 3) +TYPED_SFIELD(sfTakerGetsIssuer, UINT160, 4) + +// 256-bit (common) +TYPED_SFIELD(sfLedgerHash, UINT256, 1) +TYPED_SFIELD(sfParentHash, UINT256, 2) +TYPED_SFIELD(sfTransactionHash, UINT256, 3) +TYPED_SFIELD(sfAccountHash, UINT256, 4) +TYPED_SFIELD(sfPreviousTxnID, UINT256, 5, SField::sMD_DeleteFinal) +TYPED_SFIELD(sfLedgerIndex, UINT256, 6) +TYPED_SFIELD(sfWalletLocator, UINT256, 7) +TYPED_SFIELD(sfRootIndex, UINT256, 8, SField::sMD_Always) +TYPED_SFIELD(sfAccountTxnID, UINT256, 9) +TYPED_SFIELD(sfNFTokenID, UINT256, 10) +TYPED_SFIELD(sfEmitParentTxnID, UINT256, 11) +TYPED_SFIELD(sfEmitNonce, UINT256, 12) +TYPED_SFIELD(sfEmitHookHash, UINT256, 13) +TYPED_SFIELD(sfAMMID, UINT256, 14) + +// 256-bit (uncommon) +TYPED_SFIELD(sfBookDirectory, UINT256, 16) +TYPED_SFIELD(sfInvoiceID, UINT256, 17) +TYPED_SFIELD(sfNickname, UINT256, 18) +TYPED_SFIELD(sfAmendment, UINT256, 19) +// 20 unused +TYPED_SFIELD(sfDigest, UINT256, 21) +TYPED_SFIELD(sfChannel, UINT256, 22) +TYPED_SFIELD(sfConsensusHash, UINT256, 23) +TYPED_SFIELD(sfCheckID, UINT256, 24) +TYPED_SFIELD(sfValidatedHash, UINT256, 25) +TYPED_SFIELD(sfPreviousPageMin, UINT256, 26) +TYPED_SFIELD(sfNextPageMin, UINT256, 27) +TYPED_SFIELD(sfNFTokenBuyOffer, UINT256, 28) +TYPED_SFIELD(sfNFTokenSellOffer, UINT256, 29) +TYPED_SFIELD(sfHookStateKey, UINT256, 30) +TYPED_SFIELD(sfHookHash, UINT256, 31) +TYPED_SFIELD(sfHookNamespace, UINT256, 32) +TYPED_SFIELD(sfHookSetTxnID, UINT256, 33) + +// currency amount (common) +TYPED_SFIELD(sfAmount, AMOUNT, 1) +TYPED_SFIELD(sfBalance, AMOUNT, 2) +TYPED_SFIELD(sfLimitAmount, AMOUNT, 3) +TYPED_SFIELD(sfTakerPays, AMOUNT, 4) +TYPED_SFIELD(sfTakerGets, AMOUNT, 5) +TYPED_SFIELD(sfLowLimit, AMOUNT, 6) +TYPED_SFIELD(sfHighLimit, AMOUNT, 7) +TYPED_SFIELD(sfFee, AMOUNT, 8) +TYPED_SFIELD(sfSendMax, AMOUNT, 9) +TYPED_SFIELD(sfDeliverMin, AMOUNT, 10) +TYPED_SFIELD(sfAmount2, AMOUNT, 11) +TYPED_SFIELD(sfBidMin, AMOUNT, 12) +TYPED_SFIELD(sfBidMax, AMOUNT, 13) + +// currency amount (uncommon) +TYPED_SFIELD(sfMinimumOffer, AMOUNT, 16) +TYPED_SFIELD(sfRippleEscrow, AMOUNT, 17) +TYPED_SFIELD(sfDeliveredAmount, AMOUNT, 18) +TYPED_SFIELD(sfNFTokenBrokerFee, AMOUNT, 19) + +// Reserve 20 & 21 for Hooks. + +// currency amount (fees) +TYPED_SFIELD(sfBaseFeeDrops, AMOUNT, 22) +TYPED_SFIELD(sfReserveBaseDrops, AMOUNT, 23) +TYPED_SFIELD(sfReserveIncrementDrops, AMOUNT, 24) + +// currency amount (AMM) +TYPED_SFIELD(sfLPTokenOut, AMOUNT, 25) +TYPED_SFIELD(sfLPTokenIn, AMOUNT, 26) +TYPED_SFIELD(sfEPrice, AMOUNT, 27) +TYPED_SFIELD(sfPrice, AMOUNT, 28) +TYPED_SFIELD(sfSignatureReward, AMOUNT, 29) +TYPED_SFIELD(sfMinAccountCreateAmount, AMOUNT, 30) +TYPED_SFIELD(sfLPTokenBalance, AMOUNT, 31) + +// variable length (common) +TYPED_SFIELD(sfPublicKey, VL, 1) +TYPED_SFIELD(sfMessageKey, VL, 2) +TYPED_SFIELD(sfSigningPubKey, VL, 3) +TYPED_SFIELD(sfTxnSignature, VL, 4, SField::sMD_Default, SField::notSigning) +TYPED_SFIELD(sfURI, VL, 5) +TYPED_SFIELD(sfSignature, VL, 6, SField::sMD_Default, SField::notSigning) +TYPED_SFIELD(sfDomain, VL, 7) +TYPED_SFIELD(sfFundCode, VL, 8) +TYPED_SFIELD(sfRemoveCode, VL, 9) +TYPED_SFIELD(sfExpireCode, VL, 10) +TYPED_SFIELD(sfCreateCode, VL, 11) +TYPED_SFIELD(sfMemoType, VL, 12) +TYPED_SFIELD(sfMemoData, VL, 13) +TYPED_SFIELD(sfMemoFormat, VL, 14) + +// variable length (uncommon) +TYPED_SFIELD(sfFulfillment, VL, 16) +TYPED_SFIELD(sfCondition, VL, 17) +TYPED_SFIELD(sfMasterSignature, VL, 18, SField::sMD_Default, SField::notSigning) +TYPED_SFIELD(sfUNLModifyValidator, VL, 19) +TYPED_SFIELD(sfValidatorToDisable, VL, 20) +TYPED_SFIELD(sfValidatorToReEnable, VL, 21) +TYPED_SFIELD(sfHookStateData, VL, 22) +TYPED_SFIELD(sfHookReturnString, VL, 23) +TYPED_SFIELD(sfHookParameterName, VL, 24) +TYPED_SFIELD(sfHookParameterValue, VL, 25) +TYPED_SFIELD(sfDIDDocument, VL, 26) +TYPED_SFIELD(sfData, VL, 27) +TYPED_SFIELD(sfAssetClass, VL, 28) +TYPED_SFIELD(sfProvider, VL, 29) + +// account (common) +TYPED_SFIELD(sfAccount, ACCOUNT, 1) +TYPED_SFIELD(sfOwner, ACCOUNT, 2) +TYPED_SFIELD(sfDestination, ACCOUNT, 3) +TYPED_SFIELD(sfIssuer, ACCOUNT, 4) +TYPED_SFIELD(sfAuthorize, ACCOUNT, 5) +TYPED_SFIELD(sfUnauthorize, ACCOUNT, 6) +// 7 unused +TYPED_SFIELD(sfRegularKey, ACCOUNT, 8) +TYPED_SFIELD(sfNFTokenMinter, ACCOUNT, 9) +TYPED_SFIELD(sfEmitCallback, ACCOUNT, 10) + +// account (uncommon) +TYPED_SFIELD(sfHookAccount, ACCOUNT, 16) +TYPED_SFIELD(sfOtherChainSource, ACCOUNT, 18) +TYPED_SFIELD(sfOtherChainDestination, ACCOUNT, 19) +TYPED_SFIELD(sfAttestationSignerAccount, ACCOUNT, 20) +TYPED_SFIELD(sfAttestationRewardAccount, ACCOUNT, 21) +TYPED_SFIELD(sfLockingChainDoor, ACCOUNT, 22) +TYPED_SFIELD(sfIssuingChainDoor, ACCOUNT, 23) + +// vector of 256-bit +TYPED_SFIELD(sfIndexes, VECTOR256, 1, SField::sMD_Never) +TYPED_SFIELD(sfHashes, VECTOR256, 2) +TYPED_SFIELD(sfAmendments, VECTOR256, 3) +TYPED_SFIELD(sfNFTokenOffers, VECTOR256, 4) + +// path set +UNTYPED_SFIELD(sfPaths, PATHSET, 1) + +// currency +TYPED_SFIELD(sfBaseAsset, CURRENCY, 1) +TYPED_SFIELD(sfQuoteAsset, CURRENCY, 2) + +// issue +TYPED_SFIELD(sfLockingChainIssue, ISSUE, 1) +TYPED_SFIELD(sfIssuingChainIssue, ISSUE, 2) +TYPED_SFIELD(sfAsset, ISSUE, 3) +TYPED_SFIELD(sfAsset2, ISSUE, 4) + +// bridge +TYPED_SFIELD(sfXChainBridge, XCHAIN_BRIDGE, 1) + +// inner object +// OBJECT/1 is reserved for end of object +UNTYPED_SFIELD(sfTransactionMetaData, OBJECT, 2) +UNTYPED_SFIELD(sfCreatedNode, OBJECT, 3) +UNTYPED_SFIELD(sfDeletedNode, OBJECT, 4) +UNTYPED_SFIELD(sfModifiedNode, OBJECT, 5) +UNTYPED_SFIELD(sfPreviousFields, OBJECT, 6) +UNTYPED_SFIELD(sfFinalFields, OBJECT, 7) +UNTYPED_SFIELD(sfNewFields, OBJECT, 8) +UNTYPED_SFIELD(sfTemplateEntry, OBJECT, 9) +UNTYPED_SFIELD(sfMemo, OBJECT, 10) +UNTYPED_SFIELD(sfSignerEntry, OBJECT, 11) +UNTYPED_SFIELD(sfNFToken, OBJECT, 12) +UNTYPED_SFIELD(sfEmitDetails, OBJECT, 13) +UNTYPED_SFIELD(sfHook, OBJECT, 14) + +// inner object (uncommon) +UNTYPED_SFIELD(sfSigner, OBJECT, 16) +// 17 unused +UNTYPED_SFIELD(sfMajority, OBJECT, 18) +UNTYPED_SFIELD(sfDisabledValidator, OBJECT, 19) +UNTYPED_SFIELD(sfEmittedTxn, OBJECT, 20) +UNTYPED_SFIELD(sfHookExecution, OBJECT, 21) +UNTYPED_SFIELD(sfHookDefinition, OBJECT, 22) +UNTYPED_SFIELD(sfHookParameter, OBJECT, 23) +UNTYPED_SFIELD(sfHookGrant, OBJECT, 24) +UNTYPED_SFIELD(sfVoteEntry, OBJECT, 25) +UNTYPED_SFIELD(sfAuctionSlot, OBJECT, 26) +UNTYPED_SFIELD(sfAuthAccount, OBJECT, 27) +UNTYPED_SFIELD(sfXChainClaimProofSig, OBJECT, 28) +UNTYPED_SFIELD(sfXChainCreateAccountProofSig, OBJECT, 29) +UNTYPED_SFIELD(sfXChainClaimAttestationCollectionElement, OBJECT, 30) +UNTYPED_SFIELD(sfXChainCreateAccountAttestationCollectionElement, OBJECT, 31) +UNTYPED_SFIELD(sfPriceData, OBJECT, 32) + +// array of objects (common) +// ARRAY/1 is reserved for end of array +// sfSigningAccounts has never been used. +//UNTYPED_SFIELD(sfSigningAccounts, ARRAY, 2) +UNTYPED_SFIELD(sfSigners, ARRAY, 3, SField::sMD_Default, SField::notSigning) +UNTYPED_SFIELD(sfSignerEntries, ARRAY, 4) +UNTYPED_SFIELD(sfTemplate, ARRAY, 5) +UNTYPED_SFIELD(sfNecessary, ARRAY, 6) +UNTYPED_SFIELD(sfSufficient, ARRAY, 7) +UNTYPED_SFIELD(sfAffectedNodes, ARRAY, 8) +UNTYPED_SFIELD(sfMemos, ARRAY, 9) +UNTYPED_SFIELD(sfNFTokens, ARRAY, 10) +UNTYPED_SFIELD(sfHooks, ARRAY, 11) +UNTYPED_SFIELD(sfVoteSlots, ARRAY, 12) + +// array of objects (uncommon) +UNTYPED_SFIELD(sfMajorities, ARRAY, 16) +UNTYPED_SFIELD(sfDisabledValidators, ARRAY, 17) +UNTYPED_SFIELD(sfHookExecutions, ARRAY, 18) +UNTYPED_SFIELD(sfHookParameters, ARRAY, 19) +UNTYPED_SFIELD(sfHookGrants, ARRAY, 20) +UNTYPED_SFIELD(sfXChainClaimAttestations, ARRAY, 21) +UNTYPED_SFIELD(sfXChainCreateAccountAttestations, ARRAY, 22) +// 23 unused +UNTYPED_SFIELD(sfPriceDataSeries, ARRAY, 24) +UNTYPED_SFIELD(sfAuthAccounts, ARRAY, 25) diff --git a/include/xrpl/protocol/detail/transactions.macro b/include/xrpl/protocol/detail/transactions.macro new file mode 100644 index 00000000000..98678e9d509 --- /dev/null +++ b/include/xrpl/protocol/detail/transactions.macro @@ -0,0 +1,423 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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. +*/ +//============================================================================== + +#if !defined(TRANSACTION) +#error "undefined macro: TRANSACTION" +#endif + +/** + * TRANSACTION(tag, value, name, fields) + * + * You must define a transactor class in the `ripple` namespace named `name`, + * and include its header in `src/xrpld/app/tx/detail/applySteps.cpp`. + */ + +/** This transaction type executes a payment. */ +TRANSACTION(ttPAYMENT, 0, Payment, ({ + {sfDestination, soeREQUIRED}, + {sfAmount, soeREQUIRED}, + {sfSendMax, soeOPTIONAL}, + {sfPaths, soeDEFAULT}, + {sfInvoiceID, soeOPTIONAL}, + {sfDestinationTag, soeOPTIONAL}, + {sfDeliverMin, soeOPTIONAL}, +})) + +/** This transaction type creates an escrow object. */ +TRANSACTION(ttESCROW_CREATE, 1, EscrowCreate, ({ + {sfDestination, soeREQUIRED}, + {sfAmount, soeREQUIRED}, + {sfCondition, soeOPTIONAL}, + {sfCancelAfter, soeOPTIONAL}, + {sfFinishAfter, soeOPTIONAL}, + {sfDestinationTag, soeOPTIONAL}, +})) + +/** This transaction type completes an existing escrow. */ +TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish, ({ + {sfOwner, soeREQUIRED}, + {sfOfferSequence, soeREQUIRED}, + {sfFulfillment, soeOPTIONAL}, + {sfCondition, soeOPTIONAL}, +})) + + +/** This transaction type adjusts various account settings. */ +TRANSACTION(ttACCOUNT_SET, 3, AccountSet, ({ + {sfEmailHash, soeOPTIONAL}, + {sfWalletLocator, soeOPTIONAL}, + {sfWalletSize, soeOPTIONAL}, + {sfMessageKey, soeOPTIONAL}, + {sfDomain, soeOPTIONAL}, + {sfTransferRate, soeOPTIONAL}, + {sfSetFlag, soeOPTIONAL}, + {sfClearFlag, soeOPTIONAL}, + {sfTickSize, soeOPTIONAL}, + {sfNFTokenMinter, soeOPTIONAL}, +})) + +/** This transaction type cancels an existing escrow. */ +TRANSACTION(ttESCROW_CANCEL, 4, EscrowCancel, ({ + {sfOwner, soeREQUIRED}, + {sfOfferSequence, soeREQUIRED}, +})) + +/** This transaction type sets or clears an account's "regular key". */ +TRANSACTION(ttREGULAR_KEY_SET, 5, SetRegularKey, ({ + {sfRegularKey, soeOPTIONAL}, +})) + +// 6 deprecated + +/** This transaction type creates an offer to trade one asset for another. */ +TRANSACTION(ttOFFER_CREATE, 7, OfferCreate, ({ + {sfTakerPays, soeREQUIRED}, + {sfTakerGets, soeREQUIRED}, + {sfExpiration, soeOPTIONAL}, + {sfOfferSequence, soeOPTIONAL}, +})) + +/** This transaction type cancels existing offers to trade one asset for another. */ +TRANSACTION(ttOFFER_CANCEL, 8, OfferCancel, ({ + {sfOfferSequence, soeREQUIRED}, +})) + +// 9 deprecated + +/** This transaction type creates a new set of tickets. */ +TRANSACTION(ttTICKET_CREATE, 10, TicketCreate, ({ + {sfTicketCount, soeREQUIRED}, +})) + +// 11 deprecated + +/** This transaction type modifies the signer list associated with an account. */ +// The SignerEntries are optional because a SignerList is deleted by +// setting the SignerQuorum to zero and omitting SignerEntries. +TRANSACTION(ttSIGNER_LIST_SET, 12, SignerListSet, ({ + {sfSignerQuorum, soeREQUIRED}, + {sfSignerEntries, soeOPTIONAL}, +})) + +/** This transaction type creates a new unidirectional XRP payment channel. */ +TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate, ({ + {sfDestination, soeREQUIRED}, + {sfAmount, soeREQUIRED}, + {sfSettleDelay, soeREQUIRED}, + {sfPublicKey, soeREQUIRED}, + {sfCancelAfter, soeOPTIONAL}, + {sfDestinationTag, soeOPTIONAL}, +})) + +/** This transaction type funds an existing unidirectional XRP payment channel. */ +TRANSACTION(ttPAYCHAN_FUND, 14, PaymentChannelFund, ({ + {sfChannel, soeREQUIRED}, + {sfAmount, soeREQUIRED}, + {sfExpiration, soeOPTIONAL}, +})) + +/** This transaction type submits a claim against an existing unidirectional payment channel. */ +TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim, ({ + {sfChannel, soeREQUIRED}, + {sfAmount, soeOPTIONAL}, + {sfBalance, soeOPTIONAL}, + {sfSignature, soeOPTIONAL}, + {sfPublicKey, soeOPTIONAL}, +})) + +/** This transaction type creates a new check. */ +TRANSACTION(ttCHECK_CREATE, 16, CheckCreate, ({ + {sfDestination, soeREQUIRED}, + {sfSendMax, soeREQUIRED}, + {sfExpiration, soeOPTIONAL}, + {sfDestinationTag, soeOPTIONAL}, + {sfInvoiceID, soeOPTIONAL}, +})) + +/** This transaction type cashes an existing check. */ +TRANSACTION(ttCHECK_CASH, 17, CheckCash, ({ + {sfCheckID, soeREQUIRED}, + {sfAmount, soeOPTIONAL}, + {sfDeliverMin, soeOPTIONAL}, +})) + +/** This transaction type cancels an existing check. */ +TRANSACTION(ttCHECK_CANCEL, 18, CheckCancel, ({ + {sfCheckID, soeREQUIRED}, +})) + +/** This transaction type grants or revokes authorization to transfer funds. */ +TRANSACTION(ttDEPOSIT_PREAUTH, 19, DepositPreauth, ({ + {sfAuthorize, soeOPTIONAL}, + {sfUnauthorize, soeOPTIONAL}, +})) + +/** This transaction type modifies a trustline between two accounts. */ +TRANSACTION(ttTRUST_SET, 20, TrustSet, ({ + {sfLimitAmount, soeOPTIONAL}, + {sfQualityIn, soeOPTIONAL}, + {sfQualityOut, soeOPTIONAL}, +})) + +/** This transaction type deletes an existing account. */ +TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete, ({ + {sfDestination, soeREQUIRED}, + {sfDestinationTag, soeOPTIONAL}, +})) + +// 22 reserved + +/** This transaction mints a new NFT. */ +TRANSACTION(ttNFTOKEN_MINT, 25, NFTokenMint, ({ + {sfNFTokenTaxon, soeREQUIRED}, + {sfTransferFee, soeOPTIONAL}, + {sfIssuer, soeOPTIONAL}, + {sfURI, soeOPTIONAL}, + {sfAmount, soeOPTIONAL}, + {sfDestination, soeOPTIONAL}, + {sfExpiration, soeOPTIONAL}, +})) + +/** This transaction burns (i.e. destroys) an existing NFT. */ +TRANSACTION(ttNFTOKEN_BURN, 26, NFTokenBurn, ({ + {sfNFTokenID, soeREQUIRED}, + {sfOwner, soeOPTIONAL}, +})) + +/** This transaction creates a new offer to buy or sell an NFT. */ +TRANSACTION(ttNFTOKEN_CREATE_OFFER, 27, NFTokenCreateOffer, ({ + {sfNFTokenID, soeREQUIRED}, + {sfAmount, soeREQUIRED}, + {sfDestination, soeOPTIONAL}, + {sfOwner, soeOPTIONAL}, + {sfExpiration, soeOPTIONAL}, +})) + +/** This transaction cancels an existing offer to buy or sell an existing NFT. */ +TRANSACTION(ttNFTOKEN_CANCEL_OFFER, 28, NFTokenCancelOffer, ({ + {sfNFTokenOffers, soeREQUIRED}, +})) + +/** This transaction accepts an existing offer to buy or sell an existing NFT. */ +TRANSACTION(ttNFTOKEN_ACCEPT_OFFER, 29, NFTokenAcceptOffer, ({ + {sfNFTokenBuyOffer, soeOPTIONAL}, + {sfNFTokenSellOffer, soeOPTIONAL}, + {sfNFTokenBrokerFee, soeOPTIONAL}, +})) + +/** This transaction claws back issued tokens. */ +TRANSACTION(ttCLAWBACK, 30, Clawback, ({ + {sfAmount, soeREQUIRED}, +})) + +/** This transaction type creates an AMM instance */ +TRANSACTION(ttAMM_CREATE, 35, AMMCreate, ({ + {sfAmount, soeREQUIRED}, + {sfAmount2, soeREQUIRED}, + {sfTradingFee, soeREQUIRED}, +})) + +/** This transaction type deposits into an AMM instance */ +TRANSACTION(ttAMM_DEPOSIT, 36, AMMDeposit, ({ + {sfAsset, soeREQUIRED}, + {sfAsset2, soeREQUIRED}, + {sfAmount, soeOPTIONAL}, + {sfAmount2, soeOPTIONAL}, + {sfEPrice, soeOPTIONAL}, + {sfLPTokenOut, soeOPTIONAL}, + {sfTradingFee, soeOPTIONAL}, +})) + +/** This transaction type withdraws from an AMM instance */ +TRANSACTION(ttAMM_WITHDRAW, 37, AMMWithdraw, ({ + {sfAsset, soeREQUIRED}, + {sfAsset2, soeREQUIRED}, + {sfAmount, soeOPTIONAL}, + {sfAmount2, soeOPTIONAL}, + {sfEPrice, soeOPTIONAL}, + {sfLPTokenIn, soeOPTIONAL}, +})) + +/** This transaction type votes for the trading fee */ +TRANSACTION(ttAMM_VOTE, 38, AMMVote, ({ + {sfAsset, soeREQUIRED}, + {sfAsset2, soeREQUIRED}, + {sfTradingFee, soeREQUIRED}, +})) + +/** This transaction type bids for the auction slot */ +TRANSACTION(ttAMM_BID, 39, AMMBid, ({ + {sfAsset, soeREQUIRED}, + {sfAsset2, soeREQUIRED}, + {sfBidMin, soeOPTIONAL}, + {sfBidMax, soeOPTIONAL}, + {sfAuthAccounts, soeOPTIONAL}, +})) + +/** This transaction type deletes AMM in the empty state */ +TRANSACTION(ttAMM_DELETE, 40, AMMDelete, ({ + {sfAsset, soeREQUIRED}, + {sfAsset2, soeREQUIRED}, +})) + +/** This transactions creates a crosschain sequence number */ +TRANSACTION(ttXCHAIN_CREATE_CLAIM_ID, 41, XChainCreateClaimID, ({ + {sfXChainBridge, soeREQUIRED}, + {sfSignatureReward, soeREQUIRED}, + {sfOtherChainSource, soeREQUIRED}, +})) + +/** This transactions initiates a crosschain transaction */ +TRANSACTION(ttXCHAIN_COMMIT, 42, XChainCommit, ({ + {sfXChainBridge, soeREQUIRED}, + {sfXChainClaimID, soeREQUIRED}, + {sfAmount, soeREQUIRED}, + {sfOtherChainDestination, soeOPTIONAL}, +})) + +/** This transaction completes a crosschain transaction */ +TRANSACTION(ttXCHAIN_CLAIM, 43, XChainClaim, ({ + {sfXChainBridge, soeREQUIRED}, + {sfXChainClaimID, soeREQUIRED}, + {sfDestination, soeREQUIRED}, + {sfDestinationTag, soeOPTIONAL}, + {sfAmount, soeREQUIRED}, +})) + +/** This transaction initiates a crosschain account create transaction */ +TRANSACTION(ttXCHAIN_ACCOUNT_CREATE_COMMIT, 44, XChainAccountCreateCommit, ({ + {sfXChainBridge, soeREQUIRED}, + {sfDestination, soeREQUIRED}, + {sfAmount, soeREQUIRED}, + {sfSignatureReward, soeREQUIRED}, +})) + +/** This transaction adds an attestation to a claim */ +TRANSACTION(ttXCHAIN_ADD_CLAIM_ATTESTATION, 45, XChainAddClaimAttestation, ({ + {sfXChainBridge, soeREQUIRED}, + + {sfAttestationSignerAccount, soeREQUIRED}, + {sfPublicKey, soeREQUIRED}, + {sfSignature, soeREQUIRED}, + {sfOtherChainSource, soeREQUIRED}, + {sfAmount, soeREQUIRED}, + {sfAttestationRewardAccount, soeREQUIRED}, + {sfWasLockingChainSend, soeREQUIRED}, + + {sfXChainClaimID, soeREQUIRED}, + {sfDestination, soeOPTIONAL}, +})) + +/** This transaction adds an attestation to an account */ +TRANSACTION(ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, 46, XChainAddAccountCreateAttestation, ({ + {sfXChainBridge, soeREQUIRED}, + + {sfAttestationSignerAccount, soeREQUIRED}, + {sfPublicKey, soeREQUIRED}, + {sfSignature, soeREQUIRED}, + {sfOtherChainSource, soeREQUIRED}, + {sfAmount, soeREQUIRED}, + {sfAttestationRewardAccount, soeREQUIRED}, + {sfWasLockingChainSend, soeREQUIRED}, + + {sfXChainAccountCreateCount, soeREQUIRED}, + {sfDestination, soeREQUIRED}, + {sfSignatureReward, soeREQUIRED}, +})) + +/** This transaction modifies a sidechain */ +TRANSACTION(ttXCHAIN_MODIFY_BRIDGE, 47, XChainModifyBridge, ({ + {sfXChainBridge, soeREQUIRED}, + {sfSignatureReward, soeOPTIONAL}, + {sfMinAccountCreateAmount, soeOPTIONAL}, +})) + +/** This transactions creates a sidechain */ +TRANSACTION(ttXCHAIN_CREATE_BRIDGE, 48, XChainCreateBridge, ({ + {sfXChainBridge, soeREQUIRED}, + {sfSignatureReward, soeREQUIRED}, + {sfMinAccountCreateAmount, soeOPTIONAL}, +})) + +/** This transaction type creates or updates a DID */ +TRANSACTION(ttDID_SET, 49, DIDSet, ({ + {sfDIDDocument, soeOPTIONAL}, + {sfURI, soeOPTIONAL}, + {sfData, soeOPTIONAL}, +})) + +/** This transaction type deletes a DID */ +TRANSACTION(ttDID_DELETE, 50, DIDDelete, ({})) + +/** This transaction type creates an Oracle instance */ +TRANSACTION(ttORACLE_SET, 51, OracleSet, ({ + {sfOracleDocumentID, soeREQUIRED}, + {sfProvider, soeOPTIONAL}, + {sfURI, soeOPTIONAL}, + {sfAssetClass, soeOPTIONAL}, + {sfLastUpdateTime, soeREQUIRED}, + {sfPriceDataSeries, soeREQUIRED}, +})) + +/** This transaction type deletes an Oracle instance */ +TRANSACTION(ttORACLE_DELETE, 52, OracleDelete, ({ + {sfOracleDocumentID, soeREQUIRED}, +})) + +/** This transaction type fixes a problem in the ledger state */ +TRANSACTION(ttLEDGER_STATE_FIX, 53, LedgerStateFix, ({ + {sfLedgerFixType, soeREQUIRED}, + {sfOwner, soeOPTIONAL}, +})) + +/** This system-generated transaction type is used to update the status of the various amendments. + + For details, see: https://xrpl.org/amendments.html + */ +TRANSACTION(ttAMENDMENT, 100, EnableAmendment, ({ + {sfLedgerSequence, soeREQUIRED}, + {sfAmendment, soeREQUIRED}, +})) + +/** This system-generated transaction type is used to update the network's fee settings. + + For details, see: https://xrpl.org/fee-voting.html + */ +TRANSACTION(ttFEE, 101, SetFee, ({ + {sfLedgerSequence, soeOPTIONAL}, + // Old version uses raw numbers + {sfBaseFee, soeOPTIONAL}, + {sfReferenceFeeUnits, soeOPTIONAL}, + {sfReserveBase, soeOPTIONAL}, + {sfReserveIncrement, soeOPTIONAL}, + // New version uses Amounts + {sfBaseFeeDrops, soeOPTIONAL}, + {sfReserveBaseDrops, soeOPTIONAL}, + {sfReserveIncrementDrops, soeOPTIONAL}, +})) + +/** This system-generated transaction type is used to update the network's negative UNL + + For details, see: https://xrpl.org/negative-unl.html + */ +TRANSACTION(ttUNL_MODIFY, 102, UNLModify, ({ + {sfUNLModifyDisabling, soeREQUIRED}, + {sfLedgerSequence, soeREQUIRED}, + {sfUNLModifyValidator, soeREQUIRED}, +})) diff --git a/include/xrpl/protocol/jss.h b/include/xrpl/protocol/jss.h index e3eda80b44f..1e4e22cd73a 100644 --- a/include/xrpl/protocol/jss.h +++ b/include/xrpl/protocol/jss.h @@ -41,20 +41,13 @@ namespace jss { error: Common properties of RPC error responses. */ +// clang-format off JSS(AL_size); // out: GetCounts JSS(AL_hit_rate); // out: GetCounts JSS(Account); // in: TransactionSign; field. -JSS(AccountDelete); // transaction type. JSS(AccountRoot); // ledger type. -JSS(AccountSet); // transaction type. JSS(AMM); // ledger type -JSS(AMMBid); // transaction type JSS(AMMID); // field -JSS(AMMCreate); // transaction type -JSS(AMMDeposit); // transaction type -JSS(AMMDelete); // transaction type -JSS(AMMVote); // transaction type -JSS(AMMWithdraw); // transaction type JSS(Amendments); // ledger type. JSS(Amount); // in: TransactionSign; field. JSS(Amount2); // in/out: AMM IOU/XRP pool, deposit, withdraw amount @@ -67,25 +60,14 @@ JSS(AuthAccounts); // in: AMM Auction Slot JSS(BaseAsset); // in: Oracle JSS(Bridge); // ledger type. JSS(Check); // ledger type. -JSS(CheckCancel); // transaction type. -JSS(CheckCash); // transaction type. -JSS(CheckCreate); // transaction type. -JSS(Clawback); // transaction type. JSS(ClearFlag); // field. JSS(DID); // ledger type. -JSS(DIDDelete); // transaction type. -JSS(DIDSet); // transaction type. JSS(DeliverMax); // out: alias to Amount JSS(DeliverMin); // in: TransactionSign -JSS(DepositPreauth); // transaction and ledger type. JSS(Destination); // in: TransactionSign; field. JSS(DirectoryNode); // ledger type. -JSS(EnableAmendment); // transaction type. JSS(EPrice); // in: AMM Deposit option JSS(Escrow); // ledger type. -JSS(EscrowCancel); // transaction type. -JSS(EscrowCreate); // transaction type. -JSS(EscrowFinish); // transaction type. JSS(Fee); // in/out: TransactionSign; field. JSS(FeeSettings); // ledger type. JSS(Flags); // in/out: TransactionSign; field. @@ -97,68 +79,40 @@ JSS(LimitAmount); // field. JSS(BidMax); // in: AMM Bid JSS(BidMin); // in: AMM Bid JSS(NetworkID); // field. -JSS(NFTokenBurn); // transaction type. -JSS(NFTokenMint); // transaction type. JSS(NFTokenOffer); // ledger type. -JSS(NFTokenAcceptOffer); // transaction type. -JSS(NFTokenCancelOffer); // transaction type. -JSS(NFTokenCreateOffer); // transaction type. JSS(NFTokenPage); // ledger type. -JSS(LedgerStateFix); // transaction type. JSS(LPTokenOut); // in: AMM Liquidity Provider deposit tokens JSS(LPTokenIn); // in: AMM Liquidity Provider withdraw tokens JSS(LPToken); // out: AMM Liquidity Provider tokens info JSS(Offer); // ledger type. -JSS(OfferCancel); // transaction type. -JSS(OfferCreate); // transaction type. JSS(OfferSequence); // field. JSS(Oracle); // ledger type. -JSS(OracleDelete); // transaction type. JSS(OracleDocumentID); // field -JSS(OracleSet); // transaction type. JSS(Owner); // field JSS(Paths); // in/out: TransactionSign JSS(PayChannel); // ledger type. -JSS(Payment); // transaction type. -JSS(PaymentChannelClaim); // transaction type. -JSS(PaymentChannelCreate); // transaction type. -JSS(PaymentChannelFund); // transaction type. JSS(PriceDataSeries); // field. JSS(PriceData); // field. JSS(Provider); // field. JSS(QuoteAsset); // in: Oracle. JSS(RippleState); // ledger type. JSS(SLE_hit_rate); // out: GetCounts. -JSS(SetFee); // transaction type. -JSS(UNLModify); // transaction type. JSS(Scale); // field. JSS(SettleDelay); // in: TransactionSign JSS(SendMax); // in: TransactionSign JSS(Sequence); // in/out: TransactionSign; field. JSS(SetFlag); // field. -JSS(SetRegularKey); // transaction type. JSS(SignerList); // ledger type. -JSS(SignerListSet); // transaction type. JSS(SigningPubKey); // field. JSS(TakerGets); // field. JSS(TakerPays); // field. JSS(Ticket); // ledger type. -JSS(TicketCreate); // transaction type. JSS(TxnSignature); // field. JSS(TradingFee); // in/out: AMM trading fee JSS(TransactionType); // in: TransactionSign. JSS(TransferRate); // in: TransferRate. -JSS(TrustSet); // transaction type. JSS(URI); // field. JSS(VoteSlots); // out: AMM Vote -JSS(XChainAddAccountCreateAttestation); // transaction type. -JSS(XChainAddClaimAttestation); // transaction type. -JSS(XChainAccountCreateCommit); // transaction type. -JSS(XChainClaim); // transaction type. -JSS(XChainCommit); // transaction type. -JSS(XChainCreateBridge); // transaction type. -JSS(XChainCreateClaimID); // transaction type. -JSS(XChainModifyBridge); // transaction type. JSS(XChainOwnedClaimID); // ledger type. JSS(XChainOwnedCreateAccountClaimID); // ledger type. JSS(aborted); // out: InboundLedger @@ -764,6 +718,18 @@ JSS(write_load); // out: GetCounts JSS(xchain_owned_claim_id); // in: LedgerEntry, AccountObjects JSS(xchain_owned_create_account_claim_id); // in: LedgerEntry JSS(NegativeUNL); // out: ValidatorList; ledger type +// clang-format on + +#pragma push_macro("TRANSACTION") +#undef TRANSACTION + +#define TRANSACTION(tag, value, name, fields) JSS(name); + +#include + +#undef TRANSACTION +#pragma pop_macro("TRANSACTION") + #undef JSS } // namespace jss diff --git a/src/libxrpl/protocol/Feature.cpp b/src/libxrpl/protocol/Feature.cpp index 078369bf20c..3f6e760577a 100644 --- a/src/libxrpl/protocol/Feature.cpp +++ b/src/libxrpl/protocol/Feature.cpp @@ -409,114 +409,27 @@ featureToName(uint256 const& f) return featureCollections.featureToName(f); } -#pragma push_macro("REGISTER_FEATURE") -#undef REGISTER_FEATURE +// All known amendments must be registered either here or below with the +// "retired" amendments -/** -Takes the name of a feature, whether it's supported, and the default vote. Will -register the feature, and create a variable whose name is "feature" plus the -feature name. -*/ -#define REGISTER_FEATURE(fName, supported, votebehavior) \ - uint256 const feature##fName = \ - registerFeature(#fName, supported, votebehavior) +#pragma push_macro("XRPL_FEATURE") +#undef XRPL_FEATURE +#pragma push_macro("XRPL_FIX") +#undef XRPL_FIX -#pragma push_macro("REGISTER_FIX") -#undef REGISTER_FIX +#define XRPL_FEATURE(name, supported, vote) \ + uint256 const feature##name = registerFeature(#name, supported, vote); +#define XRPL_FIX(name, supported, vote) \ + uint256 const fix##name = registerFeature("fix" #name, supported, vote); -/** -Takes the name of a feature, whether it's supported, and the default vote. Will -register the feature, and create a variable whose name is the unmodified feature -name. -*/ -#define REGISTER_FIX(fName, supported, votebehavior) \ - uint256 const fName = registerFeature(#fName, supported, votebehavior) +#include -// clang-format off +#undef XRPL_FIX +#pragma pop_macro("XRPL_FIX") +#undef XRPL_FEATURE +#pragma pop_macro("XRPL_FEATURE") -// All known amendments must be registered either here or below with the -// "retired" amendments -REGISTER_FEATURE(OwnerPaysFee, Supported::no, VoteBehavior::DefaultNo); -REGISTER_FEATURE(Flow, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FEATURE(FlowCross, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FIX (fix1513, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FEATURE(DepositAuth, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FEATURE(Checks, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FIX (fix1571, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FIX (fix1543, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FIX (fix1623, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FEATURE(DepositPreauth, Supported::yes, VoteBehavior::DefaultYes); -// Use liquidity from strands that consume max offers, but mark as dry -REGISTER_FIX (fix1515, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FIX (fix1578, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FEATURE(MultiSignReserve, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FIX (fixTakerDryOfferRemoval, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FIX (fixMasterKeyAsRegularKey, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FIX (fixCheckThreading, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FIX (fixPayChanRecipientOwnerDir, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FEATURE(DeletableAccounts, Supported::yes, VoteBehavior::DefaultYes); -// fixQualityUpperBound should be activated before FlowCross -REGISTER_FIX (fixQualityUpperBound, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FEATURE(RequireFullyCanonicalSig, Supported::yes, VoteBehavior::DefaultYes); -// fix1781: XRPEndpointSteps should be included in the circular payment check -REGISTER_FIX (fix1781, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FEATURE(HardenedValidations, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FIX (fixAmendmentMajorityCalc, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FEATURE(NegativeUNL, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FEATURE(TicketBatch, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FEATURE(FlowSortStrands, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FIX (fixSTAmountCanonicalize, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FIX (fixRmSmallIncreasedQOffers, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FEATURE(CheckCashMakesTrustLine, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FEATURE(ExpandedSignerList, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FEATURE(NonFungibleTokensV1_1, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX (fixTrustLinesToSelf, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX (fixRemoveNFTokenAutoTrustLine, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FEATURE(ImmediateOfferKilled, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FEATURE(DisallowIncoming, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FEATURE(XRPFees, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX (fixUniversalNumber, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX (fixNonFungibleTokensV1_2, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX (fixNFTokenRemint, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX (fixReducedOffersV1, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FEATURE(Clawback, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FEATURE(AMM, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FEATURE(XChainBridge, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX (fixDisallowIncomingV1, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FEATURE(DID, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX (fixFillOrKill, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX (fixNFTokenReserve, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX (fixInnerObjTemplate, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX (fixAMMOverflowOffer, Supported::yes, VoteBehavior::DefaultYes); -REGISTER_FEATURE(PriceOracle, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX (fixEmptyDID, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX (fixXChainRewardRounding, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX (fixPreviousTxnID, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX (fixAMMv1_1, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FEATURE(NFTokenMintOffer, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX (fixReducedOffersV2, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX (fixEnforceNFTokenTrustline, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX (fixInnerObjTemplate2, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FIX (fixNFTokenPageLinks, Supported::yes, VoteBehavior::DefaultNo); -// InvariantsV1_1 will be changes to Supported::yes when all the -// invariants expected to be included under it are complete. -REGISTER_FEATURE(InvariantsV1_1, Supported::no, VoteBehavior::DefaultNo); - -// The following amendments are obsolete, but must remain supported -// because they could potentially get enabled. -// -// Obsolete features are (usually) not in the ledger, and may have code -// controlled by the feature. They need to be supported because at some -// time in the past, the feature was supported and votable, but never -// passed. So the feature needs to be supported in case it is ever -// enabled (added to the ledger). -// -// If a feature remains obsolete for long enough that no clients are able -// to vote for it, the feature can be removed (entirely?) from the code. -REGISTER_FEATURE(CryptoConditionsSuite, Supported::yes, VoteBehavior::Obsolete); -REGISTER_FEATURE(NonFungibleTokensV1, Supported::yes, VoteBehavior::Obsolete); -REGISTER_FIX (fixNFTokenDirV1, Supported::yes, VoteBehavior::Obsolete); -REGISTER_FIX (fixNFTokenNegOffer, Supported::yes, VoteBehavior::Obsolete); +// clang-format off // The following amendments have been active for at least two years. Their // pre-amendment code has been removed and the identifiers are deprecated. @@ -542,12 +455,6 @@ uint256 const // clang-format on -#undef REGISTER_FIX -#pragma pop_macro("REGISTER_FIX") - -#undef REGISTER_FEATURE -#pragma pop_macro("REGISTER_FEATURE") - // All of the features should now be registered, since variables in a cpp file // are initialized from top to bottom. // diff --git a/src/libxrpl/protocol/LedgerFormats.cpp b/src/libxrpl/protocol/LedgerFormats.cpp index 9401c00278b..d66b085e0d0 100644 --- a/src/libxrpl/protocol/LedgerFormats.cpp +++ b/src/libxrpl/protocol/LedgerFormats.cpp @@ -25,347 +25,28 @@ namespace ripple { LedgerFormats::LedgerFormats() { - // clang-format off // Fields shared by all ledger formats: static const std::initializer_list commonFields{ - {sfLedgerIndex, soeOPTIONAL}, - {sfLedgerEntryType, soeREQUIRED}, - {sfFlags, soeREQUIRED}, + {sfLedgerIndex, soeOPTIONAL}, + {sfLedgerEntryType, soeREQUIRED}, + {sfFlags, soeREQUIRED}, }; - add(jss::AccountRoot, - ltACCOUNT_ROOT, - { - {sfAccount, soeREQUIRED}, - {sfSequence, soeREQUIRED}, - {sfBalance, soeREQUIRED}, - {sfOwnerCount, soeREQUIRED}, - {sfPreviousTxnID, soeREQUIRED}, - {sfPreviousTxnLgrSeq, soeREQUIRED}, - {sfAccountTxnID, soeOPTIONAL}, - {sfRegularKey, soeOPTIONAL}, - {sfEmailHash, soeOPTIONAL}, - {sfWalletLocator, soeOPTIONAL}, - {sfWalletSize, soeOPTIONAL}, - {sfMessageKey, soeOPTIONAL}, - {sfTransferRate, soeOPTIONAL}, - {sfDomain, soeOPTIONAL}, - {sfTickSize, soeOPTIONAL}, - {sfTicketCount, soeOPTIONAL}, - {sfNFTokenMinter, soeOPTIONAL}, - {sfMintedNFTokens, soeDEFAULT}, - {sfBurnedNFTokens, soeDEFAULT}, - {sfFirstNFTokenSequence, soeOPTIONAL}, - {sfAMMID, soeOPTIONAL}, - }, - commonFields); +#pragma push_macro("UNWRAP") +#undef UNWRAP +#pragma push_macro("LEDGER_ENTRY") +#undef LEDGER_ENTRY - add(jss::DirectoryNode, - ltDIR_NODE, - { - {sfOwner, soeOPTIONAL}, // for owner directories - {sfTakerPaysCurrency, soeOPTIONAL}, // order book directories - {sfTakerPaysIssuer, soeOPTIONAL}, // order book directories - {sfTakerGetsCurrency, soeOPTIONAL}, // order book directories - {sfTakerGetsIssuer, soeOPTIONAL}, // order book directories - {sfExchangeRate, soeOPTIONAL}, // order book directories - {sfIndexes, soeREQUIRED}, - {sfRootIndex, soeREQUIRED}, - {sfIndexNext, soeOPTIONAL}, - {sfIndexPrevious, soeOPTIONAL}, - {sfNFTokenID, soeOPTIONAL}, - {sfPreviousTxnID, soeOPTIONAL}, - {sfPreviousTxnLgrSeq, soeOPTIONAL}, - }, - commonFields); +#define UNWRAP(...) __VA_ARGS__ +#define LEDGER_ENTRY(tag, value, name, fields) \ + add(jss::name, tag, UNWRAP fields, commonFields); - add(jss::Offer, - ltOFFER, - { - {sfAccount, soeREQUIRED}, - {sfSequence, soeREQUIRED}, - {sfTakerPays, soeREQUIRED}, - {sfTakerGets, soeREQUIRED}, - {sfBookDirectory, soeREQUIRED}, - {sfBookNode, soeREQUIRED}, - {sfOwnerNode, soeREQUIRED}, - {sfPreviousTxnID, soeREQUIRED}, - {sfPreviousTxnLgrSeq, soeREQUIRED}, - {sfExpiration, soeOPTIONAL}, - }, - commonFields); +#include - add(jss::RippleState, - ltRIPPLE_STATE, - { - {sfBalance, soeREQUIRED}, - {sfLowLimit, soeREQUIRED}, - {sfHighLimit, soeREQUIRED}, - {sfPreviousTxnID, soeREQUIRED}, - {sfPreviousTxnLgrSeq, soeREQUIRED}, - {sfLowNode, soeOPTIONAL}, - {sfLowQualityIn, soeOPTIONAL}, - {sfLowQualityOut, soeOPTIONAL}, - {sfHighNode, soeOPTIONAL}, - {sfHighQualityIn, soeOPTIONAL}, - {sfHighQualityOut, soeOPTIONAL}, - }, - commonFields); - - add(jss::Escrow, - ltESCROW, - { - {sfAccount, soeREQUIRED}, - {sfDestination, soeREQUIRED}, - {sfAmount, soeREQUIRED}, - {sfCondition, soeOPTIONAL}, - {sfCancelAfter, soeOPTIONAL}, - {sfFinishAfter, soeOPTIONAL}, - {sfSourceTag, soeOPTIONAL}, - {sfDestinationTag, soeOPTIONAL}, - {sfOwnerNode, soeREQUIRED}, - {sfPreviousTxnID, soeREQUIRED}, - {sfPreviousTxnLgrSeq, soeREQUIRED}, - {sfDestinationNode, soeOPTIONAL}, - }, - commonFields); - - add(jss::LedgerHashes, - ltLEDGER_HASHES, - { - {sfFirstLedgerSequence, soeOPTIONAL}, - {sfLastLedgerSequence, soeOPTIONAL}, - {sfHashes, soeREQUIRED}, - }, - commonFields); - - add(jss::Amendments, - ltAMENDMENTS, - { - {sfAmendments, soeOPTIONAL}, // Enabled - {sfMajorities, soeOPTIONAL}, - {sfPreviousTxnID, soeOPTIONAL}, - {sfPreviousTxnLgrSeq, soeOPTIONAL}, - }, - commonFields); - - add(jss::FeeSettings, - ltFEE_SETTINGS, - { - // Old version uses raw numbers - {sfBaseFee, soeOPTIONAL}, - {sfReferenceFeeUnits, soeOPTIONAL}, - {sfReserveBase, soeOPTIONAL}, - {sfReserveIncrement, soeOPTIONAL}, - // New version uses Amounts - {sfBaseFeeDrops, soeOPTIONAL}, - {sfReserveBaseDrops, soeOPTIONAL}, - {sfReserveIncrementDrops, soeOPTIONAL}, - {sfPreviousTxnID, soeOPTIONAL}, - {sfPreviousTxnLgrSeq, soeOPTIONAL}, - }, - commonFields); - - add(jss::Ticket, - ltTICKET, - { - {sfAccount, soeREQUIRED}, - {sfOwnerNode, soeREQUIRED}, - {sfTicketSequence, soeREQUIRED}, - {sfPreviousTxnID, soeREQUIRED}, - {sfPreviousTxnLgrSeq, soeREQUIRED}, - }, - commonFields); - - // All fields are soeREQUIRED because there is always a - // SignerEntries. If there are no SignerEntries the node is deleted. - add(jss::SignerList, - ltSIGNER_LIST, - { - {sfOwnerNode, soeREQUIRED}, - {sfSignerQuorum, soeREQUIRED}, - {sfSignerEntries, soeREQUIRED}, - {sfSignerListID, soeREQUIRED}, - {sfPreviousTxnID, soeREQUIRED}, - {sfPreviousTxnLgrSeq, soeREQUIRED}, - }, - commonFields); - - add(jss::PayChannel, - ltPAYCHAN, - { - {sfAccount, soeREQUIRED}, - {sfDestination, soeREQUIRED}, - {sfAmount, soeREQUIRED}, - {sfBalance, soeREQUIRED}, - {sfPublicKey, soeREQUIRED}, - {sfSettleDelay, soeREQUIRED}, - {sfExpiration, soeOPTIONAL}, - {sfCancelAfter, soeOPTIONAL}, - {sfSourceTag, soeOPTIONAL}, - {sfDestinationTag, soeOPTIONAL}, - {sfOwnerNode, soeREQUIRED}, - {sfPreviousTxnID, soeREQUIRED}, - {sfPreviousTxnLgrSeq, soeREQUIRED}, - {sfDestinationNode, soeOPTIONAL}, - }, - commonFields); - - add(jss::Check, - ltCHECK, - { - {sfAccount, soeREQUIRED}, - {sfDestination, soeREQUIRED}, - {sfSendMax, soeREQUIRED}, - {sfSequence, soeREQUIRED}, - {sfOwnerNode, soeREQUIRED}, - {sfDestinationNode, soeREQUIRED}, - {sfExpiration, soeOPTIONAL}, - {sfInvoiceID, soeOPTIONAL}, - {sfSourceTag, soeOPTIONAL}, - {sfDestinationTag, soeOPTIONAL}, - {sfPreviousTxnID, soeREQUIRED}, - {sfPreviousTxnLgrSeq, soeREQUIRED}, - }, - commonFields); - - add(jss::DepositPreauth, - ltDEPOSIT_PREAUTH, - { - {sfAccount, soeREQUIRED}, - {sfAuthorize, soeREQUIRED}, - {sfOwnerNode, soeREQUIRED}, - {sfPreviousTxnID, soeREQUIRED}, - {sfPreviousTxnLgrSeq, soeREQUIRED}, - }, - commonFields); - - add(jss::NegativeUNL, - ltNEGATIVE_UNL, - { - {sfDisabledValidators, soeOPTIONAL}, - {sfValidatorToDisable, soeOPTIONAL}, - {sfValidatorToReEnable, soeOPTIONAL}, - {sfPreviousTxnID, soeOPTIONAL}, - {sfPreviousTxnLgrSeq, soeOPTIONAL}, - }, - commonFields); - - add(jss::NFTokenPage, - ltNFTOKEN_PAGE, - { - {sfPreviousPageMin, soeOPTIONAL}, - {sfNextPageMin, soeOPTIONAL}, - {sfNFTokens, soeREQUIRED}, - {sfPreviousTxnID, soeREQUIRED}, - {sfPreviousTxnLgrSeq, soeREQUIRED} - }, - commonFields); - - add(jss::NFTokenOffer, - ltNFTOKEN_OFFER, - { - {sfOwner, soeREQUIRED}, - {sfNFTokenID, soeREQUIRED}, - {sfAmount, soeREQUIRED}, - {sfOwnerNode, soeREQUIRED}, - {sfNFTokenOfferNode, soeREQUIRED}, - {sfDestination, soeOPTIONAL}, - {sfExpiration, soeOPTIONAL}, - {sfPreviousTxnID, soeREQUIRED}, - {sfPreviousTxnLgrSeq, soeREQUIRED} - }, - commonFields); - - add(jss::AMM, - ltAMM, - { - {sfAccount, soeREQUIRED}, - {sfTradingFee, soeDEFAULT}, - {sfVoteSlots, soeOPTIONAL}, - {sfAuctionSlot, soeOPTIONAL}, - {sfLPTokenBalance, soeREQUIRED}, - {sfAsset, soeREQUIRED}, - {sfAsset2, soeREQUIRED}, - {sfOwnerNode, soeREQUIRED}, - {sfPreviousTxnID, soeOPTIONAL}, - {sfPreviousTxnLgrSeq, soeOPTIONAL}, - }, - commonFields); - - add(jss::Bridge, - ltBRIDGE, - { - {sfAccount, soeREQUIRED}, - {sfSignatureReward, soeREQUIRED}, - {sfMinAccountCreateAmount, soeOPTIONAL}, - {sfXChainBridge, soeREQUIRED}, - {sfXChainClaimID, soeREQUIRED}, - {sfXChainAccountCreateCount, soeREQUIRED}, - {sfXChainAccountClaimCount, soeREQUIRED}, - {sfOwnerNode, soeREQUIRED}, - {sfPreviousTxnID, soeREQUIRED}, - {sfPreviousTxnLgrSeq, soeREQUIRED} - }, - commonFields); - - add(jss::XChainOwnedClaimID, - ltXCHAIN_OWNED_CLAIM_ID, - { - {sfAccount, soeREQUIRED}, - {sfXChainBridge, soeREQUIRED}, - {sfXChainClaimID, soeREQUIRED}, - {sfOtherChainSource, soeREQUIRED}, - {sfXChainClaimAttestations, soeREQUIRED}, - {sfSignatureReward, soeREQUIRED}, - {sfOwnerNode, soeREQUIRED}, - {sfPreviousTxnID, soeREQUIRED}, - {sfPreviousTxnLgrSeq, soeREQUIRED} - }, - commonFields); - - add(jss::XChainOwnedCreateAccountClaimID, - ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID, - { - {sfAccount, soeREQUIRED}, - {sfXChainBridge, soeREQUIRED}, - {sfXChainAccountCreateCount, soeREQUIRED}, - {sfXChainCreateAccountAttestations, soeREQUIRED}, - {sfOwnerNode, soeREQUIRED}, - {sfPreviousTxnID, soeREQUIRED}, - {sfPreviousTxnLgrSeq, soeREQUIRED} - }, - commonFields); - - add(jss::DID, - ltDID, - { - {sfAccount, soeREQUIRED}, - {sfDIDDocument, soeOPTIONAL}, - {sfURI, soeOPTIONAL}, - {sfData, soeOPTIONAL}, - {sfOwnerNode, soeREQUIRED}, - {sfPreviousTxnID, soeREQUIRED}, - {sfPreviousTxnLgrSeq, soeREQUIRED} - }, - commonFields); - - add(jss::Oracle, - ltORACLE, - { - {sfOwner, soeREQUIRED}, - {sfProvider, soeREQUIRED}, - {sfPriceDataSeries, soeREQUIRED}, - {sfAssetClass, soeREQUIRED}, - {sfLastUpdateTime, soeREQUIRED}, - {sfURI, soeOPTIONAL}, - {sfOwnerNode, soeREQUIRED}, - {sfPreviousTxnID, soeREQUIRED}, - {sfPreviousTxnLgrSeq, soeREQUIRED} - }, - commonFields); - - // clang-format on +#undef LEDGER_ENTRY +#pragma pop_macro("LEDGER_ENTRY") +#undef UNWRAP +#pragma pop_macro("UNWRAP") } LedgerFormats const& diff --git a/src/libxrpl/protocol/SField.cpp b/src/libxrpl/protocol/SField.cpp index f8eb2d6f877..18226008504 100644 --- a/src/libxrpl/protocol/SField.cpp +++ b/src/libxrpl/protocol/SField.cpp @@ -49,386 +49,37 @@ TypedField::TypedField(private_access_tag_t pat, Args&&... args) // database: // Use macros for most SField construction to enforce naming conventions. -#pragma push_macro("CONSTRUCT_UNTYPED_SFIELD") -#undef CONSTRUCT_UNTYPED_SFIELD - -// It would be possible to design the macros so that sfName and txtName would -// be constructed from a single macro parameter. We chose not to take that -// path because then you cannot grep for the exact SField name and find -// where it is constructed. These macros allow that grep to succeed. -#define CONSTRUCT_UNTYPED_SFIELD(sfName, txtName, stiSuffix, fieldValue, ...) \ - SField const sfName( \ - access, STI_##stiSuffix, fieldValue, txtName, ##__VA_ARGS__); \ - static_assert( \ - std::string_view(#sfName) == "sf" txtName, \ - "Declaration of SField does not match its text name") - -#pragma push_macro("CONSTRUCT_TYPED_SFIELD") -#undef CONSTRUCT_TYPED_SFIELD - -#define CONSTRUCT_TYPED_SFIELD(sfName, txtName, stiSuffix, fieldValue, ...) \ - SF_##stiSuffix const sfName( \ - access, STI_##stiSuffix, fieldValue, txtName, ##__VA_ARGS__); \ - static_assert( \ - std::string_view(#sfName) == "sf" txtName, \ - "Declaration of SField does not match its text name") - -// clang-format off +#pragma push_macro("UNTYPED_SFIELD") +#undef UNTYPED_SFIELD +#pragma push_macro("TYPED_SFIELD") +#undef TYPED_SFIELD + +#define UNTYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) \ + SField const sfName( \ + access, \ + STI_##stiSuffix, \ + fieldValue, \ + std::string_view(#sfName).substr(2).data(), \ + ##__VA_ARGS__); +#define TYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) \ + SF_##stiSuffix const sfName( \ + access, \ + STI_##stiSuffix, \ + fieldValue, \ + std::string_view(#sfName).substr(2).data(), \ + ##__VA_ARGS__); // SFields which, for historical reasons, do not follow naming conventions. SField const sfInvalid(access, -1); SField const sfGeneric(access, 0); SField const sfHash(access, STI_UINT256, 257, "hash"); -SField const sfIndex(access, STI_UINT256, 258, "index"); - -// Untyped SFields -CONSTRUCT_UNTYPED_SFIELD(sfLedgerEntry, "LedgerEntry", LEDGERENTRY, 257); -CONSTRUCT_UNTYPED_SFIELD(sfTransaction, "Transaction", TRANSACTION, 257); -CONSTRUCT_UNTYPED_SFIELD(sfValidation, "Validation", VALIDATION, 257); -CONSTRUCT_UNTYPED_SFIELD(sfMetadata, "Metadata", METADATA, 257); - -// 8-bit integers -CONSTRUCT_TYPED_SFIELD(sfCloseResolution, "CloseResolution", UINT8, 1); -CONSTRUCT_TYPED_SFIELD(sfMethod, "Method", UINT8, 2); -CONSTRUCT_TYPED_SFIELD(sfTransactionResult, "TransactionResult", UINT8, 3); -CONSTRUCT_TYPED_SFIELD(sfScale, "Scale", UINT8, 4); - -// 8-bit integers (uncommon) -CONSTRUCT_TYPED_SFIELD(sfTickSize, "TickSize", UINT8, 16); -CONSTRUCT_TYPED_SFIELD(sfUNLModifyDisabling, "UNLModifyDisabling", UINT8, 17); -CONSTRUCT_TYPED_SFIELD(sfHookResult, "HookResult", UINT8, 18); -CONSTRUCT_TYPED_SFIELD(sfWasLockingChainSend, "WasLockingChainSend", UINT8, 19); - -// 16-bit integers -CONSTRUCT_TYPED_SFIELD(sfLedgerEntryType, "LedgerEntryType", UINT16, 1, SField::sMD_Never); -CONSTRUCT_TYPED_SFIELD(sfTransactionType, "TransactionType", UINT16, 2); -CONSTRUCT_TYPED_SFIELD(sfSignerWeight, "SignerWeight", UINT16, 3); -CONSTRUCT_TYPED_SFIELD(sfTransferFee, "TransferFee", UINT16, 4); -CONSTRUCT_TYPED_SFIELD(sfTradingFee, "TradingFee", UINT16, 5); -CONSTRUCT_TYPED_SFIELD(sfDiscountedFee, "DiscountedFee", UINT16, 6); - -// 16-bit integers (uncommon) -CONSTRUCT_TYPED_SFIELD(sfVersion, "Version", UINT16, 16); -CONSTRUCT_TYPED_SFIELD(sfHookStateChangeCount, "HookStateChangeCount", UINT16, 17); -CONSTRUCT_TYPED_SFIELD(sfHookEmitCount, "HookEmitCount", UINT16, 18); -CONSTRUCT_TYPED_SFIELD(sfHookExecutionIndex, "HookExecutionIndex", UINT16, 19); -CONSTRUCT_TYPED_SFIELD(sfHookApiVersion, "HookApiVersion", UINT16, 20); -CONSTRUCT_TYPED_SFIELD(sfLedgerFixType, "LedgerFixType", UINT16, 21); - -// 32-bit integers (common) -CONSTRUCT_TYPED_SFIELD(sfNetworkID, "NetworkID", UINT32, 1); -CONSTRUCT_TYPED_SFIELD(sfFlags, "Flags", UINT32, 2); -CONSTRUCT_TYPED_SFIELD(sfSourceTag, "SourceTag", UINT32, 3); -CONSTRUCT_TYPED_SFIELD(sfSequence, "Sequence", UINT32, 4); -CONSTRUCT_TYPED_SFIELD(sfPreviousTxnLgrSeq, "PreviousTxnLgrSeq", UINT32, 5, SField::sMD_DeleteFinal); -CONSTRUCT_TYPED_SFIELD(sfLedgerSequence, "LedgerSequence", UINT32, 6); -CONSTRUCT_TYPED_SFIELD(sfCloseTime, "CloseTime", UINT32, 7); -CONSTRUCT_TYPED_SFIELD(sfParentCloseTime, "ParentCloseTime", UINT32, 8); -CONSTRUCT_TYPED_SFIELD(sfSigningTime, "SigningTime", UINT32, 9); -CONSTRUCT_TYPED_SFIELD(sfExpiration, "Expiration", UINT32, 10); -CONSTRUCT_TYPED_SFIELD(sfTransferRate, "TransferRate", UINT32, 11); -CONSTRUCT_TYPED_SFIELD(sfWalletSize, "WalletSize", UINT32, 12); -CONSTRUCT_TYPED_SFIELD(sfOwnerCount, "OwnerCount", UINT32, 13); -CONSTRUCT_TYPED_SFIELD(sfDestinationTag, "DestinationTag", UINT32, 14); -CONSTRUCT_TYPED_SFIELD(sfLastUpdateTime, "LastUpdateTime", UINT32, 15); - -// 32-bit integers (uncommon) -CONSTRUCT_TYPED_SFIELD(sfHighQualityIn, "HighQualityIn", UINT32, 16); -CONSTRUCT_TYPED_SFIELD(sfHighQualityOut, "HighQualityOut", UINT32, 17); -CONSTRUCT_TYPED_SFIELD(sfLowQualityIn, "LowQualityIn", UINT32, 18); -CONSTRUCT_TYPED_SFIELD(sfLowQualityOut, "LowQualityOut", UINT32, 19); -CONSTRUCT_TYPED_SFIELD(sfQualityIn, "QualityIn", UINT32, 20); -CONSTRUCT_TYPED_SFIELD(sfQualityOut, "QualityOut", UINT32, 21); -CONSTRUCT_TYPED_SFIELD(sfStampEscrow, "StampEscrow", UINT32, 22); -CONSTRUCT_TYPED_SFIELD(sfBondAmount, "BondAmount", UINT32, 23); -CONSTRUCT_TYPED_SFIELD(sfLoadFee, "LoadFee", UINT32, 24); -CONSTRUCT_TYPED_SFIELD(sfOfferSequence, "OfferSequence", UINT32, 25); -CONSTRUCT_TYPED_SFIELD(sfFirstLedgerSequence, "FirstLedgerSequence", UINT32, 26); -CONSTRUCT_TYPED_SFIELD(sfLastLedgerSequence, "LastLedgerSequence", UINT32, 27); -CONSTRUCT_TYPED_SFIELD(sfTransactionIndex, "TransactionIndex", UINT32, 28); -CONSTRUCT_TYPED_SFIELD(sfOperationLimit, "OperationLimit", UINT32, 29); -CONSTRUCT_TYPED_SFIELD(sfReferenceFeeUnits, "ReferenceFeeUnits", UINT32, 30); -CONSTRUCT_TYPED_SFIELD(sfReserveBase, "ReserveBase", UINT32, 31); -CONSTRUCT_TYPED_SFIELD(sfReserveIncrement, "ReserveIncrement", UINT32, 32); -CONSTRUCT_TYPED_SFIELD(sfSetFlag, "SetFlag", UINT32, 33); -CONSTRUCT_TYPED_SFIELD(sfClearFlag, "ClearFlag", UINT32, 34); -CONSTRUCT_TYPED_SFIELD(sfSignerQuorum, "SignerQuorum", UINT32, 35); -CONSTRUCT_TYPED_SFIELD(sfCancelAfter, "CancelAfter", UINT32, 36); -CONSTRUCT_TYPED_SFIELD(sfFinishAfter, "FinishAfter", UINT32, 37); -CONSTRUCT_TYPED_SFIELD(sfSignerListID, "SignerListID", UINT32, 38); -CONSTRUCT_TYPED_SFIELD(sfSettleDelay, "SettleDelay", UINT32, 39); -CONSTRUCT_TYPED_SFIELD(sfTicketCount, "TicketCount", UINT32, 40); -CONSTRUCT_TYPED_SFIELD(sfTicketSequence, "TicketSequence", UINT32, 41); -CONSTRUCT_TYPED_SFIELD(sfNFTokenTaxon, "NFTokenTaxon", UINT32, 42); -CONSTRUCT_TYPED_SFIELD(sfMintedNFTokens, "MintedNFTokens", UINT32, 43); -CONSTRUCT_TYPED_SFIELD(sfBurnedNFTokens, "BurnedNFTokens", UINT32, 44); -CONSTRUCT_TYPED_SFIELD(sfHookStateCount, "HookStateCount", UINT32, 45); -CONSTRUCT_TYPED_SFIELD(sfEmitGeneration, "EmitGeneration", UINT32, 46); -// 47 is reserved for LockCount(Hooks) -CONSTRUCT_TYPED_SFIELD(sfVoteWeight, "VoteWeight", UINT32, 48); -CONSTRUCT_TYPED_SFIELD(sfFirstNFTokenSequence, "FirstNFTokenSequence", UINT32, 50); -CONSTRUCT_TYPED_SFIELD(sfOracleDocumentID, "OracleDocumentID", UINT32, 51); - -// 64-bit integers (common) -CONSTRUCT_TYPED_SFIELD(sfIndexNext, "IndexNext", UINT64, 1); -CONSTRUCT_TYPED_SFIELD(sfIndexPrevious, "IndexPrevious", UINT64, 2); -CONSTRUCT_TYPED_SFIELD(sfBookNode, "BookNode", UINT64, 3); -CONSTRUCT_TYPED_SFIELD(sfOwnerNode, "OwnerNode", UINT64, 4); -CONSTRUCT_TYPED_SFIELD(sfBaseFee, "BaseFee", UINT64, 5); -CONSTRUCT_TYPED_SFIELD(sfExchangeRate, "ExchangeRate", UINT64, 6); -CONSTRUCT_TYPED_SFIELD(sfLowNode, "LowNode", UINT64, 7); -CONSTRUCT_TYPED_SFIELD(sfHighNode, "HighNode", UINT64, 8); -CONSTRUCT_TYPED_SFIELD(sfDestinationNode, "DestinationNode", UINT64, 9); -CONSTRUCT_TYPED_SFIELD(sfCookie, "Cookie", UINT64, 10); -CONSTRUCT_TYPED_SFIELD(sfServerVersion, "ServerVersion", UINT64, 11); -CONSTRUCT_TYPED_SFIELD(sfNFTokenOfferNode, "NFTokenOfferNode", UINT64, 12); -CONSTRUCT_TYPED_SFIELD(sfEmitBurden, "EmitBurden", UINT64, 13); - -// 64-bit integers (uncommon) -CONSTRUCT_TYPED_SFIELD(sfHookOn, "HookOn", UINT64, 16); -CONSTRUCT_TYPED_SFIELD(sfHookInstructionCount, "HookInstructionCount", UINT64, 17); -CONSTRUCT_TYPED_SFIELD(sfHookReturnCode, "HookReturnCode", UINT64, 18); -CONSTRUCT_TYPED_SFIELD(sfReferenceCount, "ReferenceCount", UINT64, 19); -CONSTRUCT_TYPED_SFIELD(sfXChainClaimID, "XChainClaimID", UINT64, 20); -CONSTRUCT_TYPED_SFIELD(sfXChainAccountCreateCount, "XChainAccountCreateCount", UINT64, 21); -CONSTRUCT_TYPED_SFIELD(sfXChainAccountClaimCount, "XChainAccountClaimCount", UINT64, 22); -CONSTRUCT_TYPED_SFIELD(sfAssetPrice, "AssetPrice", UINT64, 23); - -// 128-bit -CONSTRUCT_TYPED_SFIELD(sfEmailHash, "EmailHash", UINT128, 1); - -// 160-bit (common) -CONSTRUCT_TYPED_SFIELD(sfTakerPaysCurrency, "TakerPaysCurrency", UINT160, 1); -CONSTRUCT_TYPED_SFIELD(sfTakerPaysIssuer, "TakerPaysIssuer", UINT160, 2); -CONSTRUCT_TYPED_SFIELD(sfTakerGetsCurrency, "TakerGetsCurrency", UINT160, 3); -CONSTRUCT_TYPED_SFIELD(sfTakerGetsIssuer, "TakerGetsIssuer", UINT160, 4); - -// 256-bit (common) -CONSTRUCT_TYPED_SFIELD(sfLedgerHash, "LedgerHash", UINT256, 1); -CONSTRUCT_TYPED_SFIELD(sfParentHash, "ParentHash", UINT256, 2); -CONSTRUCT_TYPED_SFIELD(sfTransactionHash, "TransactionHash", UINT256, 3); -CONSTRUCT_TYPED_SFIELD(sfAccountHash, "AccountHash", UINT256, 4); -CONSTRUCT_TYPED_SFIELD(sfPreviousTxnID, "PreviousTxnID", UINT256, 5, SField::sMD_DeleteFinal); -CONSTRUCT_TYPED_SFIELD(sfLedgerIndex, "LedgerIndex", UINT256, 6); -CONSTRUCT_TYPED_SFIELD(sfWalletLocator, "WalletLocator", UINT256, 7); -CONSTRUCT_TYPED_SFIELD(sfRootIndex, "RootIndex", UINT256, 8, SField::sMD_Always); -CONSTRUCT_TYPED_SFIELD(sfAccountTxnID, "AccountTxnID", UINT256, 9); -CONSTRUCT_TYPED_SFIELD(sfNFTokenID, "NFTokenID", UINT256, 10); -CONSTRUCT_TYPED_SFIELD(sfEmitParentTxnID, "EmitParentTxnID", UINT256, 11); -CONSTRUCT_TYPED_SFIELD(sfEmitNonce, "EmitNonce", UINT256, 12); -CONSTRUCT_TYPED_SFIELD(sfEmitHookHash, "EmitHookHash", UINT256, 13); -CONSTRUCT_TYPED_SFIELD(sfAMMID, "AMMID", UINT256, 14); - -// 256-bit (uncommon) -CONSTRUCT_TYPED_SFIELD(sfBookDirectory, "BookDirectory", UINT256, 16); -CONSTRUCT_TYPED_SFIELD(sfInvoiceID, "InvoiceID", UINT256, 17); -CONSTRUCT_TYPED_SFIELD(sfNickname, "Nickname", UINT256, 18); -CONSTRUCT_TYPED_SFIELD(sfAmendment, "Amendment", UINT256, 19); -// 20 is currently unused -CONSTRUCT_TYPED_SFIELD(sfDigest, "Digest", UINT256, 21); -CONSTRUCT_TYPED_SFIELD(sfChannel, "Channel", UINT256, 22); -CONSTRUCT_TYPED_SFIELD(sfConsensusHash, "ConsensusHash", UINT256, 23); -CONSTRUCT_TYPED_SFIELD(sfCheckID, "CheckID", UINT256, 24); -CONSTRUCT_TYPED_SFIELD(sfValidatedHash, "ValidatedHash", UINT256, 25); -CONSTRUCT_TYPED_SFIELD(sfPreviousPageMin, "PreviousPageMin", UINT256, 26); -CONSTRUCT_TYPED_SFIELD(sfNextPageMin, "NextPageMin", UINT256, 27); -CONSTRUCT_TYPED_SFIELD(sfNFTokenBuyOffer, "NFTokenBuyOffer", UINT256, 28); -CONSTRUCT_TYPED_SFIELD(sfNFTokenSellOffer, "NFTokenSellOffer", UINT256, 29); -CONSTRUCT_TYPED_SFIELD(sfHookStateKey, "HookStateKey", UINT256, 30); -CONSTRUCT_TYPED_SFIELD(sfHookHash, "HookHash", UINT256, 31); -CONSTRUCT_TYPED_SFIELD(sfHookNamespace, "HookNamespace", UINT256, 32); -CONSTRUCT_TYPED_SFIELD(sfHookSetTxnID, "HookSetTxnID", UINT256, 33); - -// currency amount (common) -CONSTRUCT_TYPED_SFIELD(sfAmount, "Amount", AMOUNT, 1); -CONSTRUCT_TYPED_SFIELD(sfBalance, "Balance", AMOUNT, 2); -CONSTRUCT_TYPED_SFIELD(sfLimitAmount, "LimitAmount", AMOUNT, 3); -CONSTRUCT_TYPED_SFIELD(sfTakerPays, "TakerPays", AMOUNT, 4); -CONSTRUCT_TYPED_SFIELD(sfTakerGets, "TakerGets", AMOUNT, 5); -CONSTRUCT_TYPED_SFIELD(sfLowLimit, "LowLimit", AMOUNT, 6); -CONSTRUCT_TYPED_SFIELD(sfHighLimit, "HighLimit", AMOUNT, 7); -CONSTRUCT_TYPED_SFIELD(sfFee, "Fee", AMOUNT, 8); -CONSTRUCT_TYPED_SFIELD(sfSendMax, "SendMax", AMOUNT, 9); -CONSTRUCT_TYPED_SFIELD(sfDeliverMin, "DeliverMin", AMOUNT, 10); -CONSTRUCT_TYPED_SFIELD(sfAmount2, "Amount2", AMOUNT, 11); -CONSTRUCT_TYPED_SFIELD(sfBidMin, "BidMin", AMOUNT, 12); -CONSTRUCT_TYPED_SFIELD(sfBidMax, "BidMax", AMOUNT, 13); - -// currency amount (uncommon) -CONSTRUCT_TYPED_SFIELD(sfMinimumOffer, "MinimumOffer", AMOUNT, 16); -CONSTRUCT_TYPED_SFIELD(sfRippleEscrow, "RippleEscrow", AMOUNT, 17); -CONSTRUCT_TYPED_SFIELD(sfDeliveredAmount, "DeliveredAmount", AMOUNT, 18); -CONSTRUCT_TYPED_SFIELD(sfNFTokenBrokerFee, "NFTokenBrokerFee", AMOUNT, 19); - -// Reserve 20 & 21 for Hooks - -// currency amount (fees) -CONSTRUCT_TYPED_SFIELD(sfBaseFeeDrops, "BaseFeeDrops", AMOUNT, 22); -CONSTRUCT_TYPED_SFIELD(sfReserveBaseDrops, "ReserveBaseDrops", AMOUNT, 23); -CONSTRUCT_TYPED_SFIELD(sfReserveIncrementDrops, "ReserveIncrementDrops", AMOUNT, 24); - -// currency amount (AMM) -CONSTRUCT_TYPED_SFIELD(sfLPTokenOut, "LPTokenOut", AMOUNT, 25); -CONSTRUCT_TYPED_SFIELD(sfLPTokenIn, "LPTokenIn", AMOUNT, 26); -CONSTRUCT_TYPED_SFIELD(sfEPrice, "EPrice", AMOUNT, 27); -CONSTRUCT_TYPED_SFIELD(sfPrice, "Price", AMOUNT, 28); -CONSTRUCT_TYPED_SFIELD(sfSignatureReward, "SignatureReward", AMOUNT, 29); -CONSTRUCT_TYPED_SFIELD(sfMinAccountCreateAmount, "MinAccountCreateAmount", AMOUNT, 30); -CONSTRUCT_TYPED_SFIELD(sfLPTokenBalance, "LPTokenBalance", AMOUNT, 31); - -// variable length (common) -CONSTRUCT_TYPED_SFIELD(sfPublicKey, "PublicKey", VL, 1); -CONSTRUCT_TYPED_SFIELD(sfMessageKey, "MessageKey", VL, 2); -CONSTRUCT_TYPED_SFIELD(sfSigningPubKey, "SigningPubKey", VL, 3); -CONSTRUCT_TYPED_SFIELD(sfTxnSignature, "TxnSignature", VL, 4, SField::sMD_Default, SField::notSigning); -CONSTRUCT_TYPED_SFIELD(sfURI, "URI", VL, 5); -CONSTRUCT_TYPED_SFIELD(sfSignature, "Signature", VL, 6, SField::sMD_Default, SField::notSigning); -CONSTRUCT_TYPED_SFIELD(sfDomain, "Domain", VL, 7); -CONSTRUCT_TYPED_SFIELD(sfFundCode, "FundCode", VL, 8); -CONSTRUCT_TYPED_SFIELD(sfRemoveCode, "RemoveCode", VL, 9); -CONSTRUCT_TYPED_SFIELD(sfExpireCode, "ExpireCode", VL, 10); -CONSTRUCT_TYPED_SFIELD(sfCreateCode, "CreateCode", VL, 11); -CONSTRUCT_TYPED_SFIELD(sfMemoType, "MemoType", VL, 12); -CONSTRUCT_TYPED_SFIELD(sfMemoData, "MemoData", VL, 13); -CONSTRUCT_TYPED_SFIELD(sfMemoFormat, "MemoFormat", VL, 14); - -// variable length (uncommon) -CONSTRUCT_TYPED_SFIELD(sfFulfillment, "Fulfillment", VL, 16); -CONSTRUCT_TYPED_SFIELD(sfCondition, "Condition", VL, 17); -CONSTRUCT_TYPED_SFIELD(sfMasterSignature, "MasterSignature", VL, 18, SField::sMD_Default, SField::notSigning); -CONSTRUCT_TYPED_SFIELD(sfUNLModifyValidator, "UNLModifyValidator", VL, 19); -CONSTRUCT_TYPED_SFIELD(sfValidatorToDisable, "ValidatorToDisable", VL, 20); -CONSTRUCT_TYPED_SFIELD(sfValidatorToReEnable, "ValidatorToReEnable", VL, 21); -CONSTRUCT_TYPED_SFIELD(sfHookStateData, "HookStateData", VL, 22); -CONSTRUCT_TYPED_SFIELD(sfHookReturnString, "HookReturnString", VL, 23); -CONSTRUCT_TYPED_SFIELD(sfHookParameterName, "HookParameterName", VL, 24); -CONSTRUCT_TYPED_SFIELD(sfHookParameterValue, "HookParameterValue", VL, 25); -CONSTRUCT_TYPED_SFIELD(sfDIDDocument, "DIDDocument", VL, 26); -CONSTRUCT_TYPED_SFIELD(sfData, "Data", VL, 27); -CONSTRUCT_TYPED_SFIELD(sfAssetClass, "AssetClass", VL, 28); -CONSTRUCT_TYPED_SFIELD(sfProvider, "Provider", VL, 29); - -// account -CONSTRUCT_TYPED_SFIELD(sfAccount, "Account", ACCOUNT, 1); -CONSTRUCT_TYPED_SFIELD(sfOwner, "Owner", ACCOUNT, 2); -CONSTRUCT_TYPED_SFIELD(sfDestination, "Destination", ACCOUNT, 3); -CONSTRUCT_TYPED_SFIELD(sfIssuer, "Issuer", ACCOUNT, 4); -CONSTRUCT_TYPED_SFIELD(sfAuthorize, "Authorize", ACCOUNT, 5); -CONSTRUCT_TYPED_SFIELD(sfUnauthorize, "Unauthorize", ACCOUNT, 6); -// 7 is currently unused -CONSTRUCT_TYPED_SFIELD(sfRegularKey, "RegularKey", ACCOUNT, 8); -CONSTRUCT_TYPED_SFIELD(sfNFTokenMinter, "NFTokenMinter", ACCOUNT, 9); -CONSTRUCT_TYPED_SFIELD(sfEmitCallback, "EmitCallback", ACCOUNT, 10); - -// account (uncommon) -CONSTRUCT_TYPED_SFIELD(sfHookAccount, "HookAccount", ACCOUNT, 16); -CONSTRUCT_TYPED_SFIELD(sfOtherChainSource, "OtherChainSource", ACCOUNT, 18); -CONSTRUCT_TYPED_SFIELD(sfOtherChainDestination, "OtherChainDestination",ACCOUNT, 19); -CONSTRUCT_TYPED_SFIELD(sfAttestationSignerAccount, "AttestationSignerAccount", ACCOUNT, 20); -CONSTRUCT_TYPED_SFIELD(sfAttestationRewardAccount, "AttestationRewardAccount", ACCOUNT, 21); -CONSTRUCT_TYPED_SFIELD(sfLockingChainDoor, "LockingChainDoor", ACCOUNT, 22); -CONSTRUCT_TYPED_SFIELD(sfIssuingChainDoor, "IssuingChainDoor", ACCOUNT, 23); - -// vector of 256-bit -CONSTRUCT_TYPED_SFIELD(sfIndexes, "Indexes", VECTOR256, 1, SField::sMD_Never); -CONSTRUCT_TYPED_SFIELD(sfHashes, "Hashes", VECTOR256, 2); -CONSTRUCT_TYPED_SFIELD(sfAmendments, "Amendments", VECTOR256, 3); -CONSTRUCT_TYPED_SFIELD(sfNFTokenOffers, "NFTokenOffers", VECTOR256, 4); - -// path set -CONSTRUCT_UNTYPED_SFIELD(sfPaths, "Paths", PATHSET, 1); - -// currency -CONSTRUCT_TYPED_SFIELD(sfBaseAsset, "BaseAsset", CURRENCY, 1); -CONSTRUCT_TYPED_SFIELD(sfQuoteAsset, "QuoteAsset", CURRENCY, 2); - -// issue -CONSTRUCT_TYPED_SFIELD(sfLockingChainIssue, "LockingChainIssue", ISSUE, 1); -CONSTRUCT_TYPED_SFIELD(sfIssuingChainIssue, "IssuingChainIssue", ISSUE, 2); -CONSTRUCT_TYPED_SFIELD(sfAsset, "Asset", ISSUE, 3); -CONSTRUCT_TYPED_SFIELD(sfAsset2, "Asset2", ISSUE, 4); - -// Bridge -CONSTRUCT_TYPED_SFIELD(sfXChainBridge, "XChainBridge", XCHAIN_BRIDGE, - 1); -// inner object -// OBJECT/1 is reserved for end of object -CONSTRUCT_UNTYPED_SFIELD(sfTransactionMetaData, "TransactionMetaData", OBJECT, 2); -CONSTRUCT_UNTYPED_SFIELD(sfCreatedNode, "CreatedNode", OBJECT, 3); -CONSTRUCT_UNTYPED_SFIELD(sfDeletedNode, "DeletedNode", OBJECT, 4); -CONSTRUCT_UNTYPED_SFIELD(sfModifiedNode, "ModifiedNode", OBJECT, 5); -CONSTRUCT_UNTYPED_SFIELD(sfPreviousFields, "PreviousFields", OBJECT, 6); -CONSTRUCT_UNTYPED_SFIELD(sfFinalFields, "FinalFields", OBJECT, 7); -CONSTRUCT_UNTYPED_SFIELD(sfNewFields, "NewFields", OBJECT, 8); -CONSTRUCT_UNTYPED_SFIELD(sfTemplateEntry, "TemplateEntry", OBJECT, 9); -CONSTRUCT_UNTYPED_SFIELD(sfMemo, "Memo", OBJECT, 10); -CONSTRUCT_UNTYPED_SFIELD(sfSignerEntry, "SignerEntry", OBJECT, 11); -CONSTRUCT_UNTYPED_SFIELD(sfNFToken, "NFToken", OBJECT, 12); -CONSTRUCT_UNTYPED_SFIELD(sfEmitDetails, "EmitDetails", OBJECT, 13); -CONSTRUCT_UNTYPED_SFIELD(sfHook, "Hook", OBJECT, 14); - -// inner object (uncommon) -CONSTRUCT_UNTYPED_SFIELD(sfSigner, "Signer", OBJECT, 16); -// 17 has not been used yet -CONSTRUCT_UNTYPED_SFIELD(sfMajority, "Majority", OBJECT, 18); -CONSTRUCT_UNTYPED_SFIELD(sfDisabledValidator, "DisabledValidator", OBJECT, 19); -CONSTRUCT_UNTYPED_SFIELD(sfEmittedTxn, "EmittedTxn", OBJECT, 20); -CONSTRUCT_UNTYPED_SFIELD(sfHookExecution, "HookExecution", OBJECT, 21); -CONSTRUCT_UNTYPED_SFIELD(sfHookDefinition, "HookDefinition", OBJECT, 22); -CONSTRUCT_UNTYPED_SFIELD(sfHookParameter, "HookParameter", OBJECT, 23); -CONSTRUCT_UNTYPED_SFIELD(sfHookGrant, "HookGrant", OBJECT, 24); -CONSTRUCT_UNTYPED_SFIELD(sfVoteEntry, "VoteEntry", OBJECT, 25); -CONSTRUCT_UNTYPED_SFIELD(sfAuctionSlot, "AuctionSlot", OBJECT, 26); -CONSTRUCT_UNTYPED_SFIELD(sfAuthAccount, "AuthAccount", OBJECT, 27); -CONSTRUCT_UNTYPED_SFIELD(sfXChainClaimProofSig, "XChainClaimProofSig", OBJECT, 28); -CONSTRUCT_UNTYPED_SFIELD(sfXChainCreateAccountProofSig, - "XChainCreateAccountProofSig", - OBJECT, 29); -CONSTRUCT_UNTYPED_SFIELD(sfXChainClaimAttestationCollectionElement, - "XChainClaimAttestationCollectionElement", - OBJECT, 30); -CONSTRUCT_UNTYPED_SFIELD(sfXChainCreateAccountAttestationCollectionElement, - "XChainCreateAccountAttestationCollectionElement", - OBJECT, 31); -CONSTRUCT_UNTYPED_SFIELD(sfPriceData, "PriceData", OBJECT, 32); - -// array of objects -// ARRAY/1 is reserved for end of array -// 2 has never been used -CONSTRUCT_UNTYPED_SFIELD(sfSigners, "Signers", ARRAY, 3, SField::sMD_Default, SField::notSigning); -CONSTRUCT_UNTYPED_SFIELD(sfSignerEntries, "SignerEntries", ARRAY, 4); -CONSTRUCT_UNTYPED_SFIELD(sfTemplate, "Template", ARRAY, 5); -CONSTRUCT_UNTYPED_SFIELD(sfNecessary, "Necessary", ARRAY, 6); -CONSTRUCT_UNTYPED_SFIELD(sfSufficient, "Sufficient", ARRAY, 7); -CONSTRUCT_UNTYPED_SFIELD(sfAffectedNodes, "AffectedNodes", ARRAY, 8); -CONSTRUCT_UNTYPED_SFIELD(sfMemos, "Memos", ARRAY, 9); -CONSTRUCT_UNTYPED_SFIELD(sfNFTokens, "NFTokens", ARRAY, 10); -CONSTRUCT_UNTYPED_SFIELD(sfHooks, "Hooks", ARRAY, 11); -CONSTRUCT_UNTYPED_SFIELD(sfVoteSlots, "VoteSlots", ARRAY, 12); - -// array of objects (uncommon) -CONSTRUCT_UNTYPED_SFIELD(sfMajorities, "Majorities", ARRAY, 16); -CONSTRUCT_UNTYPED_SFIELD(sfDisabledValidators, "DisabledValidators", ARRAY, 17); -CONSTRUCT_UNTYPED_SFIELD(sfHookExecutions, "HookExecutions", ARRAY, 18); -CONSTRUCT_UNTYPED_SFIELD(sfHookParameters, "HookParameters", ARRAY, 19); -CONSTRUCT_UNTYPED_SFIELD(sfHookGrants, "HookGrants", ARRAY, 20); -CONSTRUCT_UNTYPED_SFIELD(sfXChainClaimAttestations, - "XChainClaimAttestations", - ARRAY, 21); -CONSTRUCT_UNTYPED_SFIELD(sfXChainCreateAccountAttestations, - "XChainCreateAccountAttestations", - ARRAY, 22); -// 23 is unused and available for use -CONSTRUCT_UNTYPED_SFIELD(sfPriceDataSeries, "PriceDataSeries", ARRAY, 24); -CONSTRUCT_UNTYPED_SFIELD(sfAuthAccounts, "AuthAccounts", ARRAY, 25); - -// clang-format on -#undef CONSTRUCT_TYPED_SFIELD -#undef CONSTRUCT_UNTYPED_SFIELD +#include -#pragma pop_macro("CONSTRUCT_TYPED_SFIELD") -#pragma pop_macro("CONSTRUCT_UNTYPED_SFIELD") +#undef TYPED_SFIELD +#pragma pop_macro("TYPED_SFIELD") +#undef UNTYPED_SFIELD +#pragma pop_macro("UNTYPED_SFIELD") SField::SField( private_access_tag_t, diff --git a/src/libxrpl/protocol/TxFormats.cpp b/src/libxrpl/protocol/TxFormats.cpp index 8a93232604e..76b1ae8ad4f 100644 --- a/src/libxrpl/protocol/TxFormats.cpp +++ b/src/libxrpl/protocol/TxFormats.cpp @@ -47,472 +47,21 @@ TxFormats::TxFormats() {sfNetworkID, soeOPTIONAL}, }; - add(jss::AccountSet, - ttACCOUNT_SET, - { - {sfEmailHash, soeOPTIONAL}, - {sfWalletLocator, soeOPTIONAL}, - {sfWalletSize, soeOPTIONAL}, - {sfMessageKey, soeOPTIONAL}, - {sfDomain, soeOPTIONAL}, - {sfTransferRate, soeOPTIONAL}, - {sfSetFlag, soeOPTIONAL}, - {sfClearFlag, soeOPTIONAL}, - {sfTickSize, soeOPTIONAL}, - {sfNFTokenMinter, soeOPTIONAL}, - }, - commonFields); +#pragma push_macro("UNWRAP") +#undef UNWRAP +#pragma push_macro("TRANSACTION") +#undef TRANSACTION - add(jss::TrustSet, - ttTRUST_SET, - { - {sfLimitAmount, soeOPTIONAL}, - {sfQualityIn, soeOPTIONAL}, - {sfQualityOut, soeOPTIONAL}, - }, - commonFields); +#define UNWRAP(...) __VA_ARGS__ +#define TRANSACTION(tag, value, name, fields) \ + add(jss::name, tag, UNWRAP fields, commonFields); - add(jss::OfferCreate, - ttOFFER_CREATE, - { - {sfTakerPays, soeREQUIRED}, - {sfTakerGets, soeREQUIRED}, - {sfExpiration, soeOPTIONAL}, - {sfOfferSequence, soeOPTIONAL}, - }, - commonFields); +#include - add(jss::AMMCreate, - ttAMM_CREATE, - { - {sfAmount, soeREQUIRED}, - {sfAmount2, soeREQUIRED}, - {sfTradingFee, soeREQUIRED}, - }, - commonFields); - - add(jss::AMMDeposit, - ttAMM_DEPOSIT, - { - {sfAsset, soeREQUIRED}, - {sfAsset2, soeREQUIRED}, - {sfAmount, soeOPTIONAL}, - {sfAmount2, soeOPTIONAL}, - {sfEPrice, soeOPTIONAL}, - {sfLPTokenOut, soeOPTIONAL}, - {sfTradingFee, soeOPTIONAL}, - }, - commonFields); - - add(jss::AMMWithdraw, - ttAMM_WITHDRAW, - { - {sfAsset, soeREQUIRED}, - {sfAsset2, soeREQUIRED}, - {sfAmount, soeOPTIONAL}, - {sfAmount2, soeOPTIONAL}, - {sfEPrice, soeOPTIONAL}, - {sfLPTokenIn, soeOPTIONAL}, - }, - commonFields); - - add(jss::AMMVote, - ttAMM_VOTE, - { - {sfAsset, soeREQUIRED}, - {sfAsset2, soeREQUIRED}, - {sfTradingFee, soeREQUIRED}, - }, - commonFields); - - add(jss::AMMBid, - ttAMM_BID, - { - {sfAsset, soeREQUIRED}, - {sfAsset2, soeREQUIRED}, - {sfBidMin, soeOPTIONAL}, - {sfBidMax, soeOPTIONAL}, - {sfAuthAccounts, soeOPTIONAL}, - }, - commonFields); - - add(jss::AMMDelete, - ttAMM_DELETE, - { - {sfAsset, soeREQUIRED}, - {sfAsset2, soeREQUIRED}, - }, - commonFields); - - add(jss::OfferCancel, - ttOFFER_CANCEL, - { - {sfOfferSequence, soeREQUIRED}, - }, - commonFields); - - add(jss::SetRegularKey, - ttREGULAR_KEY_SET, - { - {sfRegularKey, soeOPTIONAL}, - }, - commonFields); - - add(jss::Payment, - ttPAYMENT, - { - {sfDestination, soeREQUIRED}, - {sfAmount, soeREQUIRED}, - {sfSendMax, soeOPTIONAL}, - {sfPaths, soeDEFAULT}, - {sfInvoiceID, soeOPTIONAL}, - {sfDestinationTag, soeOPTIONAL}, - {sfDeliverMin, soeOPTIONAL}, - }, - commonFields); - - add(jss::EscrowCreate, - ttESCROW_CREATE, - { - {sfDestination, soeREQUIRED}, - {sfAmount, soeREQUIRED}, - {sfCondition, soeOPTIONAL}, - {sfCancelAfter, soeOPTIONAL}, - {sfFinishAfter, soeOPTIONAL}, - {sfDestinationTag, soeOPTIONAL}, - }, - commonFields); - - add(jss::EscrowFinish, - ttESCROW_FINISH, - { - {sfOwner, soeREQUIRED}, - {sfOfferSequence, soeREQUIRED}, - {sfFulfillment, soeOPTIONAL}, - {sfCondition, soeOPTIONAL}, - }, - commonFields); - - add(jss::EscrowCancel, - ttESCROW_CANCEL, - { - {sfOwner, soeREQUIRED}, - {sfOfferSequence, soeREQUIRED}, - }, - commonFields); - - add(jss::EnableAmendment, - ttAMENDMENT, - { - {sfLedgerSequence, soeREQUIRED}, - {sfAmendment, soeREQUIRED}, - }, - commonFields); - - add(jss::SetFee, - ttFEE, - { - {sfLedgerSequence, soeOPTIONAL}, - // Old version uses raw numbers - {sfBaseFee, soeOPTIONAL}, - {sfReferenceFeeUnits, soeOPTIONAL}, - {sfReserveBase, soeOPTIONAL}, - {sfReserveIncrement, soeOPTIONAL}, - // New version uses Amounts - {sfBaseFeeDrops, soeOPTIONAL}, - {sfReserveBaseDrops, soeOPTIONAL}, - {sfReserveIncrementDrops, soeOPTIONAL}, - }, - commonFields); - - add(jss::UNLModify, - ttUNL_MODIFY, - { - {sfUNLModifyDisabling, soeREQUIRED}, - {sfLedgerSequence, soeREQUIRED}, - {sfUNLModifyValidator, soeREQUIRED}, - }, - commonFields); - - add(jss::TicketCreate, - ttTICKET_CREATE, - { - {sfTicketCount, soeREQUIRED}, - }, - commonFields); - - // The SignerEntries are optional because a SignerList is deleted by - // setting the SignerQuorum to zero and omitting SignerEntries. - add(jss::SignerListSet, - ttSIGNER_LIST_SET, - { - {sfSignerQuorum, soeREQUIRED}, - {sfSignerEntries, soeOPTIONAL}, - }, - commonFields); - - add(jss::PaymentChannelCreate, - ttPAYCHAN_CREATE, - { - {sfDestination, soeREQUIRED}, - {sfAmount, soeREQUIRED}, - {sfSettleDelay, soeREQUIRED}, - {sfPublicKey, soeREQUIRED}, - {sfCancelAfter, soeOPTIONAL}, - {sfDestinationTag, soeOPTIONAL}, - }, - commonFields); - - add(jss::PaymentChannelFund, - ttPAYCHAN_FUND, - { - {sfChannel, soeREQUIRED}, - {sfAmount, soeREQUIRED}, - {sfExpiration, soeOPTIONAL}, - }, - commonFields); - - add(jss::PaymentChannelClaim, - ttPAYCHAN_CLAIM, - { - {sfChannel, soeREQUIRED}, - {sfAmount, soeOPTIONAL}, - {sfBalance, soeOPTIONAL}, - {sfSignature, soeOPTIONAL}, - {sfPublicKey, soeOPTIONAL}, - }, - commonFields); - - add(jss::CheckCreate, - ttCHECK_CREATE, - { - {sfDestination, soeREQUIRED}, - {sfSendMax, soeREQUIRED}, - {sfExpiration, soeOPTIONAL}, - {sfDestinationTag, soeOPTIONAL}, - {sfInvoiceID, soeOPTIONAL}, - }, - commonFields); - - add(jss::CheckCash, - ttCHECK_CASH, - { - {sfCheckID, soeREQUIRED}, - {sfAmount, soeOPTIONAL}, - {sfDeliverMin, soeOPTIONAL}, - }, - commonFields); - - add(jss::CheckCancel, - ttCHECK_CANCEL, - { - {sfCheckID, soeREQUIRED}, - }, - commonFields); - - add(jss::AccountDelete, - ttACCOUNT_DELETE, - { - {sfDestination, soeREQUIRED}, - {sfDestinationTag, soeOPTIONAL}, - }, - commonFields); - - add(jss::DepositPreauth, - ttDEPOSIT_PREAUTH, - { - {sfAuthorize, soeOPTIONAL}, - {sfUnauthorize, soeOPTIONAL}, - }, - commonFields); - - add(jss::NFTokenMint, - ttNFTOKEN_MINT, - { - {sfNFTokenTaxon, soeREQUIRED}, - {sfTransferFee, soeOPTIONAL}, - {sfIssuer, soeOPTIONAL}, - {sfURI, soeOPTIONAL}, - {sfAmount, soeOPTIONAL}, - {sfDestination, soeOPTIONAL}, - {sfExpiration, soeOPTIONAL}, - }, - commonFields); - - add(jss::NFTokenBurn, - ttNFTOKEN_BURN, - { - {sfNFTokenID, soeREQUIRED}, - {sfOwner, soeOPTIONAL}, - }, - commonFields); - - add(jss::NFTokenCreateOffer, - ttNFTOKEN_CREATE_OFFER, - { - {sfNFTokenID, soeREQUIRED}, - {sfAmount, soeREQUIRED}, - {sfDestination, soeOPTIONAL}, - {sfOwner, soeOPTIONAL}, - {sfExpiration, soeOPTIONAL}, - }, - commonFields); - - add(jss::NFTokenCancelOffer, - ttNFTOKEN_CANCEL_OFFER, - { - {sfNFTokenOffers, soeREQUIRED}, - }, - commonFields); - - add(jss::NFTokenAcceptOffer, - ttNFTOKEN_ACCEPT_OFFER, - { - {sfNFTokenBuyOffer, soeOPTIONAL}, - {sfNFTokenSellOffer, soeOPTIONAL}, - {sfNFTokenBrokerFee, soeOPTIONAL}, - }, - commonFields); - - add(jss::Clawback, - ttCLAWBACK, - { - {sfAmount, soeREQUIRED}, - }, - commonFields); - - add(jss::XChainCreateBridge, - ttXCHAIN_CREATE_BRIDGE, - { - {sfXChainBridge, soeREQUIRED}, - {sfSignatureReward, soeREQUIRED}, - {sfMinAccountCreateAmount, soeOPTIONAL}, - }, - commonFields); - - add(jss::XChainModifyBridge, - ttXCHAIN_MODIFY_BRIDGE, - { - {sfXChainBridge, soeREQUIRED}, - {sfSignatureReward, soeOPTIONAL}, - {sfMinAccountCreateAmount, soeOPTIONAL}, - }, - commonFields); - - add(jss::XChainCreateClaimID, - ttXCHAIN_CREATE_CLAIM_ID, - { - {sfXChainBridge, soeREQUIRED}, - {sfSignatureReward, soeREQUIRED}, - {sfOtherChainSource, soeREQUIRED}, - }, - commonFields); - - add(jss::XChainCommit, - ttXCHAIN_COMMIT, - { - {sfXChainBridge, soeREQUIRED}, - {sfXChainClaimID, soeREQUIRED}, - {sfAmount, soeREQUIRED}, - {sfOtherChainDestination, soeOPTIONAL}, - }, - commonFields); - - add(jss::XChainClaim, - ttXCHAIN_CLAIM, - { - {sfXChainBridge, soeREQUIRED}, - {sfXChainClaimID, soeREQUIRED}, - {sfDestination, soeREQUIRED}, - {sfDestinationTag, soeOPTIONAL}, - {sfAmount, soeREQUIRED}, - }, - commonFields); - - add(jss::XChainAddClaimAttestation, - ttXCHAIN_ADD_CLAIM_ATTESTATION, - { - {sfXChainBridge, soeREQUIRED}, - - {sfAttestationSignerAccount, soeREQUIRED}, - {sfPublicKey, soeREQUIRED}, - {sfSignature, soeREQUIRED}, - {sfOtherChainSource, soeREQUIRED}, - {sfAmount, soeREQUIRED}, - {sfAttestationRewardAccount, soeREQUIRED}, - {sfWasLockingChainSend, soeREQUIRED}, - - {sfXChainClaimID, soeREQUIRED}, - {sfDestination, soeOPTIONAL}, - }, - commonFields); - - add(jss::XChainAddAccountCreateAttestation, - ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, - { - {sfXChainBridge, soeREQUIRED}, - - {sfAttestationSignerAccount, soeREQUIRED}, - {sfPublicKey, soeREQUIRED}, - {sfSignature, soeREQUIRED}, - {sfOtherChainSource, soeREQUIRED}, - {sfAmount, soeREQUIRED}, - {sfAttestationRewardAccount, soeREQUIRED}, - {sfWasLockingChainSend, soeREQUIRED}, - - {sfXChainAccountCreateCount, soeREQUIRED}, - {sfDestination, soeREQUIRED}, - {sfSignatureReward, soeREQUIRED}, - }, - commonFields); - - add(jss::XChainAccountCreateCommit, - ttXCHAIN_ACCOUNT_CREATE_COMMIT, - { - {sfXChainBridge, soeREQUIRED}, - {sfDestination, soeREQUIRED}, - {sfAmount, soeREQUIRED}, - {sfSignatureReward, soeREQUIRED}, - }, - commonFields); - - add(jss::DIDSet, - ttDID_SET, - { - {sfDIDDocument, soeOPTIONAL}, - {sfURI, soeOPTIONAL}, - {sfData, soeOPTIONAL}, - }, - commonFields); - - add(jss::DIDDelete, ttDID_DELETE, {}, commonFields); - - add(jss::OracleSet, - ttORACLE_SET, - { - {sfOracleDocumentID, soeREQUIRED}, - {sfProvider, soeOPTIONAL}, - {sfURI, soeOPTIONAL}, - {sfAssetClass, soeOPTIONAL}, - {sfLastUpdateTime, soeREQUIRED}, - {sfPriceDataSeries, soeREQUIRED}, - }, - commonFields); - - add(jss::OracleDelete, - ttORACLE_DELETE, - { - {sfOracleDocumentID, soeREQUIRED}, - }, - commonFields); - - add(jss::LedgerStateFix, - ttLEDGER_STATE_FIX, - { - {sfLedgerFixType, soeREQUIRED}, - {sfOwner, soeOPTIONAL}, - }, - commonFields); +#undef TRANSACTION +#pragma pop_macro("TRANSACTION") +#undef UNWRAP +#pragma pop_macro("UNWRAP") } TxFormats const& diff --git a/src/test/jtx/impl/AMM.cpp b/src/test/jtx/impl/AMM.cpp index 8c369e68527..4ef4fef7c1e 100644 --- a/src/test/jtx/impl/AMM.cpp +++ b/src/test/jtx/impl/AMM.cpp @@ -140,7 +140,7 @@ AMM::create( if (flags) jv[jss::Flags] = *flags; if (fee_ != 0) - jv[jss::Fee] = std::to_string(fee_); + jv[sfFee] = std::to_string(fee_); else jv[jss::Fee] = std::to_string(env_.current()->fees().increment.drops()); submit(jv, seq, ter); diff --git a/src/xrpld/app/tx/detail/CancelCheck.h b/src/xrpld/app/tx/detail/CancelCheck.h index 582d8559e50..d9b70f919c1 100644 --- a/src/xrpld/app/tx/detail/CancelCheck.h +++ b/src/xrpld/app/tx/detail/CancelCheck.h @@ -43,6 +43,8 @@ class CancelCheck : public Transactor doApply() override; }; +using CheckCancel = CancelCheck; + } // namespace ripple #endif diff --git a/src/xrpld/app/tx/detail/CancelOffer.h b/src/xrpld/app/tx/detail/CancelOffer.h index 1e3b4a5c983..0942e61282b 100644 --- a/src/xrpld/app/tx/detail/CancelOffer.h +++ b/src/xrpld/app/tx/detail/CancelOffer.h @@ -46,6 +46,8 @@ class CancelOffer : public Transactor doApply() override; }; +using OfferCancel = CancelOffer; + } // namespace ripple #endif diff --git a/src/xrpld/app/tx/detail/CashCheck.h b/src/xrpld/app/tx/detail/CashCheck.h index c90cd93a9f8..da7ef22e3c3 100644 --- a/src/xrpld/app/tx/detail/CashCheck.h +++ b/src/xrpld/app/tx/detail/CashCheck.h @@ -43,6 +43,8 @@ class CashCheck : public Transactor doApply() override; }; +using CheckCash = CashCheck; + } // namespace ripple #endif diff --git a/src/xrpld/app/tx/detail/Change.h b/src/xrpld/app/tx/detail/Change.h index 7a569bc920e..b0780a75c04 100644 --- a/src/xrpld/app/tx/detail/Change.h +++ b/src/xrpld/app/tx/detail/Change.h @@ -69,6 +69,10 @@ class Change : public Transactor applyUNLModify(); }; +using EnableAmendment = Change; +using SetFee = Change; +using UNLModify = Change; + } // namespace ripple #endif diff --git a/src/xrpld/app/tx/detail/CreateCheck.h b/src/xrpld/app/tx/detail/CreateCheck.h index 86daad07061..0e414ce0123 100644 --- a/src/xrpld/app/tx/detail/CreateCheck.h +++ b/src/xrpld/app/tx/detail/CreateCheck.h @@ -43,6 +43,8 @@ class CreateCheck : public Transactor doApply() override; }; +using CheckCreate = CreateCheck; + } // namespace ripple #endif diff --git a/src/xrpld/app/tx/detail/CreateOffer.h b/src/xrpld/app/tx/detail/CreateOffer.h index 47129df5b04..234267804c9 100644 --- a/src/xrpld/app/tx/detail/CreateOffer.h +++ b/src/xrpld/app/tx/detail/CreateOffer.h @@ -142,6 +142,8 @@ class CreateOffer : public Transactor OfferStream::StepCounter stepCounter_; }; +using OfferCreate = CreateOffer; + } // namespace ripple #endif diff --git a/src/xrpld/app/tx/detail/CreateTicket.h b/src/xrpld/app/tx/detail/CreateTicket.h index edfcaa787c9..099dcde9347 100644 --- a/src/xrpld/app/tx/detail/CreateTicket.h +++ b/src/xrpld/app/tx/detail/CreateTicket.h @@ -84,6 +84,8 @@ class CreateTicket : public Transactor doApply() override; }; +using TicketCreate = CreateTicket; + } // namespace ripple #endif diff --git a/src/xrpld/app/tx/detail/DeleteAccount.h b/src/xrpld/app/tx/detail/DeleteAccount.h index e1da2f45964..5f88a9ba718 100644 --- a/src/xrpld/app/tx/detail/DeleteAccount.h +++ b/src/xrpld/app/tx/detail/DeleteAccount.h @@ -48,6 +48,8 @@ class DeleteAccount : public Transactor doApply() override; }; +using AccountDelete = DeleteAccount; + } // namespace ripple #endif diff --git a/src/xrpld/app/tx/detail/DeleteOracle.h b/src/xrpld/app/tx/detail/DeleteOracle.h index 8f1402563a2..bbbfc6f5256 100644 --- a/src/xrpld/app/tx/detail/DeleteOracle.h +++ b/src/xrpld/app/tx/detail/DeleteOracle.h @@ -59,6 +59,8 @@ class DeleteOracle : public Transactor beast::Journal j); }; +using OracleDelete = DeleteOracle; + } // namespace ripple #endif // RIPPLE_TX_DELETEORACLE_H_INCLUDED diff --git a/src/xrpld/app/tx/detail/PayChan.h b/src/xrpld/app/tx/detail/PayChan.h index 8bb3a6d9379..5eef7e51c0c 100644 --- a/src/xrpld/app/tx/detail/PayChan.h +++ b/src/xrpld/app/tx/detail/PayChan.h @@ -46,6 +46,8 @@ class PayChanCreate : public Transactor doApply() override; }; +using PaymentChannelCreate = PayChanCreate; + //------------------------------------------------------------------------------ class PayChanFund : public Transactor @@ -67,6 +69,8 @@ class PayChanFund : public Transactor doApply() override; }; +using PaymentChannelFund = PayChanFund; + //------------------------------------------------------------------------------ class PayChanClaim : public Transactor @@ -85,6 +89,8 @@ class PayChanClaim : public Transactor doApply() override; }; +using PaymentChannelClaim = PayChanClaim; + } // namespace ripple #endif diff --git a/src/xrpld/app/tx/detail/SetAccount.h b/src/xrpld/app/tx/detail/SetAccount.h index 8e9b74d860b..62cae28e51c 100644 --- a/src/xrpld/app/tx/detail/SetAccount.h +++ b/src/xrpld/app/tx/detail/SetAccount.h @@ -51,6 +51,8 @@ class SetAccount : public Transactor doApply() override; }; +using AccountSet = SetAccount; + } // namespace ripple #endif diff --git a/src/xrpld/app/tx/detail/SetOracle.h b/src/xrpld/app/tx/detail/SetOracle.h index 13c4d7a0cc9..656b6560192 100644 --- a/src/xrpld/app/tx/detail/SetOracle.h +++ b/src/xrpld/app/tx/detail/SetOracle.h @@ -52,6 +52,8 @@ class SetOracle : public Transactor doApply() override; }; +using OracleSet = SetOracle; + } // namespace ripple #endif // RIPPLE_TX_SETORACLE_H_INCLUDED diff --git a/src/xrpld/app/tx/detail/SetSignerList.h b/src/xrpld/app/tx/detail/SetSignerList.h index c2006945eca..35951645c21 100644 --- a/src/xrpld/app/tx/detail/SetSignerList.h +++ b/src/xrpld/app/tx/detail/SetSignerList.h @@ -97,6 +97,8 @@ class SetSignerList : public Transactor const; }; +using SignerListSet = SetSignerList; + } // namespace ripple #endif diff --git a/src/xrpld/app/tx/detail/SetTrust.h b/src/xrpld/app/tx/detail/SetTrust.h index a86c8498d48..6e5a72b3062 100644 --- a/src/xrpld/app/tx/detail/SetTrust.h +++ b/src/xrpld/app/tx/detail/SetTrust.h @@ -47,6 +47,8 @@ class SetTrust : public Transactor doApply() override; }; +using TrustSet = SetTrust; + } // namespace ripple #endif diff --git a/src/xrpld/app/tx/detail/XChainBridge.h b/src/xrpld/app/tx/detail/XChainBridge.h index 822f687729a..2e5e927d120 100644 --- a/src/xrpld/app/tx/detail/XChainBridge.h +++ b/src/xrpld/app/tx/detail/XChainBridge.h @@ -67,6 +67,9 @@ class BridgeModify : public Transactor TER doApply() override; }; + +using XChainModifyBridge = BridgeModify; + //------------------------------------------------------------------------------ // Claim funds from a `XChainCommit` transaction. This is normally not needed, @@ -248,6 +251,8 @@ class XChainCreateAccountCommit : public Transactor doApply() override; }; +using XChainAccountCreateCommit = XChainCreateAccountCommit; + //------------------------------------------------------------------------------ } // namespace ripple diff --git a/src/xrpld/app/tx/detail/applySteps.cpp b/src/xrpld/app/tx/detail/applySteps.cpp index cbeabb6fc9c..f39c61abeac 100644 --- a/src/xrpld/app/tx/detail/applySteps.cpp +++ b/src/xrpld/app/tx/detail/applySteps.cpp @@ -76,98 +76,18 @@ with_txn_type(TxType txnType, F&& f) { switch (txnType) { - case ttACCOUNT_DELETE: - return f.template operator()(); - case ttACCOUNT_SET: - return f.template operator()(); - case ttCHECK_CANCEL: - return f.template operator()(); - case ttCHECK_CASH: - return f.template operator()(); - case ttCHECK_CREATE: - return f.template operator()(); - case ttDEPOSIT_PREAUTH: - return f.template operator()(); - case ttOFFER_CANCEL: - return f.template operator()(); - case ttOFFER_CREATE: - return f.template operator()(); - case ttESCROW_CREATE: - return f.template operator()(); - case ttESCROW_FINISH: - return f.template operator()(); - case ttESCROW_CANCEL: - return f.template operator()(); - case ttLEDGER_STATE_FIX: - return f.template operator()(); - case ttPAYCHAN_CLAIM: - return f.template operator()(); - case ttPAYCHAN_CREATE: - return f.template operator()(); - case ttPAYCHAN_FUND: - return f.template operator()(); - case ttPAYMENT: - return f.template operator()(); - case ttREGULAR_KEY_SET: - return f.template operator()(); - case ttSIGNER_LIST_SET: - return f.template operator()(); - case ttTICKET_CREATE: - return f.template operator()(); - case ttTRUST_SET: - return f.template operator()(); - case ttAMENDMENT: - case ttFEE: - case ttUNL_MODIFY: - return f.template operator()(); - case ttNFTOKEN_MINT: - return f.template operator()(); - case ttNFTOKEN_BURN: - return f.template operator()(); - case ttNFTOKEN_CREATE_OFFER: - return f.template operator()(); - case ttNFTOKEN_CANCEL_OFFER: - return f.template operator()(); - case ttNFTOKEN_ACCEPT_OFFER: - return f.template operator()(); - case ttCLAWBACK: - return f.template operator()(); - case ttAMM_CREATE: - return f.template operator()(); - case ttAMM_DEPOSIT: - return f.template operator()(); - case ttAMM_WITHDRAW: - return f.template operator()(); - case ttAMM_VOTE: - return f.template operator()(); - case ttAMM_BID: - return f.template operator()(); - case ttAMM_DELETE: - return f.template operator()(); - case ttXCHAIN_CREATE_BRIDGE: - return f.template operator()(); - case ttXCHAIN_MODIFY_BRIDGE: - return f.template operator()(); - case ttXCHAIN_CREATE_CLAIM_ID: - return f.template operator()(); - case ttXCHAIN_COMMIT: - return f.template operator()(); - case ttXCHAIN_CLAIM: - return f.template operator()(); - case ttXCHAIN_ADD_CLAIM_ATTESTATION: - return f.template operator()(); - case ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION: - return f.template operator()(); - case ttXCHAIN_ACCOUNT_CREATE_COMMIT: - return f.template operator()(); - case ttDID_SET: - return f.template operator()(); - case ttDID_DELETE: - return f.template operator()(); - case ttORACLE_SET: - return f.template operator()(); - case ttORACLE_DELETE: - return f.template operator()(); +#pragma push_macro("TRANSACTION") +#undef TRANSACTION + +#define TRANSACTION(tag, value, name, fields) \ + case tag: \ + return f.template operator()(); + +#include + +#undef TRANSACTION +#pragma pop_macro("TRANSACTION") + default: throw UnknownTxnType(txnType); } From 23c37fa50600f0442bf353cb8ce3324f81919e80 Mon Sep 17 00:00:00 2001 From: Gregory Tsipenyuk Date: Tue, 29 Oct 2024 15:19:28 -0400 Subject: [PATCH 63/82] Introduce MPT support (XLS-33d): (#5143) Amendment: - MPTokensV1 New Transactions: - MPTokenIssuanceCreate - MPTokenIssuanceDestroy - MPTokenIssuanceSet - MPTokenAuthorize Modified Transactions: - Payment - Clawback New Objects: - MPTokenIssuance - MPToken API updates: - ledger_entry - account_objects - ledger_data Other: - Add += and -= operators to ValueProxy Read full spec: https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0033d-multi-purpose-tokens --------- Co-authored-by: Shawn Xie Co-authored-by: Howard Hinnant Co-authored-by: Ed Hennis Co-authored-by: John Freeman --- Builds/levelization/results/loops.txt | 2 +- include/xrpl/basics/MPTAmount.h | 166 ++ include/xrpl/basics/Number.h | 13 + include/xrpl/basics/XRPAmount.h | 4 + include/xrpl/basics/base_uint.h | 2 + include/xrpl/protocol/AmountConversions.h | 8 +- include/xrpl/protocol/Asset.h | 177 ++ include/xrpl/protocol/Feature.h | 2 +- include/xrpl/protocol/Indexes.h | 27 + include/xrpl/protocol/Issue.h | 20 +- include/xrpl/protocol/LedgerFormats.h | 12 + include/xrpl/protocol/MPTIssue.h | 98 + include/xrpl/protocol/Protocol.h | 6 + include/xrpl/protocol/Rate.h | 4 +- include/xrpl/protocol/SField.h | 1 + include/xrpl/protocol/SOTemplate.h | 31 +- include/xrpl/protocol/STAmount.h | 246 +- include/xrpl/protocol/STBitString.h | 8 + include/xrpl/protocol/STObject.h | 35 + include/xrpl/protocol/Serializer.h | 6 + include/xrpl/protocol/TER.h | 5 +- include/xrpl/protocol/TxFlags.h | 27 +- include/xrpl/protocol/UintTypes.h | 5 + include/xrpl/protocol/detail/STVar.h | 24 + include/xrpl/protocol/detail/features.macro | 3 +- .../xrpl/protocol/detail/ledger_entries.macro | 28 + include/xrpl/protocol/detail/sfields.macro | 9 + .../xrpl/protocol/detail/transactions.macro | 34 +- include/xrpl/protocol/jss.h | 874 ++++---- src/libxrpl/basics/MPTAmount.cpp | 68 + src/libxrpl/basics/Number.cpp | 5 + src/libxrpl/protocol/Asset.cpp | 73 + src/libxrpl/protocol/Indexes.cpp | 38 + src/libxrpl/protocol/Issue.cpp | 24 +- src/libxrpl/protocol/MPTIssue.cpp | 107 + src/libxrpl/protocol/Quality.cpp | 10 +- src/libxrpl/protocol/Rate2.cpp | 16 +- src/libxrpl/protocol/STAmount.cpp | 470 ++-- src/libxrpl/protocol/STInteger.cpp | 22 +- src/libxrpl/protocol/STLedgerEntry.cpp | 4 + src/libxrpl/protocol/STObject.cpp | 6 + src/libxrpl/protocol/STParsedJSON.cpp | 33 +- src/libxrpl/protocol/STTx.cpp | 33 + src/libxrpl/protocol/STVar.cpp | 156 +- src/libxrpl/protocol/TER.cpp | 2 + src/test/app/Clawback_test.cpp | 1 + src/test/app/Flow_test.cpp | 4 - src/test/app/MPToken_test.cpp | 1981 +++++++++++++++++ src/test/app/SetAuth_test.cpp | 4 +- src/test/app/TrustAndBalance_test.cpp | 1 - src/test/jtx.h | 1 + src/test/jtx/Env.h | 6 + src/test/jtx/amount.h | 69 +- src/test/jtx/impl/mpt.cpp | 412 ++++ src/test/jtx/impl/trust.cpp | 8 +- src/test/jtx/mpt.h | 254 +++ src/test/jtx/trust.h | 5 +- src/test/ledger/PaymentSandbox_test.cpp | 2 - src/test/protocol/Quality_test.cpp | 2 +- src/test/protocol/STAmount_test.cpp | 2 - src/test/protocol/STObject_test.cpp | 22 + src/test/protocol/STTx_test.cpp | 37 + src/test/rpc/LedgerRPC_test.cpp | 74 + src/xrpld/app/ledger/detail/LedgerToJson.cpp | 13 + src/xrpld/app/misc/NetworkOPs.cpp | 3 + src/xrpld/app/paths/Credit.cpp | 4 +- src/xrpld/app/paths/PathRequest.cpp | 2 +- src/xrpld/app/paths/Pathfinder.cpp | 7 +- src/xrpld/app/tx/detail/Clawback.cpp | 205 +- src/xrpld/app/tx/detail/InvariantCheck.cpp | 204 +- src/xrpld/app/tx/detail/InvariantCheck.h | 28 +- src/xrpld/app/tx/detail/MPTokenAuthorize.cpp | 267 +++ src/xrpld/app/tx/detail/MPTokenAuthorize.h | 63 + .../app/tx/detail/MPTokenIssuanceCreate.cpp | 142 ++ .../app/tx/detail/MPTokenIssuanceCreate.h | 60 + .../app/tx/detail/MPTokenIssuanceDestroy.cpp | 84 + .../app/tx/detail/MPTokenIssuanceDestroy.h | 48 + .../app/tx/detail/MPTokenIssuanceSet.cpp | 118 + src/xrpld/app/tx/detail/MPTokenIssuanceSet.h | 48 + src/xrpld/app/tx/detail/Payment.cpp | 289 ++- src/xrpld/app/tx/detail/SetTrust.cpp | 2 +- src/xrpld/app/tx/detail/applySteps.cpp | 4 + src/xrpld/ledger/View.h | 94 +- src/xrpld/ledger/detail/View.cpp | 399 +++- src/xrpld/rpc/MPTokenIssuanceID.h | 61 + src/xrpld/rpc/detail/MPTokenIssuanceID.cpp | 83 + src/xrpld/rpc/detail/RPCHelpers.cpp | 6 +- src/xrpld/rpc/detail/TransactionSign.cpp | 3 +- src/xrpld/rpc/handlers/AccountObjects.cpp | 4 +- src/xrpld/rpc/handlers/AccountTx.cpp | 3 + src/xrpld/rpc/handlers/LedgerEntry.cpp | 66 + src/xrpld/rpc/handlers/Tx.cpp | 2 + 92 files changed, 7084 insertions(+), 1057 deletions(-) create mode 100644 include/xrpl/basics/MPTAmount.h create mode 100644 include/xrpl/protocol/Asset.h create mode 100644 include/xrpl/protocol/MPTIssue.h create mode 100644 src/libxrpl/basics/MPTAmount.cpp create mode 100644 src/libxrpl/protocol/Asset.cpp create mode 100644 src/libxrpl/protocol/MPTIssue.cpp create mode 100644 src/test/app/MPToken_test.cpp create mode 100644 src/test/jtx/impl/mpt.cpp create mode 100644 src/test/jtx/mpt.h create mode 100644 src/xrpld/app/tx/detail/MPTokenAuthorize.cpp create mode 100644 src/xrpld/app/tx/detail/MPTokenAuthorize.h create mode 100644 src/xrpld/app/tx/detail/MPTokenIssuanceCreate.cpp create mode 100644 src/xrpld/app/tx/detail/MPTokenIssuanceCreate.h create mode 100644 src/xrpld/app/tx/detail/MPTokenIssuanceDestroy.cpp create mode 100644 src/xrpld/app/tx/detail/MPTokenIssuanceDestroy.h create mode 100644 src/xrpld/app/tx/detail/MPTokenIssuanceSet.cpp create mode 100644 src/xrpld/app/tx/detail/MPTokenIssuanceSet.h create mode 100644 src/xrpld/rpc/MPTokenIssuanceID.h create mode 100644 src/xrpld/rpc/detail/MPTokenIssuanceID.cpp diff --git a/Builds/levelization/results/loops.txt b/Builds/levelization/results/loops.txt index ca01e0f5e82..669fb6bbe33 100644 --- a/Builds/levelization/results/loops.txt +++ b/Builds/levelization/results/loops.txt @@ -5,7 +5,7 @@ Loop: test.jtx test.unit_test test.unit_test == test.jtx Loop: xrpl.basics xrpl.json - xrpl.json ~= xrpl.basics + xrpl.json == xrpl.basics Loop: xrpld.app xrpld.core xrpld.app > xrpld.core diff --git a/include/xrpl/basics/MPTAmount.h b/include/xrpl/basics/MPTAmount.h new file mode 100644 index 00000000000..34f747a21be --- /dev/null +++ b/include/xrpl/basics/MPTAmount.h @@ -0,0 +1,166 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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_MPTAMOUNT_H_INCLUDED +#define RIPPLE_BASICS_MPTAMOUNT_H_INCLUDED + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +namespace ripple { + +class MPTAmount : private boost::totally_ordered, + private boost::additive, + private boost::equality_comparable, + private boost::additive +{ +public: + using value_type = std::int64_t; + +protected: + value_type value_; + +public: + MPTAmount() = default; + constexpr MPTAmount(MPTAmount const& other) = default; + constexpr MPTAmount& + operator=(MPTAmount const& other) = default; + + constexpr explicit MPTAmount(value_type value); + + constexpr MPTAmount& operator=(beast::Zero); + + MPTAmount& + operator+=(MPTAmount const& other); + + MPTAmount& + operator-=(MPTAmount const& other); + + MPTAmount + operator-() const; + + bool + operator==(MPTAmount const& other) const; + + bool + operator==(value_type other) const; + + bool + operator<(MPTAmount const& other) const; + + /** Returns true if the amount is not zero */ + explicit constexpr + operator bool() const noexcept; + + /** Return the sign of the amount */ + constexpr int + signum() const noexcept; + + /** Returns the underlying value. Code SHOULD NOT call this + function unless the type has been abstracted away, + e.g. in a templated function. + */ + constexpr value_type + value() const; + + static MPTAmount + minPositiveAmount(); +}; + +constexpr MPTAmount::MPTAmount(value_type value) : value_(value) +{ +} + +constexpr MPTAmount& +MPTAmount::operator=(beast::Zero) +{ + value_ = 0; + return *this; +} + +/** Returns true if the amount is not zero */ +constexpr MPTAmount::operator bool() const noexcept +{ + return value_ != 0; +} + +/** Return the sign of the amount */ +constexpr int +MPTAmount::signum() const noexcept +{ + return (value_ < 0) ? -1 : (value_ ? 1 : 0); +} + +/** Returns the underlying value. Code SHOULD NOT call this + function unless the type has been abstracted away, + e.g. in a templated function. +*/ +constexpr MPTAmount::value_type +MPTAmount::value() const +{ + return value_; +} + +inline std::string +to_string(MPTAmount const& amount) +{ + return std::to_string(amount.value()); +} + +inline MPTAmount +mulRatio( + MPTAmount const& amt, + std::uint32_t num, + std::uint32_t den, + bool roundUp) +{ + using namespace boost::multiprecision; + + if (!den) + Throw("division by zero"); + + int128_t const amt128(amt.value()); + auto const neg = amt.value() < 0; + auto const m = amt128 * num; + auto r = m / den; + if (m % den) + { + if (!neg && roundUp) + r += 1; + if (neg && !roundUp) + r -= 1; + } + if (r > std::numeric_limits::max()) + Throw("MPT mulRatio overflow"); + return MPTAmount(r.convert_to()); +} + +} // namespace ripple + +#endif // RIPPLE_BASICS_MPTAMOUNT_H_INCLUDED diff --git a/include/xrpl/basics/Number.h b/include/xrpl/basics/Number.h index 5856ef325dc..01b3adb22d4 100644 --- a/include/xrpl/basics/Number.h +++ b/include/xrpl/basics/Number.h @@ -20,6 +20,7 @@ #ifndef RIPPLE_BASICS_NUMBER_H_INCLUDED #define RIPPLE_BASICS_NUMBER_H_INCLUDED +#include #include #include #include @@ -52,6 +53,7 @@ class Number explicit constexpr Number(rep mantissa, int exponent, unchecked) noexcept; Number(XRPAmount const& x); + Number(MPTAmount const& x); constexpr rep mantissa() const noexcept; @@ -88,9 +90,16 @@ class Number static constexpr Number lowest() noexcept; + /** Conversions to Number are implicit and conversions away from Number + * are explicit. This design encourages and facilitates the use of Number + * as the preferred type for floating point arithmetic as it makes + * "mixed mode" more convenient, e.g. MPTAmount + Number. + */ explicit operator XRPAmount() const; // round to nearest, even on tie explicit + operator MPTAmount() const; // round to nearest, even on tie + explicit operator rep() const; // round to nearest, even on tie friend constexpr bool @@ -212,6 +221,10 @@ inline Number::Number(XRPAmount const& x) : Number{x.drops()} { } +inline Number::Number(MPTAmount const& x) : Number{x.value()} +{ +} + inline constexpr Number::rep Number::mantissa() const noexcept { diff --git a/include/xrpl/basics/XRPAmount.h b/include/xrpl/basics/XRPAmount.h index 9a322695168..30b194845c9 100644 --- a/include/xrpl/basics/XRPAmount.h +++ b/include/xrpl/basics/XRPAmount.h @@ -207,6 +207,10 @@ class XRPAmount : private boost::totally_ordered, return dropsAs().value_or(defaultValue.drops()); } + /* Clips a 64-bit value to a 32-bit JSON number. It is only used + * in contexts that don't expect the value to ever approach + * the 32-bit limits (i.e. fees and reserves). + */ Json::Value jsonClipped() const { diff --git a/include/xrpl/basics/base_uint.h b/include/xrpl/basics/base_uint.h index 88d21c17d22..ae5aa17a63e 100644 --- a/include/xrpl/basics/base_uint.h +++ b/include/xrpl/basics/base_uint.h @@ -549,6 +549,7 @@ class base_uint using uint128 = base_uint<128>; using uint160 = base_uint<160>; using uint256 = base_uint<256>; +using uint192 = base_uint<192>; template [[nodiscard]] inline constexpr std::strong_ordering @@ -634,6 +635,7 @@ operator<<(std::ostream& out, base_uint const& u) #ifndef __INTELLISENSE__ static_assert(sizeof(uint128) == 128 / 8, "There should be no padding bytes"); static_assert(sizeof(uint160) == 160 / 8, "There should be no padding bytes"); +static_assert(sizeof(uint192) == 192 / 8, "There should be no padding bytes"); static_assert(sizeof(uint256) == 256 / 8, "There should be no padding bytes"); #endif diff --git a/include/xrpl/protocol/AmountConversions.h b/include/xrpl/protocol/AmountConversions.h index 0348e3c975d..270d009b916 100644 --- a/include/xrpl/protocol/AmountConversions.h +++ b/include/xrpl/protocol/AmountConversions.h @@ -33,13 +33,7 @@ toSTAmount(IOUAmount const& iou, Issue const& iss) { bool const isNeg = iou.signum() < 0; std::uint64_t const umant = isNeg ? -iou.mantissa() : iou.mantissa(); - return STAmount( - iss, - umant, - iou.exponent(), - /*native*/ false, - isNeg, - STAmount::unchecked()); + return STAmount(iss, umant, iou.exponent(), isNeg, STAmount::unchecked()); } inline STAmount diff --git a/include/xrpl/protocol/Asset.h b/include/xrpl/protocol/Asset.h new file mode 100644 index 00000000000..bfb72ab61fc --- /dev/null +++ b/include/xrpl/protocol/Asset.h @@ -0,0 +1,177 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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_PROTOCOL_ASSET_H_INCLUDED +#define RIPPLE_PROTOCOL_ASSET_H_INCLUDED + +#include +#include +#include + +namespace ripple { + +template +concept ValidIssueType = + std::is_same_v || std::is_same_v; + +/* Asset is an abstraction of three different issue types: XRP, IOU, MPT. + * For historical reasons, two issue types XRP and IOU are wrapped in Issue + * type. Many functions and classes there were first written for Issue + * have been rewritten for Asset. + */ +class Asset +{ +private: + using value_type = std::variant; + value_type issue_; + +public: + Asset() = default; + + /** Conversions to Asset are implicit and conversions to specific issue + * type are explicit. This design facilitates the use of Asset. + */ + Asset(Issue const& issue) : issue_(issue) + { + } + + Asset(MPTIssue const& mptIssue) : issue_(mptIssue) + { + } + + Asset(MPTID const& issuanceID) : issue_(MPTIssue{issuanceID}) + { + } + + AccountID const& + getIssuer() const; + + template + constexpr TIss const& + get() const; + + template + TIss& + get(); + + template + constexpr bool + holds() const; + + std::string + getText() const; + + constexpr value_type const& + value() const; + + void + setJson(Json::Value& jv) const; + + bool + native() const + { + return holds() && get().native(); + } + + friend constexpr bool + operator==(Asset const& lhs, Asset const& rhs); + + friend constexpr bool + operator!=(Asset const& lhs, Asset const& rhs); + + friend constexpr bool + operator==(Currency const& lhs, Asset const& rhs); +}; + +template +constexpr bool +Asset::holds() const +{ + return std::holds_alternative(issue_); +} + +template +constexpr TIss const& +Asset::get() const +{ + if (!std::holds_alternative(issue_)) + Throw("Asset is not a requested issue"); + return std::get(issue_); +} + +template +TIss& +Asset::get() +{ + if (!std::holds_alternative(issue_)) + Throw("Asset is not a requested issue"); + return std::get(issue_); +} + +constexpr Asset::value_type const& +Asset::value() const +{ + return issue_; +} + +constexpr bool +operator==(Asset const& lhs, Asset const& rhs) +{ + return std::visit( + [&]( + TLhs const& issLhs, TRhs const& issRhs) { + if constexpr (std::is_same_v) + return issLhs == issRhs; + else + return false; + }, + lhs.issue_, + rhs.issue_); +} + +constexpr bool +operator!=(Asset const& lhs, Asset const& rhs) +{ + return !(lhs == rhs); +} + +constexpr bool +operator==(Currency const& lhs, Asset const& rhs) +{ + return rhs.holds() && rhs.get().currency == lhs; +} + +inline bool +isXRP(Asset const& asset) +{ + return asset.native(); +} + +std::string +to_string(Asset const& asset); + +bool +validJSONAsset(Json::Value const& jv); + +Asset +assetFromJson(Json::Value const& jv); + +} // namespace ripple + +#endif // RIPPLE_PROTOCOL_ASSET_H_INCLUDED diff --git a/include/xrpl/protocol/Feature.h b/include/xrpl/protocol/Feature.h index 5537c543d6f..eb975f39ae0 100644 --- a/include/xrpl/protocol/Feature.h +++ b/include/xrpl/protocol/Feature.h @@ -80,7 +80,7 @@ namespace detail { // Feature.cpp. Because it's only used to reserve storage, and determine how // large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than // the actual number of amendments. A LogicError on startup will verify this. -static constexpr std::size_t numFeatures = 79; +static constexpr std::size_t numFeatures = 80; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated diff --git a/include/xrpl/protocol/Indexes.h b/include/xrpl/protocol/Indexes.h index f179bbacfab..8249eabb43a 100644 --- a/include/xrpl/protocol/Indexes.h +++ b/include/xrpl/protocol/Indexes.h @@ -287,6 +287,30 @@ did(AccountID const& account) noexcept; Keylet oracle(AccountID const& account, std::uint32_t const& documentID) noexcept; +Keylet +mptIssuance(std::uint32_t seq, AccountID const& issuer) noexcept; + +Keylet +mptIssuance(MPTID const& issuanceID) noexcept; + +inline Keylet +mptIssuance(uint256 const& issuanceKey) +{ + return {ltMPTOKEN_ISSUANCE, issuanceKey}; +} + +Keylet +mptoken(MPTID const& issuanceID, AccountID const& holder) noexcept; + +inline Keylet +mptoken(uint256 const& mptokenKey) +{ + return {ltMPTOKEN, mptokenKey}; +} + +Keylet +mptoken(uint256 const& issuanceKey, AccountID const& holder) noexcept; + } // namespace keylet // Everything below is deprecated and should be removed in favor of keylets: @@ -327,6 +351,9 @@ std::array, 6> const directAccountKeylets{ {&keylet::nftpage_max, jss::NFTokenPage, true}, {&keylet::did, jss::DID, true}}}; +MPTID +makeMptID(std::uint32_t sequence, AccountID const& account); + } // namespace ripple #endif diff --git a/include/xrpl/protocol/Issue.h b/include/xrpl/protocol/Issue.h index a18502f2138..335dd91354a 100644 --- a/include/xrpl/protocol/Issue.h +++ b/include/xrpl/protocol/Issue.h @@ -38,16 +38,26 @@ class Issue Currency currency{}; AccountID account{}; - Issue() + Issue() = default; + + Issue(Currency const& c, AccountID const& a) : currency(c), account(a) { } - Issue(Currency const& c, AccountID const& a) : currency(c), account(a) + AccountID const& + getIssuer() const { + return account; } std::string getText() const; + + void + setJson(Json::Value& jv) const; + + bool + native() const; }; bool @@ -116,6 +126,12 @@ noIssue() return issue; } +inline bool +isXRP(Issue const& issue) +{ + return issue.native(); +} + } // namespace ripple #endif diff --git a/include/xrpl/protocol/LedgerFormats.h b/include/xrpl/protocol/LedgerFormats.h index 14fcaa673ab..b0374db1c29 100644 --- a/include/xrpl/protocol/LedgerFormats.h +++ b/include/xrpl/protocol/LedgerFormats.h @@ -174,6 +174,18 @@ enum LedgerSpecificFlags { // ltNFTOKEN_OFFER lsfSellNFToken = 0x00000001, + + // ltMPTOKEN_ISSUANCE + lsfMPTLocked = 0x00000001, // Also used in ltMPTOKEN + lsfMPTCanLock = 0x00000002, + lsfMPTRequireAuth = 0x00000004, + lsfMPTCanEscrow = 0x00000008, + lsfMPTCanTrade = 0x00000010, + lsfMPTCanTransfer = 0x00000020, + lsfMPTCanClawback = 0x00000040, + + // ltMPTOKEN + lsfMPTAuthorized = 0x00000002, }; //------------------------------------------------------------------------------ diff --git a/include/xrpl/protocol/MPTIssue.h b/include/xrpl/protocol/MPTIssue.h new file mode 100644 index 00000000000..06f55686caf --- /dev/null +++ b/include/xrpl/protocol/MPTIssue.h @@ -0,0 +1,98 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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_PROTOCOL_MPTISSUE_H_INCLUDED +#define RIPPLE_PROTOCOL_MPTISSUE_H_INCLUDED + +#include +#include + +namespace ripple { + +/* Adapt MPTID to provide the same interface as Issue. Enables using static + * polymorphism by Asset and other classes. MPTID is a 192-bit concatenation + * of a 32-bit account sequence and a 160-bit account id. + */ +class MPTIssue +{ +private: + MPTID mptID_; + +public: + MPTIssue() = default; + + explicit MPTIssue(MPTID const& issuanceID); + + AccountID const& + getIssuer() const; + + MPTID const& + getMptID() const; + + std::string + getText() const; + + void + setJson(Json::Value& jv) const; + + friend constexpr bool + operator==(MPTIssue const& lhs, MPTIssue const& rhs); + + friend constexpr bool + operator!=(MPTIssue const& lhs, MPTIssue const& rhs); + + bool + native() const + { + return false; + } +}; + +constexpr bool +operator==(MPTIssue const& lhs, MPTIssue const& rhs) +{ + return lhs.mptID_ == rhs.mptID_; +} + +constexpr bool +operator!=(MPTIssue const& lhs, MPTIssue const& rhs) +{ + return !(lhs == rhs); +} + +/** MPT is a non-native token. + */ +inline bool +isXRP(MPTID const&) +{ + return false; +} + +Json::Value +to_json(MPTIssue const& mptIssue); + +std::string +to_string(MPTIssue const& mptIssue); + +MPTIssue +mptIssueFromJson(Json::Value const& jv); + +} // namespace ripple + +#endif // RIPPLE_PROTOCOL_MPTISSUE_H_INCLUDED diff --git a/include/xrpl/protocol/Protocol.h b/include/xrpl/protocol/Protocol.h index 8d8a71dfef8..f706b6a3bbb 100644 --- a/include/xrpl/protocol/Protocol.h +++ b/include/xrpl/protocol/Protocol.h @@ -95,6 +95,12 @@ std::size_t constexpr maxDIDAttestationLength = 256; /** The maximum length of a domain */ std::size_t constexpr maxDomainLength = 256; +/** The maximum length of MPTokenMetadata */ +std::size_t constexpr maxMPTokenMetadataLength = 1024; + +/** The maximum amount of MPTokenIssuance */ +std::uint64_t constexpr maxMPTokenAmount = 0x7FFF'FFFF'FFFF'FFFFull; + /** A ledger index. */ using LedgerIndex = std::uint32_t; diff --git a/include/xrpl/protocol/Rate.h b/include/xrpl/protocol/Rate.h index b065acb2316..6970d9c16a8 100644 --- a/include/xrpl/protocol/Rate.h +++ b/include/xrpl/protocol/Rate.h @@ -74,7 +74,7 @@ STAmount multiplyRound( STAmount const& amount, Rate const& rate, - Issue const& issue, + Asset const& asset, bool roundUp); STAmount @@ -87,7 +87,7 @@ STAmount divideRound( STAmount const& amount, Rate const& rate, - Issue const& issue, + Asset const& asset, bool roundUp); namespace nft { diff --git a/include/xrpl/protocol/SField.h b/include/xrpl/protocol/SField.h index c370239ca19..942f2a8654b 100644 --- a/include/xrpl/protocol/SField.h +++ b/include/xrpl/protocol/SField.h @@ -148,6 +148,7 @@ class SField sMD_DeleteFinal = 0x04, // final value when it is deleted sMD_Create = 0x08, // value when it's created sMD_Always = 0x10, // value when node containing it is affected at all + sMD_BaseTen = 0x20, sMD_Default = sMD_ChangeOrig | sMD_ChangeNew | sMD_DeleteFinal | sMD_Create }; diff --git a/include/xrpl/protocol/SOTemplate.h b/include/xrpl/protocol/SOTemplate.h index c0fcfb64358..95cd35fead2 100644 --- a/include/xrpl/protocol/SOTemplate.h +++ b/include/xrpl/protocol/SOTemplate.h @@ -39,6 +39,9 @@ enum SOEStyle { // constructed with STObject::makeInnerObject() }; +/** Amount fields that can support MPT */ +enum SOETxMPTAmount { soeMPTNone, soeMPTSupported, soeMPTNotSupported }; + //------------------------------------------------------------------------------ /** An element in a SOTemplate. */ @@ -47,10 +50,11 @@ class SOElement // Use std::reference_wrapper so SOElement can be stored in a std::vector. std::reference_wrapper sField_; SOEStyle style_; + SOETxMPTAmount supportMpt_ = soeMPTNone; -public: - SOElement(SField const& fieldName, SOEStyle style) - : sField_(fieldName), style_(style) +private: + void + init(SField const& fieldName) const { if (!sField_.get().isUseful()) { @@ -62,6 +66,21 @@ class SOElement } } +public: + SOElement(SField const& fieldName, SOEStyle style) + : sField_(fieldName), style_(style) + { + init(fieldName); + } + SOElement( + TypedField const& fieldName, + SOEStyle style, + SOETxMPTAmount supportMpt = soeMPTNotSupported) + : sField_(fieldName), style_(style), supportMpt_(supportMpt) + { + init(fieldName); + } + SField const& sField() const { @@ -73,6 +92,12 @@ class SOElement { return style_; } + + SOETxMPTAmount + supportMPT() const + { + return supportMpt_; + } }; //------------------------------------------------------------------------------ diff --git a/include/xrpl/protocol/STAmount.h b/include/xrpl/protocol/STAmount.h index 34f82d4cebb..e0a6c1eca08 100644 --- a/include/xrpl/protocol/STAmount.h +++ b/include/xrpl/protocol/STAmount.h @@ -23,9 +23,10 @@ #include #include #include +#include #include #include -#include +#include #include #include #include @@ -33,6 +34,11 @@ namespace ripple { +template +concept AssetType = + std::is_same_v || std::is_convertible_v || + std::is_convertible_v || std::is_convertible_v; + // Internal form: // 1: If amount is zero, then value is zero and offset is -100 // 2: Otherwise: @@ -51,10 +57,9 @@ class STAmount final : public STBase, public CountedObject using rep = std::pair; private: - Issue mIssue; + Asset mAsset; mantissa_type mValue; exponent_type mOffset; - bool mIsNative; // A shorthand for isXRP(mIssue). bool mIsNegative; public: @@ -70,8 +75,10 @@ class STAmount final : public STBase, public CountedObject // Max native value on network. static const std::uint64_t cMaxNativeN = 100000000000000000ull; - static const std::uint64_t cNotNative = 0x8000000000000000ull; - static const std::uint64_t cPosNative = 0x4000000000000000ull; + static const std::uint64_t cIssuedCurrency = 0x8000000000000000ull; + static const std::uint64_t cPositive = 0x4000000000000000ull; + static const std::uint64_t cMPToken = 0x2000000000000000ull; + static const std::uint64_t cValueMask = ~(cPositive | cMPToken); static std::uint64_t const uRateOne; @@ -84,31 +91,31 @@ class STAmount final : public STBase, public CountedObject }; // Do not call canonicalize + template STAmount( SField const& name, - Issue const& issue, + A const& asset, mantissa_type mantissa, exponent_type exponent, - bool native, bool negative, unchecked); + template STAmount( - Issue const& issue, + A const& asset, mantissa_type mantissa, exponent_type exponent, - bool native, bool negative, unchecked); // Call canonicalize + template STAmount( SField const& name, - Issue const& issue, - mantissa_type mantissa, - exponent_type exponent, - bool native, - bool negative); + A const& asset, + mantissa_type mantissa = 0, + exponent_type exponent = 0, + bool negative = false); STAmount(SField const& name, std::int64_t mantissa); @@ -117,37 +124,42 @@ class STAmount final : public STBase, public CountedObject std::uint64_t mantissa = 0, bool negative = false); - STAmount( - SField const& name, - Issue const& issue, - std::uint64_t mantissa = 0, - int exponent = 0, - bool negative = false); - explicit STAmount(std::uint64_t mantissa = 0, bool negative = false); explicit STAmount(SField const& name, STAmount const& amt); + template STAmount( - Issue const& issue, + A const& asset, std::uint64_t mantissa = 0, int exponent = 0, - bool negative = false); + bool negative = false) + : mAsset(asset) + , mValue(mantissa) + , mOffset(exponent) + , mIsNegative(negative) + { + canonicalize(); + } // VFALCO Is this needed when we have the previous signature? + template STAmount( - Issue const& issue, + A const& asset, std::uint32_t mantissa, int exponent = 0, bool negative = false); - STAmount(Issue const& issue, std::int64_t mantissa, int exponent = 0); + template + STAmount(A const& asset, std::int64_t mantissa, int exponent = 0); - STAmount(Issue const& issue, int mantissa, int exponent = 0); + template + STAmount(A const& asset, int mantissa, int exponent = 0); // Legacy support for new-style amounts STAmount(IOUAmount const& amount, Issue const& issue); STAmount(XRPAmount const& amount); + STAmount(MPTAmount const& amount, MPTIssue const& mptIssue); operator Number() const; //-------------------------------------------------------------------------- @@ -162,12 +174,23 @@ class STAmount final : public STBase, public CountedObject bool native() const noexcept; + template + constexpr bool + holds() const noexcept; + bool negative() const noexcept; std::uint64_t mantissa() const noexcept; + Asset const& + asset() const; + + template + constexpr TIss const& + get() const; + Issue const& issue() const; @@ -224,17 +247,14 @@ class STAmount final : public STBase, public CountedObject // Zero while copying currency and issuer. void - clear(STAmount const& saTmpl); - - void - clear(Issue const& issue); + clear(Asset const& asset); void setIssuer(AccountID const& uIssuer); - /** Set the Issue for this amount and update mIsNative. */ + /** Set the Issue for this amount. */ void - setIssue(Issue const& issue); + setIssue(Asset const& asset); //-------------------------------------------------------------------------- // @@ -266,6 +286,8 @@ class STAmount final : public STBase, public CountedObject xrp() const; IOUAmount iou() const; + MPTAmount + mpt() const; private: static std::unique_ptr @@ -290,6 +312,100 @@ class STAmount final : public STBase, public CountedObject operator+(STAmount const& v1, STAmount const& v2); }; +template +STAmount::STAmount( + SField const& name, + A const& asset, + mantissa_type mantissa, + exponent_type exponent, + bool negative, + unchecked) + : STBase(name) + , mAsset(asset) + , mValue(mantissa) + , mOffset(exponent) + , mIsNegative(negative) +{ +} + +template +STAmount::STAmount( + A const& asset, + mantissa_type mantissa, + exponent_type exponent, + bool negative, + unchecked) + : mAsset(asset), mValue(mantissa), mOffset(exponent), mIsNegative(negative) +{ +} + +template +STAmount::STAmount( + SField const& name, + A const& asset, + std::uint64_t mantissa, + int exponent, + bool negative) + : STBase(name) + , mAsset(asset) + , mValue(mantissa) + , mOffset(exponent) + , mIsNegative(negative) +{ + // mValue is uint64, but needs to fit in the range of int64 + assert(mValue <= std::numeric_limits::max()); + canonicalize(); +} + +template +STAmount::STAmount(A const& asset, std::int64_t mantissa, int exponent) + : mAsset(asset), mOffset(exponent) +{ + set(mantissa); + canonicalize(); +} + +template +STAmount::STAmount( + A const& asset, + std::uint32_t mantissa, + int exponent, + bool negative) + : STAmount(asset, safe_cast(mantissa), exponent, negative) +{ +} + +template +STAmount::STAmount(A const& asset, int mantissa, int exponent) + : STAmount(asset, safe_cast(mantissa), exponent) +{ +} + +// Legacy support for new-style amounts +inline STAmount::STAmount(IOUAmount const& amount, Issue const& issue) + : mAsset(issue) + , mOffset(amount.exponent()) + , mIsNegative(amount < beast::zero) +{ + if (mIsNegative) + mValue = unsafe_cast(-amount.mantissa()); + else + mValue = unsafe_cast(amount.mantissa()); + + canonicalize(); +} + +inline STAmount::STAmount(MPTAmount const& amount, MPTIssue const& mptIssue) + : mAsset(mptIssue), mOffset(0), mIsNegative(amount < beast::zero) +{ + if (mIsNegative) + mValue = unsafe_cast(-amount.value()); + else + mValue = unsafe_cast(amount.value()); + + canonicalize(); +} + //------------------------------------------------------------------------------ // // Creation @@ -301,7 +417,7 @@ STAmount amountFromQuality(std::uint64_t rate); STAmount -amountFromString(Issue const& issue, std::string const& amount); +amountFromString(Asset const& issue, std::string const& amount); STAmount amountFromJson(SField const& name, Json::Value const& v); @@ -332,7 +448,14 @@ STAmount::exponent() const noexcept inline bool STAmount::native() const noexcept { - return mIsNative; + return mAsset.native(); +} + +template +constexpr bool +STAmount::holds() const noexcept +{ + return mAsset.holds(); } inline bool @@ -347,22 +470,35 @@ STAmount::mantissa() const noexcept return mValue; } +inline Asset const& +STAmount::asset() const +{ + return mAsset; +} + +template +constexpr TIss const& +STAmount::get() const +{ + return mAsset.get(); +} + inline Issue const& STAmount::issue() const { - return mIssue; + return get(); } inline Currency const& STAmount::getCurrency() const { - return mIssue.currency; + return mAsset.get().currency; } inline AccountID const& STAmount::getIssuer() const { - return mIssue.account; + return mAsset.getIssuer(); } inline int @@ -374,7 +510,7 @@ STAmount::signum() const noexcept inline STAmount STAmount::zeroed() const { - return STAmount(mIssue); + return STAmount(mAsset); } inline STAmount::operator bool() const noexcept @@ -384,8 +520,10 @@ inline STAmount::operator bool() const noexcept inline STAmount::operator Number() const { - if (mIsNative) + if (native()) return xrp(); + if (mAsset.holds()) + return mpt(); return iou(); } @@ -415,30 +553,22 @@ STAmount::clear() { // The -100 is used to allow 0 to sort less than a small positive values // which have a negative exponent. - mOffset = mIsNative ? 0 : -100; + mOffset = native() ? 0 : -100; mValue = 0; mIsNegative = false; } -// Zero while copying currency and issuer. -inline void -STAmount::clear(STAmount const& saTmpl) -{ - clear(saTmpl.mIssue); -} - inline void -STAmount::clear(Issue const& issue) +STAmount::clear(Asset const& asset) { - setIssue(issue); + setIssue(asset); clear(); } inline void STAmount::setIssuer(AccountID const& uIssuer) { - mIssue.account = uIssuer; - setIssue(mIssue); + mAsset.get().account = uIssuer; } inline STAmount const& @@ -503,17 +633,17 @@ STAmount operator-(STAmount const& v1, STAmount const& v2); STAmount -divide(STAmount const& v1, STAmount const& v2, Issue const& issue); +divide(STAmount const& v1, STAmount const& v2, Asset const& asset); STAmount -multiply(STAmount const& v1, STAmount const& v2, Issue const& issue); +multiply(STAmount const& v1, STAmount const& v2, Asset const& asset); // multiply rounding result in specified direction STAmount mulRound( STAmount const& v1, STAmount const& v2, - Issue const& issue, + Asset const& asset, bool roundUp); // multiply following the rounding directions more precisely. @@ -521,7 +651,7 @@ STAmount mulRoundStrict( STAmount const& v1, STAmount const& v2, - Issue const& issue, + Asset const& asset, bool roundUp); // divide rounding result in specified direction @@ -529,7 +659,7 @@ STAmount divRound( STAmount const& v1, STAmount const& v2, - Issue const& issue, + Asset const& asset, bool roundUp); // divide following the rounding directions more precisely. @@ -537,7 +667,7 @@ STAmount divRoundStrict( STAmount const& v1, STAmount const& v2, - Issue const& issue, + Asset const& asset, bool roundUp); // Someone is offering X for Y, what is the rate? @@ -551,7 +681,7 @@ getRate(STAmount const& offerOut, STAmount const& offerIn); inline bool isXRP(STAmount const& amount) { - return isXRP(amount.issue().currency); + return amount.native(); } // Since `canonicalize` does not have access to a ledger, this is needed to put diff --git a/include/xrpl/protocol/STBitString.h b/include/xrpl/protocol/STBitString.h index 7dc92303e72..f3a74f2fc54 100644 --- a/include/xrpl/protocol/STBitString.h +++ b/include/xrpl/protocol/STBitString.h @@ -84,6 +84,7 @@ class STBitString final : public STBase, public CountedObject> using STUInt128 = STBitString<128>; using STUInt160 = STBitString<160>; +using STUInt192 = STBitString<192>; using STUInt256 = STBitString<256>; template @@ -136,6 +137,13 @@ STUInt160::getSType() const return STI_UINT160; } +template <> +inline SerializedTypeID +STUInt192::getSType() const +{ + return STI_UINT192; +} + template <> inline SerializedTypeID STUInt256::getSType() const diff --git a/include/xrpl/protocol/STObject.h b/include/xrpl/protocol/STObject.h index a226733e986..c06f109dc56 100644 --- a/include/xrpl/protocol/STObject.h +++ b/include/xrpl/protocol/STObject.h @@ -226,6 +226,8 @@ class STObject : public STBase, public CountedObject uint160 getFieldH160(SField const& field) const; + uint192 + getFieldH192(SField const& field) const; uint256 getFieldH256(SField const& field) const; AccountID @@ -498,6 +500,11 @@ class STObject::Proxy assign(U&& u); }; +// Constraint += and -= ValueProxy operators +// to value types that support arithmetic operations +template +concept IsArithmetic = std::is_arithmetic_v || std::is_same_v; + template class STObject::ValueProxy : private Proxy { @@ -513,6 +520,16 @@ class STObject::ValueProxy : private Proxy std::enable_if_t, ValueProxy&> operator=(U&& u); + // Convenience operators for value types supporting + // arithmetic operations + template + ValueProxy& + operator+=(U const& u); + + template + ValueProxy& + operator-=(U const& u); + operator value_type() const; private: @@ -731,6 +748,24 @@ STObject::ValueProxy::operator=(U&& u) return *this; } +template +template +STObject::ValueProxy& +STObject::ValueProxy::operator+=(U const& u) +{ + this->assign(this->value() + u); + return *this; +} + +template +template +STObject::ValueProxy& +STObject::ValueProxy::operator-=(U const& u) +{ + this->assign(this->value() - u); + return *this; +} + template STObject::ValueProxy::operator value_type() const { diff --git a/include/xrpl/protocol/Serializer.h b/include/xrpl/protocol/Serializer.h index b85e8eb013d..d8d0b9222e3 100644 --- a/include/xrpl/protocol/Serializer.h +++ b/include/xrpl/protocol/Serializer.h @@ -373,6 +373,12 @@ class SerialIter return getBitString<160>(); } + uint192 + get192() + { + return getBitString<192>(); + } + uint256 get256() { diff --git a/include/xrpl/protocol/TER.h b/include/xrpl/protocol/TER.h index 5b659249dfd..cf297b0c37b 100644 --- a/include/xrpl/protocol/TER.h +++ b/include/xrpl/protocol/TER.h @@ -139,6 +139,8 @@ enum TEMcodes : TERUnderlyingType { temARRAY_EMPTY, temARRAY_TOO_LARGE, + + temBAD_TRANSFER_FEE, }; //------------------------------------------------------------------------------ @@ -339,7 +341,8 @@ enum TECcodes : TERUnderlyingType { tecINVALID_UPDATE_TIME = 188, tecTOKEN_PAIR_NOT_FOUND = 189, tecARRAY_EMPTY = 190, - tecARRAY_TOO_LARGE = 191 + tecARRAY_TOO_LARGE = 191, + tecLOCKED = 192, }; //------------------------------------------------------------------------------ diff --git a/include/xrpl/protocol/TxFlags.h b/include/xrpl/protocol/TxFlags.h index ba2b97562db..4894f48a7f9 100644 --- a/include/xrpl/protocol/TxFlags.h +++ b/include/xrpl/protocol/TxFlags.h @@ -22,6 +22,8 @@ #include +#include + namespace ripple { /** Transaction flags. @@ -104,6 +106,7 @@ constexpr std::uint32_t tfPartialPayment = 0x00020000; constexpr std::uint32_t tfLimitQuality = 0x00040000; constexpr std::uint32_t tfPaymentMask = ~(tfUniversal | tfPartialPayment | tfLimitQuality | tfNoRippleDirect); +constexpr std::uint32_t tfMPTPaymentMask = ~(tfUniversal | tfPartialPayment); // TrustSet flags: constexpr std::uint32_t tfSetfAuth = 0x00010000; @@ -130,6 +133,29 @@ constexpr std::uint32_t const tfOnlyXRP = 0x00000002; constexpr std::uint32_t const tfTrustLine = 0x00000004; constexpr std::uint32_t const tfTransferable = 0x00000008; +// MPTokenIssuanceCreate flags: +// NOTE - there is intentionally no flag here for lsfMPTLocked, which this transaction cannot mutate. +constexpr std::uint32_t const tfMPTCanLock = lsfMPTCanLock; +constexpr std::uint32_t const tfMPTRequireAuth = lsfMPTRequireAuth; +constexpr std::uint32_t const tfMPTCanEscrow = lsfMPTCanEscrow; +constexpr std::uint32_t const tfMPTCanTrade = lsfMPTCanTrade; +constexpr std::uint32_t const tfMPTCanTransfer = lsfMPTCanTransfer; +constexpr std::uint32_t const tfMPTCanClawback = lsfMPTCanClawback; +constexpr std::uint32_t const tfMPTokenIssuanceCreateMask = + ~(tfUniversal | tfMPTCanLock | tfMPTRequireAuth | tfMPTCanEscrow | tfMPTCanTrade | tfMPTCanTransfer | tfMPTCanClawback); + +// MPTokenAuthorize flags: +constexpr std::uint32_t const tfMPTUnauthorize = 0x00000001; +constexpr std::uint32_t const tfMPTokenAuthorizeMask = ~(tfUniversal | tfMPTUnauthorize); + +// MPTokenIssuanceSet flags: +constexpr std::uint32_t const tfMPTLock = 0x00000001; +constexpr std::uint32_t const tfMPTUnlock = 0x00000002; +constexpr std::uint32_t const tfMPTokenIssuanceSetMask = ~(tfUniversal | tfMPTLock | tfMPTUnlock); + +// MPTokenIssuanceDestroy flags: +constexpr std::uint32_t const tfMPTokenIssuanceDestroyMask = ~tfUniversal; + // Prior to fixRemoveNFTokenAutoTrustLine, transfer of an NFToken between // accounts allowed a TrustLine to be added to the issuer of that token // without explicit permission from that issuer. This was enabled by @@ -184,7 +210,6 @@ constexpr std::uint32_t tfDepositMask = ~(tfUniversal | tfDepositSubTx); // BridgeModify flags: constexpr std::uint32_t tfClearAccountCreateAmount = 0x00010000; constexpr std::uint32_t tfBridgeModifyMask = ~(tfUniversal | tfClearAccountCreateAmount); - // clang-format on } // namespace ripple diff --git a/include/xrpl/protocol/UintTypes.h b/include/xrpl/protocol/UintTypes.h index a0a8069f669..cf676189bad 100644 --- a/include/xrpl/protocol/UintTypes.h +++ b/include/xrpl/protocol/UintTypes.h @@ -58,6 +58,11 @@ using Currency = base_uint<160, detail::CurrencyTag>; /** NodeID is a 160-bit hash representing one node. */ using NodeID = base_uint<160, detail::NodeIDTag>; +/** MPTID is a 192-bit value representing MPT Issuance ID, + * which is a concatenation of a 32-bit sequence (big endian) + * and a 160-bit account */ +using MPTID = base_uint<192>; + /** XRP currency. */ Currency const& xrpCurrency(); diff --git a/include/xrpl/protocol/detail/STVar.h b/include/xrpl/protocol/detail/STVar.h index bee48aa53f6..4a830cf8d7c 100644 --- a/include/xrpl/protocol/detail/STVar.h +++ b/include/xrpl/protocol/detail/STVar.h @@ -23,8 +23,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -44,6 +46,19 @@ struct nonPresentObject_t extern defaultObject_t defaultObject; extern nonPresentObject_t nonPresentObject; +// Concept to constrain STVar constructors, which +// instantiate ST* types from SerializedTypeID +// clang-format off +template +concept ValidConstructSTArgs = + (std::is_same_v< + std::tuple...>, + std::tuple> || + std::is_same_v< + std::tuple...>, + std::tuple>); +// clang-format on + // "variant" that can hold any type of serialized object // and includes a small-object allocation optimization. class STVar @@ -131,6 +146,15 @@ class STVar p_ = new (&d_) T(std::forward(args)...); } + /** Construct requested Serializable Type according to id. + * The variadic args are: (SField), or (SerialIter, SField). + * depth is ignored in former case. + */ + template + requires ValidConstructSTArgs + void + constructST(SerializedTypeID id, int depth, Args&&... arg); + bool on_heap() const { diff --git a/include/xrpl/protocol/detail/features.macro b/include/xrpl/protocol/detail/features.macro index 159bc3720b7..3a8d77e2bab 100644 --- a/include/xrpl/protocol/detail/features.macro +++ b/include/xrpl/protocol/detail/features.macro @@ -31,7 +31,8 @@ // InvariantsV1_1 will be changes to Supported::yes when all the // invariants expected to be included under it are complete. -XRPL_FEATURE(InvariantsV1_1, Supported::no, VoteBehavior::DefaultNo) +XRPL_FEATURE(MPTokensV1, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(InvariantsV1_1, Supported::no, VoteBehavior::DefaultNo) XRPL_FIX (NFTokenPageLinks, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (InnerObjTemplate2, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (EnforceNFTokenTrustline, Supported::yes, VoteBehavior::DefaultNo) diff --git a/include/xrpl/protocol/detail/ledger_entries.macro b/include/xrpl/protocol/detail/ledger_entries.macro index 359000cbbf3..3c23539593d 100644 --- a/include/xrpl/protocol/detail/ledger_entries.macro +++ b/include/xrpl/protocol/detail/ledger_entries.macro @@ -392,3 +392,31 @@ LEDGER_ENTRY(ltORACLE, 0x0080, Oracle, ({ {sfPreviousTxnID, soeREQUIRED}, {sfPreviousTxnLgrSeq, soeREQUIRED}, })) + +/** A ledger object which tracks MPTokenIssuance + \sa keylet::mptIssuance + */ +LEDGER_ENTRY(ltMPTOKEN_ISSUANCE, 0x007e, MPTokenIssuance, ({ + {sfIssuer, soeREQUIRED}, + {sfSequence, soeREQUIRED}, + {sfTransferFee, soeDEFAULT}, + {sfOwnerNode, soeREQUIRED}, + {sfAssetScale, soeDEFAULT}, + {sfMaximumAmount, soeOPTIONAL}, + {sfOutstandingAmount, soeREQUIRED}, + {sfMPTokenMetadata, soeOPTIONAL}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, +})) + +/** A ledger object which tracks MPToken + \sa keylet::mptoken + */ +LEDGER_ENTRY(ltMPTOKEN, 0x007f, MPToken, ({ + {sfAccount, soeREQUIRED}, + {sfMPTokenIssuanceID, soeREQUIRED}, + {sfMPTAmount, soeDEFAULT}, + {sfOwnerNode, soeREQUIRED}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, +})) diff --git a/include/xrpl/protocol/detail/sfields.macro b/include/xrpl/protocol/detail/sfields.macro index bdfcf5dfafd..e3a93fc7f46 100644 --- a/include/xrpl/protocol/detail/sfields.macro +++ b/include/xrpl/protocol/detail/sfields.macro @@ -35,6 +35,7 @@ TYPED_SFIELD(sfCloseResolution, UINT8, 1) TYPED_SFIELD(sfMethod, UINT8, 2) TYPED_SFIELD(sfTransactionResult, UINT8, 3) TYPED_SFIELD(sfScale, UINT8, 4) +TYPED_SFIELD(sfAssetScale, UINT8, 5) // 8-bit integers (uncommon) TYPED_SFIELD(sfTickSize, UINT8, 16) @@ -136,6 +137,9 @@ TYPED_SFIELD(sfXChainClaimID, UINT64, 20) TYPED_SFIELD(sfXChainAccountCreateCount, UINT64, 21) TYPED_SFIELD(sfXChainAccountClaimCount, UINT64, 22) TYPED_SFIELD(sfAssetPrice, UINT64, 23) +TYPED_SFIELD(sfMaximumAmount, UINT64, 24, SField::sMD_BaseTen|SField::sMD_Default) +TYPED_SFIELD(sfOutstandingAmount, UINT64, 25, SField::sMD_BaseTen|SField::sMD_Default) +TYPED_SFIELD(sfMPTAmount, UINT64, 26, SField::sMD_BaseTen|SField::sMD_Default) // 128-bit TYPED_SFIELD(sfEmailHash, UINT128, 1) @@ -146,6 +150,9 @@ TYPED_SFIELD(sfTakerPaysIssuer, UINT160, 2) TYPED_SFIELD(sfTakerGetsCurrency, UINT160, 3) TYPED_SFIELD(sfTakerGetsIssuer, UINT160, 4) +// 192-bit (common) +TYPED_SFIELD(sfMPTokenIssuanceID, UINT192, 1) + // 256-bit (common) TYPED_SFIELD(sfLedgerHash, UINT256, 1) TYPED_SFIELD(sfParentHash, UINT256, 2) @@ -250,6 +257,7 @@ TYPED_SFIELD(sfDIDDocument, VL, 26) TYPED_SFIELD(sfData, VL, 27) TYPED_SFIELD(sfAssetClass, VL, 28) TYPED_SFIELD(sfProvider, VL, 29) +TYPED_SFIELD(sfMPTokenMetadata, VL, 30) // account (common) TYPED_SFIELD(sfAccount, ACCOUNT, 1) @@ -262,6 +270,7 @@ TYPED_SFIELD(sfUnauthorize, ACCOUNT, 6) TYPED_SFIELD(sfRegularKey, ACCOUNT, 8) TYPED_SFIELD(sfNFTokenMinter, ACCOUNT, 9) TYPED_SFIELD(sfEmitCallback, ACCOUNT, 10) +TYPED_SFIELD(sfHolder, ACCOUNT, 11) // account (uncommon) TYPED_SFIELD(sfHookAccount, ACCOUNT, 16) diff --git a/include/xrpl/protocol/detail/transactions.macro b/include/xrpl/protocol/detail/transactions.macro index 98678e9d509..30e27da4167 100644 --- a/include/xrpl/protocol/detail/transactions.macro +++ b/include/xrpl/protocol/detail/transactions.macro @@ -31,12 +31,12 @@ /** This transaction type executes a payment. */ TRANSACTION(ttPAYMENT, 0, Payment, ({ {sfDestination, soeREQUIRED}, - {sfAmount, soeREQUIRED}, - {sfSendMax, soeOPTIONAL}, + {sfAmount, soeREQUIRED, soeMPTSupported}, + {sfSendMax, soeOPTIONAL, soeMPTSupported}, {sfPaths, soeDEFAULT}, {sfInvoiceID, soeOPTIONAL}, {sfDestinationTag, soeOPTIONAL}, - {sfDeliverMin, soeOPTIONAL}, + {sfDeliverMin, soeOPTIONAL, soeMPTSupported}, })) /** This transaction type creates an escrow object. */ @@ -223,7 +223,8 @@ TRANSACTION(ttNFTOKEN_ACCEPT_OFFER, 29, NFTokenAcceptOffer, ({ /** This transaction claws back issued tokens. */ TRANSACTION(ttCLAWBACK, 30, Clawback, ({ - {sfAmount, soeREQUIRED}, + {sfAmount, soeREQUIRED, soeMPTSupported}, + {sfHolder, soeOPTIONAL}, })) /** This transaction type creates an AMM instance */ @@ -386,6 +387,31 @@ TRANSACTION(ttLEDGER_STATE_FIX, 53, LedgerStateFix, ({ {sfOwner, soeOPTIONAL}, })) +/** This transaction type creates a MPTokensIssuance instance */ +TRANSACTION(ttMPTOKEN_ISSUANCE_CREATE, 54, MPTokenIssuanceCreate, ({ + {sfAssetScale, soeOPTIONAL}, + {sfTransferFee, soeOPTIONAL}, + {sfMaximumAmount, soeOPTIONAL}, + {sfMPTokenMetadata, soeOPTIONAL}, +})) + +/** This transaction type destroys a MPTokensIssuance instance */ +TRANSACTION(ttMPTOKEN_ISSUANCE_DESTROY, 55, MPTokenIssuanceDestroy, ({ + {sfMPTokenIssuanceID, soeREQUIRED}, +})) + +/** This transaction type sets flags on a MPTokensIssuance or MPToken instance */ +TRANSACTION(ttMPTOKEN_ISSUANCE_SET, 56, MPTokenIssuanceSet, ({ + {sfMPTokenIssuanceID, soeREQUIRED}, + {sfHolder, soeOPTIONAL}, +})) + +/** This transaction type authorizes a MPToken instance */ +TRANSACTION(ttMPTOKEN_AUTHORIZE, 57, MPTokenAuthorize, ({ + {sfMPTokenIssuanceID, soeREQUIRED}, + {sfHolder, soeOPTIONAL}, +})) + /** This system-generated transaction type is used to update the status of the various amendments. For details, see: https://xrpl.org/amendments.html diff --git a/include/xrpl/protocol/jss.h b/include/xrpl/protocol/jss.h index 1e4e22cd73a..bafdde4fbcc 100644 --- a/include/xrpl/protocol/jss.h +++ b/include/xrpl/protocol/jss.h @@ -58,6 +58,8 @@ JSS(AssetPrice); // in: Oracle JSS(AuthAccount); // in: AMM Auction Slot JSS(AuthAccounts); // in: AMM Auction Slot JSS(BaseAsset); // in: Oracle +JSS(BidMax); // in: AMM Bid +JSS(BidMin); // in: AMM Bid JSS(Bridge); // ledger type. JSS(Check); // ledger type. JSS(ClearFlag); // field. @@ -76,8 +78,8 @@ JSS(LastLedgerSequence); // in: TransactionSign; field JSS(LastUpdateTime); // field. JSS(LedgerHashes); // ledger type. JSS(LimitAmount); // field. -JSS(BidMax); // in: AMM Bid -JSS(BidMin); // in: AMM Bid +JSS(MPToken); // ledger type. +JSS(MPTokenIssuance); // ledger type. JSS(NetworkID); // field. JSS(NFTokenOffer); // ledger type. JSS(NFTokenPage); // ledger type. @@ -132,101 +134,106 @@ JSS(account_sequence_available); // out: SubmitTransaction JSS(account_history_tx_stream); // in: Subscribe, Unsubscribe JSS(account_history_tx_index); // out: Account txn history subscribe -JSS(account_history_tx_first); // out: Account txn history subscribe -JSS(account_history_boundary); // out: Account txn history subscribe -JSS(accounts); // in: LedgerEntry, Subscribe, - // handlers/Ledger, Unsubscribe -JSS(accounts_proposed); // in: Subscribe, Unsubscribe +JSS(account_history_tx_first); // out: Account txn history subscribe +JSS(account_history_boundary); // out: Account txn history subscribe +JSS(accounts); // in: LedgerEntry, Subscribe, + // handlers/Ledger, Unsubscribe +JSS(accounts_proposed); // in: Subscribe, Unsubscribe JSS(action); -JSS(acquiring); // out: LedgerRequest -JSS(address); // out: PeerImp -JSS(affected); // out: AcceptedLedgerTx -JSS(age); // out: NetworkOPs, Peers -JSS(alternatives); // out: PathRequest, RipplePathFind -JSS(amendment_blocked); // out: NetworkOPs -JSS(amendments); // in: AccountObjects, out: NetworkOPs -JSS(amm); // out: amm_info -JSS(amm_account); // in: amm_info -JSS(amount); // out: AccountChannels, amm_info -JSS(amount2); // out: amm_info -JSS(api_version); // in: many, out: Version -JSS(api_version_low); // out: Version -JSS(applied); // out: SubmitTransaction -JSS(asks); // out: Subscribe -JSS(asset); // in: amm_info -JSS(asset2); // in: amm_info -JSS(assets); // out: GatewayBalances -JSS(asset_frozen); // out: amm_info -JSS(asset2_frozen); // out: amm_info -JSS(attestations); // -JSS(attestation_reward_account); // -JSS(auction_slot); // out: amm_info -JSS(authorized); // out: AccountLines -JSS(auth_accounts); // out: amm_info -JSS(auth_change); // out: AccountInfo -JSS(auth_change_queued); // out: AccountInfo -JSS(available); // out: ValidatorList -JSS(avg_bps_recv); // out: Peers -JSS(avg_bps_sent); // out: Peers -JSS(balance); // out: AccountLines -JSS(balances); // out: GatewayBalances -JSS(base); // out: LogLevel -JSS(base_asset); // in: get_aggregate_price -JSS(base_fee); // out: NetworkOPs -JSS(base_fee_xrp); // out: NetworkOPs -JSS(bids); // out: Subscribe -JSS(binary); // in: AccountTX, LedgerEntry, - // AccountTxOld, Tx LedgerData -JSS(blob); // out: ValidatorList -JSS(blobs_v2); // out: ValidatorList - // in: UNL -JSS(books); // in: Subscribe, Unsubscribe -JSS(both); // in: Subscribe, Unsubscribe -JSS(both_sides); // in: Subscribe, Unsubscribe -JSS(broadcast); // out: SubmitTransaction -JSS(bridge); // in: LedgerEntry -JSS(bridge_account); // in: LedgerEntry -JSS(build_path); // in: TransactionSign -JSS(build_version); // out: NetworkOPs -JSS(cancel_after); // out: AccountChannels -JSS(can_delete); // out: CanDelete -JSS(changes); // out: BookChanges -JSS(channel_id); // out: AccountChannels -JSS(channels); // out: AccountChannels -JSS(check); // in: AccountObjects -JSS(check_nodes); // in: LedgerCleaner -JSS(clear); // in/out: FetchInfo -JSS(close); // out: BookChanges -JSS(close_flags); // out: LedgerToJson -JSS(close_time); // in: Application, out: NetworkOPs, - // RCLCxPeerPos, LedgerToJson -JSS(close_time_iso); // out: Tx, NetworkOPs, TransactionEntry - // AccountTx, LedgerToJson -JSS(close_time_estimated); // in: Application, out: LedgerToJson -JSS(close_time_human); // out: LedgerToJson -JSS(close_time_offset); // out: NetworkOPs -JSS(close_time_resolution); // in: Application; out: LedgerToJson -JSS(closed); // out: NetworkOPs, LedgerToJson, - // handlers/Ledger -JSS(closed_ledger); // out: NetworkOPs -JSS(cluster); // out: PeerImp -JSS(code); // out: errors -JSS(command); // in: RPCHandler -JSS(complete); // out: NetworkOPs, InboundLedger -JSS(complete_ledgers); // out: NetworkOPs, PeerImp -JSS(consensus); // out: NetworkOPs, LedgerConsensus -JSS(converge_time); // out: NetworkOPs -JSS(converge_time_s); // out: NetworkOPs -JSS(cookie); // out: NetworkOPs -JSS(count); // in: AccountTx*, ValidatorList -JSS(counters); // in/out: retrieve counters -JSS(ctid); // in/out: Tx RPC -JSS(currency_a); // out: BookChanges -JSS(currency_b); // out: BookChanges -JSS(currency); // in: paths/PathRequest, STAmount - // out: STPathSet, STAmount, - // AccountLines -JSS(current); // out: OwnerInfo +JSS(acquiring); // out: LedgerRequest +JSS(address); // out: PeerImp +JSS(affected); // out: AcceptedLedgerTx +JSS(age); // out: NetworkOPs, Peers +JSS(alternatives); // out: PathRequest, RipplePathFind +JSS(amendment_blocked); // out: NetworkOPs +JSS(amendments); // in: AccountObjects, out: NetworkOPs +JSS(amm); // out: amm_info +JSS(amm_account); // in: amm_info +JSS(amount); // out: AccountChannels, amm_info +JSS(amount2); // out: amm_info +JSS(api_version); // in: many, out: Version +JSS(api_version_low); // out: Version +JSS(applied); // out: SubmitTransaction +JSS(asks); // out: Subscribe +JSS(asset); // in: amm_info +JSS(asset2); // in: amm_info +JSS(assets); // out: GatewayBalances +JSS(asset_frozen); // out: amm_info +JSS(asset2_frozen); // out: amm_info +JSS(attestations); +JSS(attestation_reward_account); +JSS(auction_slot); // out: amm_info +JSS(authorized); // out: AccountLines +JSS(auth_accounts); // out: amm_info +JSS(auth_change); // out: AccountInfo +JSS(auth_change_queued); // out: AccountInfo +JSS(available); // out: ValidatorList +JSS(avg_bps_recv); // out: Peers +JSS(avg_bps_sent); // out: Peers +JSS(balance); // out: AccountLines +JSS(balances); // out: GatewayBalances +JSS(base); // out: LogLevel +JSS(base_asset); // in: get_aggregate_price +JSS(base_fee); // out: NetworkOPs +JSS(base_fee_xrp); // out: NetworkOPs +JSS(bids); // out: Subscribe +JSS(binary); // in: AccountTX, LedgerEntry, + // AccountTxOld, Tx LedgerData +JSS(blob); // out: ValidatorList +JSS(blobs_v2); // out: ValidatorList + // in: UNL +JSS(books); // in: Subscribe, Unsubscribe +JSS(both); // in: Subscribe, Unsubscribe +JSS(both_sides); // in: Subscribe, Unsubscribe +JSS(broadcast); // out: SubmitTransaction +JSS(bridge); // in: LedgerEntry +JSS(bridge_account); // in: LedgerEntry +JSS(build_path); // in: TransactionSign +JSS(build_version); // out: NetworkOPs +JSS(cancel_after); // out: AccountChannels +JSS(can_delete); // out: CanDelete +JSS(mpt_amount); // out: mpt_holders +JSS(mpt_issuance); // in: LedgerEntry, AccountObjects +JSS(mpt_issuance_id); // in: Payment, mpt_holders +JSS(mptoken); // in: LedgerEntry, AccountObjects +JSS(mptoken_index); // out: mpt_holders +JSS(changes); // out: BookChanges +JSS(channel_id); // out: AccountChannels +JSS(channels); // out: AccountChannels +JSS(check); // in: AccountObjects +JSS(check_nodes); // in: LedgerCleaner +JSS(clear); // in/out: FetchInfo +JSS(close); // out: BookChanges +JSS(close_flags); // out: LedgerToJson +JSS(close_time); // in: Application, out: NetworkOPs, + // RCLCxPeerPos, LedgerToJson +JSS(close_time_iso); // out: Tx, NetworkOPs, TransactionEntry + // AccountTx, LedgerToJson +JSS(close_time_estimated); // in: Application, out: LedgerToJson +JSS(close_time_human); // out: LedgerToJson +JSS(close_time_offset); // out: NetworkOPs +JSS(close_time_resolution); // in: Application; out: LedgerToJson +JSS(closed); // out: NetworkOPs, LedgerToJson, + // handlers/Ledger +JSS(closed_ledger); // out: NetworkOPs +JSS(cluster); // out: PeerImp +JSS(code); // out: errors +JSS(command); // in: RPCHandler +JSS(complete); // out: NetworkOPs, InboundLedger +JSS(complete_ledgers); // out: NetworkOPs, PeerImp +JSS(consensus); // out: NetworkOPs, LedgerConsensus +JSS(converge_time); // out: NetworkOPs +JSS(converge_time_s); // out: NetworkOPs +JSS(cookie); // out: NetworkOPs +JSS(count); // in: AccountTx*, ValidatorList +JSS(counters); // in/out: retrieve counters +JSS(ctid); // in/out: Tx RPC +JSS(currency_a); // out: BookChanges +JSS(currency_b); // out: BookChanges +JSS(currency); // in: paths/PathRequest, STAmount + // out: STPathSet, STAmount, + // AccountLines +JSS(current); // out: OwnerInfo JSS(current_activities); JSS(current_ledger_size); // out: TxQ JSS(current_queue_size); // out: TxQ @@ -271,354 +278,355 @@ JSS(ephemeral_key); // out: ValidatorInfo // in/out: Manifest JSS(error); // out: error JSS(errored); -JSS(error_code); // out: error -JSS(error_exception); // out: Submit -JSS(error_message); // out: error -JSS(escrow); // in: LedgerEntry -JSS(expand); // in: handler/Ledger -JSS(expected_date); // out: any (warnings) -JSS(expected_date_UTC); // out: any (warnings) -JSS(expected_ledger_size); // out: TxQ -JSS(expiration); // out: AccountOffers, AccountChannels, - // ValidatorList, amm_info -JSS(fail_hard); // in: Sign, Submit -JSS(failed); // out: InboundLedger -JSS(feature); // in: Feature -JSS(features); // out: Feature -JSS(fee); // out: NetworkOPs, Peers -JSS(fee_base); // out: NetworkOPs -JSS(fee_div_max); // in: TransactionSign -JSS(fee_level); // out: AccountInfo -JSS(fee_mult_max); // in: TransactionSign -JSS(fee_ref); // out: NetworkOPs, DEPRECATED -JSS(fetch_pack); // out: NetworkOPs -JSS(FIELDS); // out: RPC server_definitions - // matches definitions.json format -JSS(first); // out: rpc/Version +JSS(error_code); // out: error +JSS(error_exception); // out: Submit +JSS(error_message); // out: error +JSS(escrow); // in: LedgerEntry +JSS(expand); // in: handler/Ledger +JSS(expected_date); // out: any (warnings) +JSS(expected_date_UTC); // out: any (warnings) +JSS(expected_ledger_size); // out: TxQ +JSS(expiration); // out: AccountOffers, AccountChannels, + // ValidatorList, amm_info +JSS(fail_hard); // in: Sign, Submit +JSS(failed); // out: InboundLedger +JSS(feature); // in: Feature +JSS(features); // out: Feature +JSS(fee); // out: NetworkOPs, Peers +JSS(fee_base); // out: NetworkOPs +JSS(fee_div_max); // in: TransactionSign +JSS(fee_level); // out: AccountInfo +JSS(fee_mult_max); // in: TransactionSign +JSS(fee_ref); // out: NetworkOPs, DEPRECATED +JSS(fetch_pack); // out: NetworkOPs +JSS(FIELDS); // out: RPC server_definitions + // matches definitions.json format +JSS(first); // out: rpc/Version JSS(finished); -JSS(fix_txns); // in: LedgerCleaner -JSS(flags); // out: AccountOffers, - // NetworkOPs -JSS(forward); // in: AccountTx -JSS(freeze); // out: AccountLines -JSS(freeze_peer); // out: AccountLines -JSS(frozen_balances); // out: GatewayBalances -JSS(full); // in: LedgerClearer, handlers/Ledger -JSS(full_reply); // out: PathFind -JSS(fullbelow_size); // out: GetCounts -JSS(good); // out: RPCVersion -JSS(hash); // out: NetworkOPs, InboundLedger, - // LedgerToJson, STTx; field -JSS(hashes); // in: AccountObjects -JSS(have_header); // out: InboundLedger -JSS(have_state); // out: InboundLedger -JSS(have_transactions); // out: InboundLedger -JSS(high); // out: BookChanges -JSS(highest_sequence); // out: AccountInfo -JSS(highest_ticket); // out: AccountInfo -JSS(historical_perminute); // historical_perminute. -JSS(hostid); // out: NetworkOPs -JSS(hotwallet); // in: GatewayBalances -JSS(id); // websocket. -JSS(ident); // in: AccountCurrencies, AccountInfo, - // OwnerInfo -JSS(ignore_default); // in: AccountLines -JSS(inLedger); // out: tx/Transaction -JSS(inbound); // out: PeerImp -JSS(index); // in: LedgerEntry - // out: STLedgerEntry, - // LedgerEntry, TxHistory, LedgerData -JSS(info); // out: ServerInfo, ConsensusInfo, FetchInfo +JSS(fix_txns); // in: LedgerCleaner +JSS(flags); // out: AccountOffers, + // NetworkOPs +JSS(forward); // in: AccountTx +JSS(freeze); // out: AccountLines +JSS(freeze_peer); // out: AccountLines +JSS(frozen_balances); // out: GatewayBalances +JSS(full); // in: LedgerClearer, handlers/Ledger +JSS(full_reply); // out: PathFind +JSS(fullbelow_size); // out: GetCounts +JSS(good); // out: RPCVersion +JSS(hash); // out: NetworkOPs, InboundLedger, + // LedgerToJson, STTx; field +JSS(hashes); // in: AccountObjects +JSS(have_header); // out: InboundLedger +JSS(have_state); // out: InboundLedger +JSS(have_transactions); // out: InboundLedger +JSS(high); // out: BookChanges +JSS(highest_sequence); // out: AccountInfo +JSS(highest_ticket); // out: AccountInfo +JSS(historical_perminute); // historical_perminute. +JSS(holders); // out: MPTHolders +JSS(hostid); // out: NetworkOPs +JSS(hotwallet); // in: GatewayBalances +JSS(id); // websocket. +JSS(ident); // in: AccountCurrencies, AccountInfo, + // OwnerInfo +JSS(ignore_default); // in: AccountLines +JSS(inLedger); // out: tx/Transaction +JSS(inbound); // out: PeerImp +JSS(index); // in: LedgerEntry + // out: STLedgerEntry, + // LedgerEntry, TxHistory, LedgerData +JSS(info); // out: ServerInfo, ConsensusInfo, FetchInfo JSS(initial_sync_duration_us); -JSS(internal_command); // in: Internal -JSS(invalid_API_version); // out: Many, when a request has an invalid - // version -JSS(io_latency_ms); // out: NetworkOPs -JSS(ip); // in: Connect, out: OverlayImpl -JSS(is_burned); // out: nft_info (clio) -JSS(isSerialized); // out: RPC server_definitions - // matches definitions.json format -JSS(isSigningField); // out: RPC server_definitions - // matches definitions.json format -JSS(isVLEncoded); // out: RPC server_definitions - // matches definitions.json format -JSS(issuer); // in: RipplePathFind, Subscribe, - // Unsubscribe, BookOffers - // out: STPathSet, STAmount +JSS(internal_command); // in: Internal +JSS(invalid_API_version); // out: Many, when a request has an invalid + // version +JSS(io_latency_ms); // out: NetworkOPs +JSS(ip); // in: Connect, out: OverlayImpl +JSS(is_burned); // out: nft_info (clio) +JSS(isSerialized); // out: RPC server_definitions + // matches definitions.json format +JSS(isSigningField); // out: RPC server_definitions + // matches definitions.json format +JSS(isVLEncoded); // out: RPC server_definitions + // matches definitions.json format +JSS(issuer); // in: RipplePathFind, Subscribe, + // Unsubscribe, BookOffers + // out: STPathSet, STAmount JSS(job); JSS(job_queue); JSS(jobs); -JSS(jsonrpc); // json version -JSS(jq_trans_overflow); // JobQueue transaction limit overflow. -JSS(kept); // out: SubmitTransaction -JSS(key); // out -JSS(key_type); // in/out: WalletPropose, TransactionSign -JSS(latency); // out: PeerImp -JSS(last); // out: RPCVersion -JSS(last_close); // out: NetworkOPs -JSS(last_refresh_time); // out: ValidatorSite -JSS(last_refresh_status); // out: ValidatorSite -JSS(last_refresh_message); // out: ValidatorSite -JSS(ledger); // in: NetworkOPs, LedgerCleaner, - // RPCHelpers - // out: NetworkOPs, PeerImp -JSS(ledger_current_index); // out: NetworkOPs, RPCHelpers, - // LedgerCurrent, LedgerAccept, - // AccountLines -JSS(ledger_data); // out: LedgerHeader -JSS(ledger_hash); // in: RPCHelpers, LedgerRequest, - // RipplePathFind, TransactionEntry, - // handlers/Ledger - // out: NetworkOPs, RPCHelpers, - // LedgerClosed, LedgerData, - // AccountLines -JSS(ledger_hit_rate); // out: GetCounts -JSS(ledger_index); // in/out: many -JSS(ledger_index_max); // in, out: AccountTx* -JSS(ledger_index_min); // in, out: AccountTx* -JSS(ledger_max); // in, out: AccountTx* -JSS(ledger_min); // in, out: AccountTx* -JSS(ledger_time); // out: NetworkOPs -JSS(LEDGER_ENTRY_TYPES); // out: RPC server_definitions - // matches definitions.json format -JSS(levels); // LogLevels -JSS(limit); // in/out: AccountTx*, AccountOffers, - // AccountLines, AccountObjects - // in: LedgerData, BookOffers -JSS(limit_peer); // out: AccountLines -JSS(lines); // out: AccountLines -JSS(list); // out: ValidatorList -JSS(load); // out: NetworkOPs, PeerImp -JSS(load_base); // out: NetworkOPs -JSS(load_factor); // out: NetworkOPs -JSS(load_factor_cluster); // out: NetworkOPs -JSS(load_factor_fee_escalation); // out: NetworkOPs -JSS(load_factor_fee_queue); // out: NetworkOPs -JSS(load_factor_fee_reference); // out: NetworkOPs -JSS(load_factor_local); // out: NetworkOPs -JSS(load_factor_net); // out: NetworkOPs -JSS(load_factor_server); // out: NetworkOPs -JSS(load_fee); // out: LoadFeeTrackImp, NetworkOPs -JSS(local); // out: resource/Logic.h -JSS(local_txs); // out: GetCounts -JSS(local_static_keys); // out: ValidatorList -JSS(low); // out: BookChanges -JSS(lowest_sequence); // out: AccountInfo -JSS(lowest_ticket); // out: AccountInfo -JSS(lp_token); // out: amm_info -JSS(majority); // out: RPC feature -JSS(manifest); // out: ValidatorInfo, Manifest -JSS(marker); // in/out: AccountTx, AccountOffers, - // AccountLines, AccountObjects, - // LedgerData - // in: BookOffers -JSS(master_key); // out: WalletPropose, NetworkOPs, - // ValidatorInfo - // in/out: Manifest -JSS(master_seed); // out: WalletPropose -JSS(master_seed_hex); // out: WalletPropose -JSS(master_signature); // out: pubManifest -JSS(max_ledger); // in/out: LedgerCleaner -JSS(max_queue_size); // out: TxQ -JSS(max_spend_drops); // out: AccountInfo -JSS(max_spend_drops_total); // out: AccountInfo -JSS(mean); // out: get_aggregate_price -JSS(median); // out: get_aggregate_price -JSS(median_fee); // out: TxQ -JSS(median_level); // out: TxQ -JSS(message); // error. -JSS(meta); // out: NetworkOPs, AccountTx*, Tx -JSS(meta_blob); // out: NetworkOPs, AccountTx*, Tx +JSS(jsonrpc); // json version +JSS(jq_trans_overflow); // JobQueue transaction limit overflow. +JSS(kept); // out: SubmitTransaction +JSS(key); // out +JSS(key_type); // in/out: WalletPropose, TransactionSign +JSS(latency); // out: PeerImp +JSS(last); // out: RPCVersion +JSS(last_close); // out: NetworkOPs +JSS(last_refresh_time); // out: ValidatorSite +JSS(last_refresh_status); // out: ValidatorSite +JSS(last_refresh_message); // out: ValidatorSite +JSS(ledger); // in: NetworkOPs, LedgerCleaner, + // RPCHelpers + // out: NetworkOPs, PeerImp +JSS(ledger_current_index); // out: NetworkOPs, RPCHelpers, + // LedgerCurrent, LedgerAccept, + // AccountLines +JSS(ledger_data); // out: LedgerHeader +JSS(ledger_hash); // in: RPCHelpers, LedgerRequest, + // RipplePathFind, TransactionEntry, + // handlers/Ledger + // out: NetworkOPs, RPCHelpers, + // LedgerClosed, LedgerData, + // AccountLines +JSS(ledger_hit_rate); // out: GetCounts +JSS(ledger_index); // in/out: many +JSS(ledger_index_max); // in, out: AccountTx* +JSS(ledger_index_min); // in, out: AccountTx* +JSS(ledger_max); // in, out: AccountTx* +JSS(ledger_min); // in, out: AccountTx* +JSS(ledger_time); // out: NetworkOPs +JSS(LEDGER_ENTRY_TYPES); // out: RPC server_definitions + // matches definitions.json format +JSS(levels); // LogLevels +JSS(limit); // in/out: AccountTx*, AccountOffers, + // AccountLines, AccountObjects + // in: LedgerData, BookOffers +JSS(limit_peer); // out: AccountLines +JSS(lines); // out: AccountLines +JSS(list); // out: ValidatorList +JSS(load); // out: NetworkOPs, PeerImp +JSS(load_base); // out: NetworkOPs +JSS(load_factor); // out: NetworkOPs +JSS(load_factor_cluster); // out: NetworkOPs +JSS(load_factor_fee_escalation); // out: NetworkOPs +JSS(load_factor_fee_queue); // out: NetworkOPs +JSS(load_factor_fee_reference); // out: NetworkOPs +JSS(load_factor_local); // out: NetworkOPs +JSS(load_factor_net); // out: NetworkOPs +JSS(load_factor_server); // out: NetworkOPs +JSS(load_fee); // out: LoadFeeTrackImp, NetworkOPs +JSS(local); // out: resource/Logic.h +JSS(local_txs); // out: GetCounts +JSS(local_static_keys); // out: ValidatorList +JSS(low); // out: BookChanges +JSS(lowest_sequence); // out: AccountInfo +JSS(lowest_ticket); // out: AccountInfo +JSS(lp_token); // out: amm_info +JSS(majority); // out: RPC feature +JSS(manifest); // out: ValidatorInfo, Manifest +JSS(marker); // in/out: AccountTx, AccountOffers, + // AccountLines, AccountObjects, + // LedgerData + // in: BookOffers +JSS(master_key); // out: WalletPropose, NetworkOPs, + // ValidatorInfo + // in/out: Manifest +JSS(master_seed); // out: WalletPropose +JSS(master_seed_hex); // out: WalletPropose +JSS(master_signature); // out: pubManifest +JSS(max_ledger); // in/out: LedgerCleaner +JSS(max_queue_size); // out: TxQ +JSS(max_spend_drops); // out: AccountInfo +JSS(max_spend_drops_total); // out: AccountInfo +JSS(mean); // out: get_aggregate_price +JSS(median); // out: get_aggregate_price +JSS(median_fee); // out: TxQ +JSS(median_level); // out: TxQ +JSS(message); // error. +JSS(meta); // out: NetworkOPs, AccountTx*, Tx +JSS(meta_blob); // out: NetworkOPs, AccountTx*, Tx JSS(metaData); -JSS(metadata); // out: TransactionEntry -JSS(method); // RPC +JSS(metadata); // out: TransactionEntry +JSS(method); // RPC JSS(methods); -JSS(metrics); // out: Peers -JSS(min_count); // in: GetCounts -JSS(min_ledger); // in: LedgerCleaner -JSS(minimum_fee); // out: TxQ -JSS(minimum_level); // out: TxQ -JSS(missingCommand); // error -JSS(name); // out: AmendmentTableImpl, PeerImp -JSS(needed_state_hashes); // out: InboundLedger +JSS(metrics); // out: Peers +JSS(min_count); // in: GetCounts +JSS(min_ledger); // in: LedgerCleaner +JSS(minimum_fee); // out: TxQ +JSS(minimum_level); // out: TxQ +JSS(missingCommand); // error +JSS(name); // out: AmendmentTableImpl, PeerImp +JSS(needed_state_hashes); // out: InboundLedger JSS(needed_transaction_hashes); // out: InboundLedger -JSS(network_id); // out: NetworkOPs -JSS(network_ledger); // out: NetworkOPs -JSS(next_refresh_time); // out: ValidatorSite -JSS(nft_id); // in: nft_sell_offers, nft_buy_offers -JSS(nft_offer); // in: LedgerEntry -JSS(nft_offer_index); // out nft_buy_offers, nft_sell_offers -JSS(nft_page); // in: LedgerEntry -JSS(nft_serial); // out: account_nfts -JSS(nft_taxon); // out: nft_info (clio) -JSS(nftoken_id); // out: insertNFTokenID -JSS(nftoken_ids); // out: insertNFTokenID -JSS(no_ripple); // out: AccountLines -JSS(no_ripple_peer); // out: AccountLines -JSS(node); // out: LedgerEntry -JSS(node_binary); // out: LedgerEntry -JSS(node_read_bytes); // out: GetCounts -JSS(node_read_errors); // out: GetCounts -JSS(node_read_retries); // out: GetCounts -JSS(node_reads_hit); // out: GetCounts -JSS(node_reads_total); // out: GetCounts -JSS(node_reads_duration_us); // out: GetCounts -JSS(node_size); // out: server_info -JSS(nodestore); // out: GetCounts -JSS(node_writes); // out: GetCounts -JSS(node_written_bytes); // out: GetCounts -JSS(node_writes_duration_us); // out: GetCounts -JSS(node_write_retries); // out: GetCounts -JSS(node_writes_delayed); // out::GetCounts -JSS(nth); // out: RPC server_definitions -JSS(nunl); // in: AccountObjects -JSS(obligations); // out: GatewayBalances -JSS(offer); // in: LedgerEntry -JSS(offers); // out: NetworkOPs, AccountOffers, Subscribe -JSS(offer_id); // out: insertNFTokenOfferID -JSS(offline); // in: TransactionSign -JSS(offset); // in/out: AccountTxOld -JSS(open); // out: handlers/Ledger -JSS(open_ledger_cost); // out: SubmitTransaction -JSS(open_ledger_fee); // out: TxQ -JSS(open_ledger_level); // out: TxQ -JSS(oracle); // in: LedgerEntry -JSS(oracles); // in: get_aggregate_price -JSS(oracle_document_id); // in: get_aggregate_price -JSS(owner); // in: LedgerEntry, out: NetworkOPs -JSS(owner_funds); // in/out: Ledger, NetworkOPs, AcceptedLedgerTx +JSS(network_id); // out: NetworkOPs +JSS(network_ledger); // out: NetworkOPs +JSS(next_refresh_time); // out: ValidatorSite +JSS(nft_id); // in: nft_sell_offers, nft_buy_offers +JSS(nft_offer); // in: LedgerEntry +JSS(nft_offer_index); // out nft_buy_offers, nft_sell_offers +JSS(nft_page); // in: LedgerEntry +JSS(nft_serial); // out: account_nfts +JSS(nft_taxon); // out: nft_info (clio) +JSS(nftoken_id); // out: insertNFTokenID +JSS(nftoken_ids); // out: insertNFTokenID +JSS(no_ripple); // out: AccountLines +JSS(no_ripple_peer); // out: AccountLines +JSS(node); // out: LedgerEntry +JSS(node_binary); // out: LedgerEntry +JSS(node_read_bytes); // out: GetCounts +JSS(node_read_errors); // out: GetCounts +JSS(node_read_retries); // out: GetCounts +JSS(node_reads_hit); // out: GetCounts +JSS(node_reads_total); // out: GetCounts +JSS(node_reads_duration_us); // out: GetCounts +JSS(node_size); // out: server_info +JSS(nodestore); // out: GetCounts +JSS(node_writes); // out: GetCounts +JSS(node_written_bytes); // out: GetCounts +JSS(node_writes_duration_us); // out: GetCounts +JSS(node_write_retries); // out: GetCounts +JSS(node_writes_delayed); // out::GetCounts +JSS(nth); // out: RPC server_definitions +JSS(nunl); // in: AccountObjects +JSS(obligations); // out: GatewayBalances +JSS(offer); // in: LedgerEntry +JSS(offers); // out: NetworkOPs, AccountOffers, Subscribe +JSS(offer_id); // out: insertNFTokenOfferID +JSS(offline); // in: TransactionSign +JSS(offset); // in/out: AccountTxOld +JSS(open); // out: handlers/Ledger +JSS(open_ledger_cost); // out: SubmitTransaction +JSS(open_ledger_fee); // out: TxQ +JSS(open_ledger_level); // out: TxQ +JSS(oracle); // in: LedgerEntry +JSS(oracles); // in: get_aggregate_price +JSS(oracle_document_id); // in: get_aggregate_price +JSS(owner); // in: LedgerEntry, out: NetworkOPs +JSS(owner_funds); // in/out: Ledger, NetworkOPs, AcceptedLedgerTx JSS(page_index); -JSS(params); // RPC -JSS(parent_close_time); // out: LedgerToJson -JSS(parent_hash); // out: LedgerToJson -JSS(partition); // in: LogLevel -JSS(passphrase); // in: WalletPropose -JSS(password); // in: Subscribe -JSS(paths); // in: RipplePathFind -JSS(paths_canonical); // out: RipplePathFind -JSS(paths_computed); // out: PathRequest, RipplePathFind -JSS(payment_channel); // in: LedgerEntry -JSS(peer); // in: AccountLines -JSS(peer_authorized); // out: AccountLines -JSS(peer_id); // out: RCLCxPeerPos -JSS(peers); // out: InboundLedger, handlers/Peers, Overlay -JSS(peer_disconnects); // Severed peer connection counter. -JSS(peer_disconnects_resources); // Severed peer connections because of - // excess resource consumption. -JSS(port); // in: Connect, out: NetworkOPs -JSS(ports); // out: NetworkOPs -JSS(previous); // out: Reservations -JSS(previous_ledger); // out: LedgerPropose -JSS(price); // out: amm_info, AuctionSlot -JSS(proof); // in: BookOffers -JSS(propose_seq); // out: LedgerPropose -JSS(proposers); // out: NetworkOPs, LedgerConsensus -JSS(protocol); // out: NetworkOPs, PeerImp -JSS(proxied); // out: RPC ping -JSS(pubkey_node); // out: NetworkOPs -JSS(pubkey_publisher); // out: ValidatorList -JSS(pubkey_validator); // out: NetworkOPs, ValidatorList -JSS(public_key); // out: OverlayImpl, PeerImp, WalletPropose, - // ValidatorInfo - // in/out: Manifest -JSS(public_key_hex); // out: WalletPropose -JSS(published_ledger); // out: NetworkOPs -JSS(publisher_lists); // out: ValidatorList -JSS(quality); // out: NetworkOPs -JSS(quality_in); // out: AccountLines -JSS(quality_out); // out: AccountLines -JSS(queue); // in: AccountInfo -JSS(queue_data); // out: AccountInfo -JSS(queued); // out: SubmitTransaction +JSS(params); // RPC +JSS(parent_close_time); // out: LedgerToJson +JSS(parent_hash); // out: LedgerToJson +JSS(partition); // in: LogLevel +JSS(passphrase); // in: WalletPropose +JSS(password); // in: Subscribe +JSS(paths); // in: RipplePathFind +JSS(paths_canonical); // out: RipplePathFind +JSS(paths_computed); // out: PathRequest, RipplePathFind +JSS(payment_channel); // in: LedgerEntry +JSS(peer); // in: AccountLines +JSS(peer_authorized); // out: AccountLines +JSS(peer_id); // out: RCLCxPeerPos +JSS(peers); // out: InboundLedger, handlers/Peers, Overlay +JSS(peer_disconnects); // Severed peer connection counter. +JSS(peer_disconnects_resources); // Severed peer connections because of + // excess resource consumption. +JSS(port); // in: Connect, out: NetworkOPs +JSS(ports); // out: NetworkOPs +JSS(previous); // out: Reservations +JSS(previous_ledger); // out: LedgerPropose +JSS(price); // out: amm_info, AuctionSlot +JSS(proof); // in: BookOffers +JSS(propose_seq); // out: LedgerPropose +JSS(proposers); // out: NetworkOPs, LedgerConsensus +JSS(protocol); // out: NetworkOPs, PeerImp +JSS(proxied); // out: RPC ping +JSS(pubkey_node); // out: NetworkOPs +JSS(pubkey_publisher); // out: ValidatorList +JSS(pubkey_validator); // out: NetworkOPs, ValidatorList +JSS(public_key); // out: OverlayImpl, PeerImp, WalletPropose, + // ValidatorInfo + // in/out: Manifest +JSS(public_key_hex); // out: WalletPropose +JSS(published_ledger); // out: NetworkOPs +JSS(publisher_lists); // out: ValidatorList +JSS(quality); // out: NetworkOPs +JSS(quality_in); // out: AccountLines +JSS(quality_out); // out: AccountLines +JSS(queue); // in: AccountInfo +JSS(queue_data); // out: AccountInfo +JSS(queued); // out: SubmitTransaction JSS(queued_duration_us); -JSS(quote_asset); // in: get_aggregate_price -JSS(random); // out: Random -JSS(raw_meta); // out: AcceptedLedgerTx -JSS(receive_currencies); // out: AccountCurrencies -JSS(reference_level); // out: TxQ -JSS(refresh_interval); // in: UNL -JSS(refresh_interval_min); // out: ValidatorSites -JSS(regular_seed); // in/out: LedgerEntry -JSS(remaining); // out: ValidatorList -JSS(remote); // out: Logic.h -JSS(request); // RPC -JSS(requested); // out: Manifest -JSS(reservations); // out: Reservations -JSS(reserve_base); // out: NetworkOPs -JSS(reserve_base_xrp); // out: NetworkOPs -JSS(reserve_inc); // out: NetworkOPs -JSS(reserve_inc_xrp); // out: NetworkOPs -JSS(response); // websocket -JSS(result); // RPC -JSS(ripple_lines); // out: NetworkOPs -JSS(ripple_state); // in: LedgerEntr -JSS(ripplerpc); // ripple RPC version -JSS(role); // out: Ping.cpp +JSS(quote_asset); // in: get_aggregate_price +JSS(random); // out: Random +JSS(raw_meta); // out: AcceptedLedgerTx +JSS(receive_currencies); // out: AccountCurrencies +JSS(reference_level); // out: TxQ +JSS(refresh_interval); // in: UNL +JSS(refresh_interval_min); // out: ValidatorSites +JSS(regular_seed); // in/out: LedgerEntry +JSS(remaining); // out: ValidatorList +JSS(remote); // out: Logic.h +JSS(request); // RPC +JSS(requested); // out: Manifest +JSS(reservations); // out: Reservations +JSS(reserve_base); // out: NetworkOPs +JSS(reserve_base_xrp); // out: NetworkOPs +JSS(reserve_inc); // out: NetworkOPs +JSS(reserve_inc_xrp); // out: NetworkOPs +JSS(response); // websocket +JSS(result); // RPC +JSS(ripple_lines); // out: NetworkOPs +JSS(ripple_state); // in: LedgerEntr +JSS(ripplerpc); // ripple RPC version +JSS(role); // out: Ping.cpp JSS(rpc); -JSS(rt_accounts); // in: Subscribe, Unsubscribe +JSS(rt_accounts); // in: Subscribe, Unsubscribe JSS(running_duration_us); -JSS(search_depth); // in: RipplePathFind -JSS(searched_all); // out: Tx -JSS(secret); // in: TransactionSign, - // ValidationCreate, ValidationSeed, - // channel_authorize -JSS(seed); // -JSS(seed_hex); // in: WalletPropose, TransactionSign -JSS(send_currencies); // out: AccountCurrencies -JSS(send_max); // in: PathRequest, RipplePathFind -JSS(seq); // in: LedgerEntry; - // out: NetworkOPs, RPCSub, AccountOffers, - // ValidatorList, ValidatorInfo, Manifest -JSS(sequence); // in: UNL -JSS(sequence_count); // out: AccountInfo -JSS(server_domain); // out: NetworkOPs -JSS(server_state); // out: NetworkOPs -JSS(server_state_duration_us); // out: NetworkOPs -JSS(server_status); // out: NetworkOPs -JSS(server_version); // out: NetworkOPs -JSS(settle_delay); // out: AccountChannels -JSS(severity); // in: LogLevel -JSS(signature); // out: NetworkOPs, ChannelAuthorize -JSS(signature_verified); // out: ChannelVerify -JSS(signing_key); // out: NetworkOPs -JSS(signing_keys); // out: ValidatorList -JSS(signing_time); // out: NetworkOPs -JSS(signer_list); // in: AccountObjects -JSS(signer_lists); // in/out: AccountInfo -JSS(size); // out: get_aggregate_price -JSS(snapshot); // in: Subscribe -JSS(source_account); // in: PathRequest, RipplePathFind -JSS(source_amount); // in: PathRequest, RipplePathFind -JSS(source_currencies); // in: PathRequest, RipplePathFind -JSS(source_tag); // out: AccountChannels -JSS(stand_alone); // out: NetworkOPs -JSS(standard_deviation); // out: get_aggregate_price -JSS(start); // in: TxHistory +JSS(search_depth); // in: RipplePathFind +JSS(searched_all); // out: Tx +JSS(secret); // in: TransactionSign, + // ValidationCreate, ValidationSeed, + // channel_authorize +JSS(seed); // +JSS(seed_hex); // in: WalletPropose, TransactionSign +JSS(send_currencies); // out: AccountCurrencies +JSS(send_max); // in: PathRequest, RipplePathFind +JSS(seq); // in: LedgerEntry; + // out: NetworkOPs, RPCSub, AccountOffers, + // ValidatorList, ValidatorInfo, Manifest +JSS(sequence); // in: UNL +JSS(sequence_count); // out: AccountInfo +JSS(server_domain); // out: NetworkOPs +JSS(server_state); // out: NetworkOPs +JSS(server_state_duration_us);// out: NetworkOPs +JSS(server_status); // out: NetworkOPs +JSS(server_version); // out: NetworkOPs +JSS(settle_delay); // out: AccountChannels +JSS(severity); // in: LogLevel +JSS(signature); // out: NetworkOPs, ChannelAuthorize +JSS(signature_verified); // out: ChannelVerify +JSS(signing_key); // out: NetworkOPs +JSS(signing_keys); // out: ValidatorList +JSS(signing_time); // out: NetworkOPs +JSS(signer_list); // in: AccountObjects +JSS(signer_lists); // in/out: AccountInfo +JSS(size); // out: get_aggregate_price +JSS(snapshot); // in: Subscribe +JSS(source_account); // in: PathRequest, RipplePathFind +JSS(source_amount); // in: PathRequest, RipplePathFind +JSS(source_currencies); // in: PathRequest, RipplePathFind +JSS(source_tag); // out: AccountChannels +JSS(stand_alone); // out: NetworkOPs +JSS(standard_deviation); // out: get_aggregate_price +JSS(start); // in: TxHistory JSS(started); -JSS(state); // out: Logic.h, ServerState, LedgerData -JSS(state_accounting); // out: NetworkOPs -JSS(state_now); // in: Subscribe -JSS(status); // error -JSS(stop); // in: LedgerCleaner -JSS(stop_history_tx_only); // in: Unsubscribe, stop history tx stream -JSS(streams); // in: Subscribe, Unsubscribe -JSS(strict); // in: AccountCurrencies, AccountInfo -JSS(sub_index); // in: LedgerEntry -JSS(subcommand); // in: PathFind -JSS(success); // rpc -JSS(supported); // out: AmendmentTableImpl -JSS(sync_mode); // in: Submit -JSS(system_time_offset); // out: NetworkOPs -JSS(tag); // out: Peers -JSS(taker); // in: Subscribe, BookOffers -JSS(taker_gets); // in: Subscribe, Unsubscribe, BookOffers -JSS(taker_gets_funded); // out: NetworkOPs -JSS(taker_pays); // in: Subscribe, Unsubscribe, BookOffers -JSS(taker_pays_funded); // out: NetworkOPs -JSS(threshold); // in: Blacklist -JSS(ticket); // in: AccountObjects -JSS(ticket_count); // out: AccountInfo -JSS(ticket_seq); // in: LedgerEntry +JSS(state); // out: Logic.h, ServerState, LedgerData +JSS(state_accounting); // out: NetworkOPs +JSS(state_now); // in: Subscribe +JSS(status); // error +JSS(stop); // in: LedgerCleaner +JSS(stop_history_tx_only); // in: Unsubscribe, stop history tx stream +JSS(streams); // in: Subscribe, Unsubscribe +JSS(strict); // in: AccountCurrencies, AccountInfo +JSS(sub_index); // in: LedgerEntry +JSS(subcommand); // in: PathFind +JSS(success); // rpc +JSS(supported); // out: AmendmentTableImpl +JSS(sync_mode); // in: Submit +JSS(system_time_offset); // out: NetworkOPs +JSS(tag); // out: Peers +JSS(taker); // in: Subscribe, BookOffers +JSS(taker_gets); // in: Subscribe, Unsubscribe, BookOffers +JSS(taker_gets_funded); // out: NetworkOPs +JSS(taker_pays); // in: Subscribe, Unsubscribe, BookOffers +JSS(taker_pays_funded); // out: NetworkOPs +JSS(threshold); // in: Blacklist +JSS(ticket); // in: AccountObjects +JSS(ticket_count); // out: AccountInfo +JSS(ticket_seq); // in: LedgerEntry JSS(time); JSS(timeouts); // out: InboundLedger JSS(time_threshold); // in/out: Oracle aggregate @@ -714,8 +722,8 @@ JSS(vote_weight); // out: amm_info JSS(warning); // rpc: JSS(warnings); // out: server_info, server_state JSS(workers); -JSS(write_load); // out: GetCounts -JSS(xchain_owned_claim_id); // in: LedgerEntry, AccountObjects +JSS(write_load); // out: GetCounts +JSS(xchain_owned_claim_id); // in: LedgerEntry, AccountObjects JSS(xchain_owned_create_account_claim_id); // in: LedgerEntry JSS(NegativeUNL); // out: ValidatorList; ledger type // clang-format on diff --git a/src/libxrpl/basics/MPTAmount.cpp b/src/libxrpl/basics/MPTAmount.cpp new file mode 100644 index 00000000000..0481da67711 --- /dev/null +++ b/src/libxrpl/basics/MPTAmount.cpp @@ -0,0 +1,68 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 + +namespace ripple { + +MPTAmount& +MPTAmount::operator+=(MPTAmount const& other) +{ + value_ += other.value(); + return *this; +} + +MPTAmount& +MPTAmount::operator-=(MPTAmount const& other) +{ + value_ -= other.value(); + return *this; +} + +MPTAmount +MPTAmount::operator-() const +{ + return MPTAmount{-value_}; +} + +bool +MPTAmount::operator==(MPTAmount const& other) const +{ + return value_ == other.value_; +} + +bool +MPTAmount::operator==(value_type other) const +{ + return value_ == other; +} + +bool +MPTAmount::operator<(MPTAmount const& other) const +{ + return value_ < other.value_; +} + +MPTAmount +MPTAmount::minPositiveAmount() +{ + return MPTAmount{1}; +} + +} // namespace ripple diff --git a/src/libxrpl/basics/Number.cpp b/src/libxrpl/basics/Number.cpp index 14260b653a2..ebbfa0023c9 100644 --- a/src/libxrpl/basics/Number.cpp +++ b/src/libxrpl/basics/Number.cpp @@ -504,6 +504,11 @@ Number::operator XRPAmount() const return XRPAmount{static_cast(*this)}; } +Number::operator MPTAmount() const +{ + return MPTAmount{static_cast(*this)}; +} + std::string to_string(Number const& amount) { diff --git a/src/libxrpl/protocol/Asset.cpp b/src/libxrpl/protocol/Asset.cpp new file mode 100644 index 00000000000..67323f8614b --- /dev/null +++ b/src/libxrpl/protocol/Asset.cpp @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 +#include +#include + +namespace ripple { + +AccountID const& +Asset::getIssuer() const +{ + return std::visit( + [&](auto&& issue) -> AccountID const& { return issue.getIssuer(); }, + issue_); +} + +std::string +Asset::getText() const +{ + return std::visit([&](auto&& issue) { return issue.getText(); }, issue_); +} + +void +Asset::setJson(Json::Value& jv) const +{ + std::visit([&](auto&& issue) { issue.setJson(jv); }, issue_); +} + +std::string +to_string(Asset const& asset) +{ + return std::visit( + [&](auto const& issue) { return to_string(issue); }, asset.value()); +} + +bool +validJSONAsset(Json::Value const& jv) +{ + if (jv.isMember(jss::mpt_issuance_id)) + return !(jv.isMember(jss::currency) || jv.isMember(jss::issuer)); + return jv.isMember(jss::currency); +} + +Asset +assetFromJson(Json::Value const& v) +{ + if (!v.isMember(jss::currency) && !v.isMember(jss::mpt_issuance_id)) + Throw( + "assetFromJson must contain currency or mpt_issuance_id"); + + if (v.isMember(jss::currency)) + return issueFromJson(v); + return mptIssueFromJson(v); +} + +} // namespace ripple diff --git a/src/libxrpl/protocol/Indexes.cpp b/src/libxrpl/protocol/Indexes.cpp index 30d97416cfa..9a537eaaf2b 100644 --- a/src/libxrpl/protocol/Indexes.cpp +++ b/src/libxrpl/protocol/Indexes.cpp @@ -73,6 +73,8 @@ enum class LedgerNameSpace : std::uint16_t { XCHAIN_CREATE_ACCOUNT_CLAIM_ID = 'K', DID = 'I', ORACLE = 'R', + MPTOKEN_ISSUANCE = '~', + MPTOKEN = 't', // No longer used or supported. Left here to reserve the space // to avoid accidental reuse. @@ -135,6 +137,16 @@ getTicketIndex(AccountID const& account, SeqProxy ticketSeq) return getTicketIndex(account, ticketSeq.value()); } +MPTID +makeMptID(std::uint32_t sequence, AccountID const& account) +{ + MPTID u; + sequence = boost::endian::native_to_big(sequence); + memcpy(u.data(), &sequence, sizeof(sequence)); + memcpy(u.data() + sizeof(sequence), account.data(), sizeof(account)); + return u; +} + //------------------------------------------------------------------------------ namespace keylet { @@ -451,6 +463,32 @@ oracle(AccountID const& account, std::uint32_t const& documentID) noexcept return {ltORACLE, indexHash(LedgerNameSpace::ORACLE, account, documentID)}; } +Keylet +mptIssuance(std::uint32_t seq, AccountID const& issuer) noexcept +{ + return mptIssuance(makeMptID(seq, issuer)); +} + +Keylet +mptIssuance(MPTID const& issuanceID) noexcept +{ + return { + ltMPTOKEN_ISSUANCE, + indexHash(LedgerNameSpace::MPTOKEN_ISSUANCE, issuanceID)}; +} + +Keylet +mptoken(MPTID const& issuanceID, AccountID const& holder) noexcept +{ + return mptoken(mptIssuance(issuanceID).key, holder); +} + +Keylet +mptoken(uint256 const& issuanceKey, AccountID const& holder) noexcept +{ + return { + ltMPTOKEN, indexHash(LedgerNameSpace::MPTOKEN, issuanceKey, holder)}; +} } // namespace keylet } // namespace ripple diff --git a/src/libxrpl/protocol/Issue.cpp b/src/libxrpl/protocol/Issue.cpp index 70d2c013d7b..179cb1eb14a 100644 --- a/src/libxrpl/protocol/Issue.cpp +++ b/src/libxrpl/protocol/Issue.cpp @@ -49,6 +49,20 @@ Issue::getText() const return ret; } +void +Issue::setJson(Json::Value& jv) const +{ + jv[jss::currency] = to_string(currency); + if (!isXRP(currency)) + jv[jss::issuer] = toBase58(account); +} + +bool +Issue::native() const +{ + return *this == xrpIssue(); +} + bool isConsistent(Issue const& ac) { @@ -68,9 +82,7 @@ Json::Value to_json(Issue const& is) { Json::Value jv; - jv[jss::currency] = to_string(is.currency); - if (!isXRP(is.currency)) - jv[jss::issuer] = toBase58(is.account); + is.setJson(jv); return jv; } @@ -83,6 +95,12 @@ issueFromJson(Json::Value const& v) "issueFromJson can only be specified with an 'object' Json value"); } + if (v.isMember(jss::mpt_issuance_id)) + { + Throw( + "issueFromJson, Issue should not have mpt_issuance_id"); + } + Json::Value const curStr = v[jss::currency]; Json::Value const issStr = v[jss::issuer]; diff --git a/src/libxrpl/protocol/MPTIssue.cpp b/src/libxrpl/protocol/MPTIssue.cpp new file mode 100644 index 00000000000..38022a0ed3a --- /dev/null +++ b/src/libxrpl/protocol/MPTIssue.cpp @@ -0,0 +1,107 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 +#include +#include + +namespace ripple { + +MPTIssue::MPTIssue(MPTID const& issuanceID) : mptID_(issuanceID) +{ +} + +AccountID const& +MPTIssue::getIssuer() const +{ + // MPTID is concatenation of sequence + account + static_assert(sizeof(MPTID) == (sizeof(std::uint32_t) + sizeof(AccountID))); + // copy from id skipping the sequence + AccountID const* account = reinterpret_cast( + mptID_.data() + sizeof(std::uint32_t)); + + return *account; +} + +MPTID const& +MPTIssue::getMptID() const +{ + return mptID_; +} + +std::string +MPTIssue::getText() const +{ + return to_string(mptID_); +} + +void +MPTIssue::setJson(Json::Value& jv) const +{ + jv[jss::mpt_issuance_id] = to_string(mptID_); +} + +Json::Value +to_json(MPTIssue const& mptIssue) +{ + Json::Value jv; + mptIssue.setJson(jv); + return jv; +} + +std::string +to_string(MPTIssue const& mptIssue) +{ + return to_string(mptIssue.getMptID()); +} + +MPTIssue +mptIssueFromJson(Json::Value const& v) +{ + if (!v.isObject()) + { + Throw( + "mptIssueFromJson can only be specified with an 'object' Json " + "value"); + } + + if (v.isMember(jss::currency) || v.isMember(jss::issuer)) + { + Throw( + "mptIssueFromJson, MPTIssue should not have currency or issuer"); + } + + Json::Value const& idStr = v[jss::mpt_issuance_id]; + + if (!idStr.isString()) + { + Throw( + "mptIssueFromJson MPTID must be a string Json value"); + } + + MPTID id; + if (!id.parseHex(idStr.asString())) + { + Throw("mptIssueFromJson MPTID is invalid"); + } + + return MPTIssue{id}; +} + +} // namespace ripple diff --git a/src/libxrpl/protocol/Quality.cpp b/src/libxrpl/protocol/Quality.cpp index 38b641328b0..c6464eba9d2 100644 --- a/src/libxrpl/protocol/Quality.cpp +++ b/src/libxrpl/protocol/Quality.cpp @@ -65,7 +65,7 @@ Quality::operator--(int) } template + *DivRoundFunc)(STAmount const&, STAmount const&, Asset const&, bool)> static Amounts ceil_in_impl( Amounts const& amount, @@ -77,7 +77,7 @@ ceil_in_impl( { Amounts result( limit, - DivRoundFunc(limit, quality.rate(), amount.out.issue(), roundUp)); + DivRoundFunc(limit, quality.rate(), amount.out.asset(), roundUp)); // Clamp out if (result.out > amount.out) result.out = amount.out; @@ -104,7 +104,7 @@ Quality::ceil_in_strict( } template + *MulRoundFunc)(STAmount const&, STAmount const&, Asset const&, bool)> static Amounts ceil_out_impl( Amounts const& amount, @@ -115,7 +115,7 @@ ceil_out_impl( if (amount.out > limit) { Amounts result( - MulRoundFunc(limit, quality.rate(), amount.in.issue(), roundUp), + MulRoundFunc(limit, quality.rate(), amount.in.asset(), roundUp), limit); // Clamp in if (result.in > amount.in) @@ -151,7 +151,7 @@ composed_quality(Quality const& lhs, Quality const& rhs) STAmount const rhs_rate(rhs.rate()); assert(rhs_rate != beast::zero); - STAmount const rate(mulRound(lhs_rate, rhs_rate, lhs_rate.issue(), true)); + STAmount const rate(mulRound(lhs_rate, rhs_rate, lhs_rate.asset(), true)); std::uint64_t const stored_exponent(rate.exponent() + 100); std::uint64_t const stored_mantissa(rate.mantissa()); diff --git a/src/libxrpl/protocol/Rate2.cpp b/src/libxrpl/protocol/Rate2.cpp index d85a49a5958..33bd9c5d0be 100644 --- a/src/libxrpl/protocol/Rate2.cpp +++ b/src/libxrpl/protocol/Rate2.cpp @@ -51,7 +51,7 @@ multiply(STAmount const& amount, Rate const& rate) if (rate == parityRate) return amount; - return multiply(amount, detail::as_amount(rate), amount.issue()); + return multiply(amount, detail::as_amount(rate), amount.asset()); } STAmount @@ -62,14 +62,14 @@ multiplyRound(STAmount const& amount, Rate const& rate, bool roundUp) if (rate == parityRate) return amount; - return mulRound(amount, detail::as_amount(rate), amount.issue(), roundUp); + return mulRound(amount, detail::as_amount(rate), amount.asset(), roundUp); } STAmount multiplyRound( STAmount const& amount, Rate const& rate, - Issue const& issue, + Asset const& asset, bool roundUp) { assert(rate.value != 0); @@ -79,7 +79,7 @@ multiplyRound( return amount; } - return mulRound(amount, detail::as_amount(rate), issue, roundUp); + return mulRound(amount, detail::as_amount(rate), asset, roundUp); } STAmount @@ -90,7 +90,7 @@ divide(STAmount const& amount, Rate const& rate) if (rate == parityRate) return amount; - return divide(amount, detail::as_amount(rate), amount.issue()); + return divide(amount, detail::as_amount(rate), amount.asset()); } STAmount @@ -101,14 +101,14 @@ divideRound(STAmount const& amount, Rate const& rate, bool roundUp) if (rate == parityRate) return amount; - return divRound(amount, detail::as_amount(rate), amount.issue(), roundUp); + return divRound(amount, detail::as_amount(rate), amount.asset(), roundUp); } STAmount divideRound( STAmount const& amount, Rate const& rate, - Issue const& issue, + Asset const& asset, bool roundUp) { assert(rate.value != 0); @@ -116,7 +116,7 @@ divideRound( if (rate == parityRate) return amount; - return divRound(amount, detail::as_amount(rate), issue, roundUp); + return divRound(amount, detail::as_amount(rate), asset, roundUp); } } // namespace ripple diff --git a/src/libxrpl/protocol/STAmount.cpp b/src/libxrpl/protocol/STAmount.cpp index bb9a24c1271..fe13118d88c 100644 --- a/src/libxrpl/protocol/STAmount.cpp +++ b/src/libxrpl/protocol/STAmount.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -63,10 +64,11 @@ static const std::uint64_t tenTo17 = tenTo14 * 1000; //------------------------------------------------------------------------------ static std::int64_t -getSNValue(STAmount const& amount) +getInt64Value(STAmount const& amount, bool valid, const char* error) { - if (!amount.native()) - Throw("amount is not native!"); + if (!valid) + Throw(error); + assert(amount.exponent() == 0); auto ret = static_cast(amount.mantissa()); @@ -78,26 +80,53 @@ getSNValue(STAmount const& amount) return ret; } +static std::int64_t +getSNValue(STAmount const& amount) +{ + return getInt64Value(amount, amount.native(), "amount is not native!"); +} + +static std::int64_t +getMPTValue(STAmount const& amount) +{ + return getInt64Value( + amount, amount.holds(), "amount is not MPT!"); +} + static bool areComparable(STAmount const& v1, STAmount const& v2) { - return v1.native() == v2.native() && - v1.issue().currency == v2.issue().currency; + if (v1.holds() && v2.holds()) + return v1.native() == v2.native() && + v1.get().currency == v2.get().currency; + if (v1.holds() && v2.holds()) + return v1.get() == v2.get(); + return false; } STAmount::STAmount(SerialIter& sit, SField const& name) : STBase(name) { std::uint64_t value = sit.get64(); - // native - if ((value & cNotNative) == 0) + // native or MPT + if ((value & cIssuedCurrency) == 0) { + if ((value & cMPToken) != 0) + { + // is MPT + mOffset = 0; + mIsNegative = (value & cPositive) == 0; + mValue = (value << 8) | sit.get8(); + mAsset = sit.get192(); + return; + } + // else is XRP + mAsset = xrpIssue(); // positive - if ((value & cPosNative) != 0) + if ((value & cPositive) != 0) { - mValue = value & ~cPosNative; + mValue = value & cValueMask; mOffset = 0; - mIsNative = true; mIsNegative = false; return; } @@ -106,9 +135,8 @@ STAmount::STAmount(SerialIter& sit, SField const& name) : STBase(name) if (value == 0) Throw("negative zero is not canonical"); - mValue = value; + mValue = value & cValueMask; mOffset = 0; - mIsNative = true; mIsNegative = true; return; } @@ -140,7 +168,7 @@ STAmount::STAmount(SerialIter& sit, SField const& name) : STBase(name) Throw("invalid currency value"); } - mIssue = issue; + mAsset = issue; mValue = value; mOffset = offset; mIsNegative = isNegative; @@ -151,97 +179,32 @@ STAmount::STAmount(SerialIter& sit, SField const& name) : STBase(name) if (offset != 512) Throw("invalid currency value"); - mIssue = issue; + mAsset = issue; mValue = 0; mOffset = 0; mIsNegative = false; canonicalize(); } -STAmount::STAmount( - SField const& name, - Issue const& issue, - mantissa_type mantissa, - exponent_type exponent, - bool native, - bool negative, - unchecked) - : STBase(name) - , mIssue(issue) - , mValue(mantissa) - , mOffset(exponent) - , mIsNative(native) - , mIsNegative(negative) -{ -} - -STAmount::STAmount( - Issue const& issue, - mantissa_type mantissa, - exponent_type exponent, - bool native, - bool negative, - unchecked) - : mIssue(issue) - , mValue(mantissa) - , mOffset(exponent) - , mIsNative(native) - , mIsNegative(negative) -{ -} - -STAmount::STAmount( - SField const& name, - Issue const& issue, - mantissa_type mantissa, - exponent_type exponent, - bool native, - bool negative) - : STBase(name) - , mIssue(issue) - , mValue(mantissa) - , mOffset(exponent) - , mIsNative(native) - , mIsNegative(negative) -{ - canonicalize(); -} - STAmount::STAmount(SField const& name, std::int64_t mantissa) - : STBase(name), mOffset(0), mIsNative(true) + : STBase(name), mAsset(xrpIssue()), mOffset(0) { set(mantissa); } STAmount::STAmount(SField const& name, std::uint64_t mantissa, bool negative) : STBase(name) + , mAsset(xrpIssue()) , mValue(mantissa) , mOffset(0) - , mIsNative(true) - , mIsNegative(negative) -{ - assert(mValue <= std::numeric_limits::max()); -} - -STAmount::STAmount( - SField const& name, - Issue const& issue, - std::uint64_t mantissa, - int exponent, - bool negative) - : STBase(name) - , mIssue(issue) - , mValue(mantissa) - , mOffset(exponent) , mIsNegative(negative) { assert(mValue <= std::numeric_limits::max()); - canonicalize(); } STAmount::STAmount(SField const& name, STAmount const& from) : STBase(name) - , mIssue(from.mIssue) + , mAsset(from.mAsset) , mValue(from.mValue) , mOffset(from.mOffset) , mIsNegative(from.mIsNegative) @@ -253,62 +216,16 @@ STAmount::STAmount(SField const& name, STAmount const& from) //------------------------------------------------------------------------------ STAmount::STAmount(std::uint64_t mantissa, bool negative) - : mValue(mantissa) + : mAsset(xrpIssue()) + , mValue(mantissa) , mOffset(0) - , mIsNative(true) , mIsNegative(mantissa != 0 && negative) { assert(mValue <= std::numeric_limits::max()); } -STAmount::STAmount( - Issue const& issue, - std::uint64_t mantissa, - int exponent, - bool negative) - : mIssue(issue), mValue(mantissa), mOffset(exponent), mIsNegative(negative) -{ - canonicalize(); -} - -STAmount::STAmount(Issue const& issue, std::int64_t mantissa, int exponent) - : mIssue(issue), mOffset(exponent) -{ - set(mantissa); - canonicalize(); -} - -STAmount::STAmount( - Issue const& issue, - std::uint32_t mantissa, - int exponent, - bool negative) - : STAmount(issue, safe_cast(mantissa), exponent, negative) -{ -} - -STAmount::STAmount(Issue const& issue, int mantissa, int exponent) - : STAmount(issue, safe_cast(mantissa), exponent) -{ -} - -// Legacy support for new-style amounts -STAmount::STAmount(IOUAmount const& amount, Issue const& issue) - : mIssue(issue) - , mOffset(amount.exponent()) - , mIsNative(false) - , mIsNegative(amount < beast::zero) -{ - if (mIsNegative) - mValue = static_cast(-amount.mantissa()); - else - mValue = static_cast(amount.mantissa()); - - canonicalize(); -} - STAmount::STAmount(XRPAmount const& amount) - : mOffset(0), mIsNative(true), mIsNegative(amount < beast::zero) + : mAsset(xrpIssue()), mOffset(0), mIsNegative(amount < beast::zero) { if (mIsNegative) mValue = unsafe_cast(-amount.drops()); @@ -344,7 +261,7 @@ STAmount::move(std::size_t n, void* buf) XRPAmount STAmount::xrp() const { - if (!mIsNative) + if (!native()) Throw( "Cannot return non-native STAmount as XRPAmount"); @@ -359,8 +276,8 @@ STAmount::xrp() const IOUAmount STAmount::iou() const { - if (mIsNative) - Throw("Cannot return native STAmount as IOUAmount"); + if (native() || !holds()) + Throw("Cannot return non-IOU STAmount as IOUAmount"); auto mantissa = static_cast(mValue); auto exponent = mOffset; @@ -371,10 +288,24 @@ STAmount::iou() const return {mantissa, exponent}; } +MPTAmount +STAmount::mpt() const +{ + if (!holds()) + Throw("Cannot return STAmount as MPTAmount"); + + auto value = static_cast(mValue); + + if (mIsNegative) + value = -value; + + return MPTAmount{value}; +} + STAmount& STAmount::operator=(IOUAmount const& iou) { - assert(mIsNative == false); + assert(native() == false); mOffset = iou.exponent(); mIsNegative = iou < beast::zero; if (mIsNegative) @@ -418,7 +349,7 @@ operator+(STAmount const& v1, STAmount const& v2) // Result must be in terms of v1 currency and issuer. return { v1.getFName(), - v1.issue(), + v1.asset(), v2.mantissa(), v2.exponent(), v2.negative()}; @@ -426,6 +357,8 @@ operator+(STAmount const& v1, STAmount const& v2) if (v1.native()) return {v1.getFName(), getSNValue(v1) + getSNValue(v2)}; + if (v1.holds()) + return {v1.mAsset, v1.mpt().value() + v2.mpt().value()}; if (getSTNumberSwitchover()) { @@ -462,18 +395,18 @@ operator+(STAmount const& v1, STAmount const& v2) std::int64_t fv = vv1 + vv2; if ((fv >= -10) && (fv <= 10)) - return {v1.getFName(), v1.issue()}; + return {v1.getFName(), v1.asset()}; if (fv >= 0) return STAmount{ v1.getFName(), - v1.issue(), + v1.asset(), static_cast(fv), ov1, false}; return STAmount{ - v1.getFName(), v1.issue(), static_cast(-fv), ov1, true}; + v1.getFName(), v1.asset(), static_cast(-fv), ov1, true}; } STAmount @@ -487,10 +420,9 @@ operator-(STAmount const& v1, STAmount const& v2) std::uint64_t const STAmount::uRateOne = getRate(STAmount(1), STAmount(1)); void -STAmount::setIssue(Issue const& issue) +STAmount::setIssue(Asset const& asset) { - mIssue = issue; - mIsNative = isXRP(*this); + mAsset = asset; } // Convert an offer into an index amount so they sort by rate. @@ -529,13 +461,12 @@ STAmount::setJson(Json::Value& elem) const { elem = Json::objectValue; - if (!mIsNative) + if (!native()) { // It is an error for currency or issuer not to be specified for valid // json. elem[jss::value] = getText(); - elem[jss::currency] = to_string(mIssue.currency); - elem[jss::issuer] = to_string(mIssue.account); + mAsset.setJson(elem); } else { @@ -561,7 +492,7 @@ STAmount::getFullText() const std::string ret; ret.reserve(64); - ret = getText() + "/" + mIssue.getText(); + ret = getText() + "/" + mAsset.getText(); return ret; } @@ -581,7 +512,7 @@ STAmount::getText() const bool const scientific( (mOffset != 0) && ((mOffset < -25) || (mOffset > -5))); - if (mIsNative || scientific) + if (native() || mAsset.holds() || scientific) { ret.append(raw_value); @@ -661,19 +592,28 @@ STAmount::getJson(JsonOptions) const void STAmount::add(Serializer& s) const { - if (mIsNative) + if (native()) { assert(mOffset == 0); if (!mIsNegative) - s.add64(mValue | cPosNative); + s.add64(mValue | cPositive); else s.add64(mValue); } + else if (mAsset.holds()) + { + auto u8 = static_cast(cMPToken >> 56); + if (!mIsNegative) + u8 |= static_cast(cPositive >> 56); + s.add8(u8); + s.add64(mValue); + s.addBitString(mAsset.get().getMptID()); + } else { if (*this == beast::zero) - s.add64(cNotNative); + s.add64(cIssuedCurrency); else if (mIsNegative) // 512 = not native s.add64( mValue | @@ -683,9 +623,8 @@ STAmount::add(Serializer& s) const mValue | (static_cast(mOffset + 512 + 256 + 97) << (64 - 10))); - - s.addBitString(mIssue.currency); - s.addBitString(mIssue.account); + s.addBitString(mAsset.get().currency); + s.addBitString(mAsset.get().account); } } @@ -699,7 +638,7 @@ STAmount::isEquivalent(const STBase& t) const bool STAmount::isDefault() const { - return (mValue == 0) && mIsNative; + return (mValue == 0) && native(); } //------------------------------------------------------------------------------ @@ -723,11 +662,9 @@ STAmount::isDefault() const void STAmount::canonicalize() { - if (isXRP(*this)) + if (native() || mAsset.holds()) { - // native currency amounts should always have an offset of zero - mIsNative = true; - + // native and MPT currency amounts should always have an offset of zero // log(2^64,10) ~ 19.2 if (mValue == 0 || mOffset <= -20) { @@ -740,18 +677,26 @@ STAmount::canonicalize() if (getSTAmountCanonicalizeSwitchover()) { // log(cMaxNativeN, 10) == 17 - if (mOffset > 17) + if (native() && mOffset > 17) Throw( "Native currency amount out of range"); + // log(maxMPTokenAmount, 10) ~ 18.96 + if (mAsset.holds() && mOffset > 18) + Throw("MPT amount out of range"); } if (getSTNumberSwitchover() && getSTAmountCanonicalizeSwitchover()) { Number num( mIsNegative ? -mValue : mValue, mOffset, Number::unchecked{}); - XRPAmount xrp{num}; - mIsNegative = xrp.drops() < 0; - mValue = mIsNegative ? -xrp.drops() : xrp.drops(); + auto set = [&](auto const& val) { + mIsNegative = val.value() < 0; + mValue = mIsNegative ? -val.value() : val.value(); + }; + if (native()) + set(XRPAmount{num}); + else + set(MPTAmount{num}); mOffset = 0; } else @@ -768,23 +713,25 @@ STAmount::canonicalize() { // N.B. do not move the overflow check to after the // multiplication - if (mValue > cMaxNativeN) + if (native() && mValue > cMaxNativeN) Throw( "Native currency amount out of range"); + else if (!native() && mValue > maxMPTokenAmount) + Throw("MPT amount out of range"); } mValue *= 10; --mOffset; } } - if (mValue > cMaxNativeN) + if (native() && mValue > cMaxNativeN) Throw("Native currency amount out of range"); + else if (!native() && mValue > maxMPTokenAmount) + Throw("MPT amount out of range"); return; } - mIsNative = false; - if (getSTNumberSwitchover()) { *this = iou(); @@ -860,7 +807,7 @@ amountFromQuality(std::uint64_t rate) } STAmount -amountFromString(Issue const& issue, std::string const& amount) +amountFromString(Asset const& asset, std::string const& amount) { static boost::regex const reNumber( "^" // the beginning of the string @@ -892,9 +839,10 @@ amountFromString(Issue const& issue, std::string const& amount) bool negative = (match[1].matched && (match[1] == "-")); - // Can't specify XRP using fractional representation - if (isXRP(issue) && match[3].matched) - Throw("XRP must be specified in integral drops."); + // Can't specify XRP or MPT using fractional representation + if ((asset.native() || asset.holds()) && match[3].matched) + Throw( + "XRP and MPT must be specified as integral amount."); std::uint64_t mantissa; int exponent; @@ -921,7 +869,7 @@ amountFromString(Issue const& issue, std::string const& amount) exponent += beast::lexicalCastThrow(std::string(match[7])); } - return {issue, mantissa, exponent, negative}; + return {asset, mantissa, exponent, negative}; } STAmount @@ -930,11 +878,12 @@ amountFromJson(SField const& name, Json::Value const& v) STAmount::mantissa_type mantissa = 0; STAmount::exponent_type exponent = 0; bool negative = false; - Issue issue; + Asset asset; Json::Value value; - Json::Value currency; + Json::Value currencyOrMPTID; Json::Value issuer; + bool isMPT = false; if (v.isNull()) { @@ -943,14 +892,25 @@ amountFromJson(SField const& name, Json::Value const& v) } else if (v.isObject()) { + if (!validJSONAsset(v)) + Throw("Invalid Asset's Json specification"); + value = v[jss::value]; - currency = v[jss::currency]; - issuer = v[jss::issuer]; + if (v.isMember(jss::mpt_issuance_id)) + { + isMPT = true; + currencyOrMPTID = v[jss::mpt_issuance_id]; + } + else + { + currencyOrMPTID = v[jss::currency]; + issuer = v[jss::issuer]; + } } else if (v.isArray()) { value = v.get(Json::UInt(0), 0); - currency = v.get(Json::UInt(1), Json::nullValue); + currencyOrMPTID = v.get(Json::UInt(1), Json::nullValue); issuer = v.get(Json::UInt(2), Json::nullValue); } else if (v.isString()) @@ -965,7 +925,7 @@ amountFromJson(SField const& name, Json::Value const& v) value = elements[0]; if (elements.size() > 1) - currency = elements[1]; + currencyOrMPTID = elements[1]; if (elements.size() > 2) issuer = elements[2]; @@ -975,26 +935,38 @@ amountFromJson(SField const& name, Json::Value const& v) value = v; } - bool const native = !currency.isString() || currency.asString().empty() || - (currency.asString() == systemCurrencyCode()); + bool const native = !currencyOrMPTID.isString() || + currencyOrMPTID.asString().empty() || + (currencyOrMPTID.asString() == systemCurrencyCode()); if (native) { if (v.isObjectOrNull()) Throw("XRP may not be specified as an object"); - issue = xrpIssue(); + asset = xrpIssue(); } else { - // non-XRP - if (!to_currency(issue.currency, currency.asString())) - Throw("invalid currency"); - - if (!issuer.isString() || !to_issuer(issue.account, issuer.asString())) - Throw("invalid issuer"); - - if (isXRP(issue.currency)) - Throw("invalid issuer"); + if (isMPT) + { + // sequence (32 bits) + account (160 bits) + uint192 u; + if (!u.parseHex(currencyOrMPTID.asString())) + Throw("invalid MPTokenIssuanceID"); + asset = u; + } + else + { + Issue issue; + if (!to_currency(issue.currency, currencyOrMPTID.asString())) + Throw("invalid currency"); + if (!issuer.isString() || + !to_issuer(issue.account, issuer.asString())) + Throw("invalid issuer"); + if (issue.native()) + Throw("invalid issuer"); + asset = issue; + } } if (value.isInt()) @@ -1015,7 +987,7 @@ amountFromJson(SField const& name, Json::Value const& v) } else if (value.isString()) { - auto const ret = amountFromString(issue, value.asString()); + auto const ret = amountFromString(asset, value.asString()); mantissa = ret.mantissa(); exponent = ret.exponent(); @@ -1026,7 +998,7 @@ amountFromJson(SField const& name, Json::Value const& v) Throw("invalid amount type"); } - return {name, issue, mantissa, exponent, native, negative}; + return {name, asset, mantissa, exponent, negative}; } bool @@ -1100,10 +1072,9 @@ operator-(STAmount const& value) return value; return STAmount( value.getFName(), - value.issue(), + value.asset(), value.mantissa(), value.exponent(), - value.native(), !value.negative(), STAmount::unchecked{}); } @@ -1162,20 +1133,20 @@ muldiv_round( } STAmount -divide(STAmount const& num, STAmount const& den, Issue const& issue) +divide(STAmount const& num, STAmount const& den, Asset const& asset) { if (den == beast::zero) Throw("division by zero"); if (num == beast::zero) - return {issue}; + return {asset}; std::uint64_t numVal = num.mantissa(); std::uint64_t denVal = den.mantissa(); int numOffset = num.exponent(); int denOffset = den.exponent(); - if (num.native()) + if (num.native() || num.holds()) { while (numVal < STAmount::cMinValue) { @@ -1185,7 +1156,7 @@ divide(STAmount const& num, STAmount const& den, Issue const& issue) } } - if (den.native()) + if (den.native() || den.holds()) { while (denVal < STAmount::cMinValue) { @@ -1200,24 +1171,22 @@ divide(STAmount const& num, STAmount const& den, Issue const& issue) // 10^32 to 10^33) followed by a division, so the result // is in the range of 10^16 to 10^15. return STAmount( - issue, + asset, muldiv(numVal, tenTo17, denVal) + 5, numOffset - denOffset - 17, num.negative() != den.negative()); } STAmount -multiply(STAmount const& v1, STAmount const& v2, Issue const& issue) +multiply(STAmount const& v1, STAmount const& v2, Asset const& asset) { if (v1 == beast::zero || v2 == beast::zero) - return STAmount(issue); + return STAmount(asset); - if (v1.native() && v2.native() && isXRP(issue)) + if (v1.native() && v2.native() && asset.native()) { - std::uint64_t const minV = - getSNValue(v1) < getSNValue(v2) ? getSNValue(v1) : getSNValue(v2); - std::uint64_t const maxV = - getSNValue(v1) < getSNValue(v2) ? getSNValue(v2) : getSNValue(v1); + std::uint64_t const minV = std::min(getSNValue(v1), getSNValue(v2)); + std::uint64_t const maxV = std::max(getSNValue(v1), getSNValue(v2)); if (minV > 3000000000ull) // sqrt(cMaxNative) Throw("Native value overflow"); @@ -1227,16 +1196,32 @@ multiply(STAmount const& v1, STAmount const& v2, Issue const& issue) return STAmount(v1.getFName(), minV * maxV); } + if (v1.holds() && v2.holds() && asset.holds()) + { + std::uint64_t const minV = std::min(getMPTValue(v1), getMPTValue(v2)); + std::uint64_t const maxV = std::max(getMPTValue(v1), getMPTValue(v2)); + + if (minV > 3037000499ull) // sqrt(maxMPTokenAmount) ~ 3037000499.98 + Throw("MPT value overflow"); + + if (((maxV >> 32) * minV) > 2147483648ull) // maxMPTokenAmount / 2^32 + Throw("MPT value overflow"); + + return STAmount(asset, minV * maxV); + } if (getSTNumberSwitchover()) - return {IOUAmount{Number{v1} * Number{v2}}, issue}; + { + auto const r = Number{v1} * Number{v2}; + return STAmount{asset, r.mantissa(), r.exponent()}; + } std::uint64_t value1 = v1.mantissa(); std::uint64_t value2 = v2.mantissa(); int offset1 = v1.exponent(); int offset2 = v2.exponent(); - if (v1.native()) + if (v1.native() || v1.holds()) { while (value1 < STAmount::cMinValue) { @@ -1245,7 +1230,7 @@ multiply(STAmount const& v1, STAmount const& v2, Issue const& issue) } } - if (v2.native()) + if (v2.native() || v2.holds()) { while (value2 < STAmount::cMinValue) { @@ -1259,7 +1244,7 @@ multiply(STAmount const& v1, STAmount const& v2, Issue const& issue) // range. Dividing their product by 10^14 maintains the // precision, by scaling the result to 10^16 to 10^18. return STAmount( - issue, + asset, muldiv(value1, value2, tenTo14) + 7, offset1 + offset2 + 14, v1.negative() != v2.negative()); @@ -1396,20 +1381,18 @@ static STAmount mulRoundImpl( STAmount const& v1, STAmount const& v2, - Issue const& issue, + Asset const& asset, bool roundUp) { if (v1 == beast::zero || v2 == beast::zero) - return {issue}; + return {asset}; - bool const xrp = isXRP(issue); + bool const xrp = asset.native(); if (v1.native() && v2.native() && xrp) { - std::uint64_t minV = - (getSNValue(v1) < getSNValue(v2)) ? getSNValue(v1) : getSNValue(v2); - std::uint64_t maxV = - (getSNValue(v1) < getSNValue(v2)) ? getSNValue(v2) : getSNValue(v1); + std::uint64_t minV = std::min(getSNValue(v1), getSNValue(v2)); + std::uint64_t maxV = std::max(getSNValue(v1), getSNValue(v2)); if (minV > 3000000000ull) // sqrt(cMaxNative) Throw("Native value overflow"); @@ -1420,10 +1403,24 @@ mulRoundImpl( return STAmount(v1.getFName(), minV * maxV); } + if (v1.holds() && v2.holds() && asset.holds()) + { + std::uint64_t const minV = std::min(getMPTValue(v1), getMPTValue(v2)); + std::uint64_t const maxV = std::max(getMPTValue(v1), getMPTValue(v2)); + + if (minV > 3037000499ull) // sqrt(maxMPTokenAmount) ~ 3037000499.98 + Throw("MPT value overflow"); + + if (((maxV >> 32) * minV) > 2147483648ull) // maxMPTokenAmount / 2^32 + Throw("MPT value overflow"); + + return STAmount(asset, minV * maxV); + } + std::uint64_t value1 = v1.mantissa(), value2 = v2.mantissa(); int offset1 = v1.exponent(), offset2 = v2.exponent(); - if (v1.native()) + if (v1.native() || v1.holds()) { while (value1 < STAmount::cMinValue) { @@ -1432,7 +1429,7 @@ mulRoundImpl( } } - if (v2.native()) + if (v2.native() || v2.holds()) { while (value2 < STAmount::cMinValue) { @@ -1463,7 +1460,7 @@ mulRoundImpl( // If appropriate, tell Number to round down. This gives the desired // result from STAmount::canonicalize. MightSaveRound const savedRound(Number::towards_zero); - return STAmount(issue, amount, offset, resultNegative); + return STAmount(asset, amount, offset, resultNegative); }(); if (roundUp && !resultNegative && !result) @@ -1480,7 +1477,7 @@ mulRoundImpl( amount = STAmount::cMinValue; offset = STAmount::cMinOffset; } - return STAmount(issue, amount, offset, resultNegative); + return STAmount(asset, amount, offset, resultNegative); } return result; } @@ -1489,22 +1486,22 @@ STAmount mulRound( STAmount const& v1, STAmount const& v2, - Issue const& issue, + Asset const& asset, bool roundUp) { return mulRoundImpl( - v1, v2, issue, roundUp); + v1, v2, asset, roundUp); } STAmount mulRoundStrict( STAmount const& v1, STAmount const& v2, - Issue const& issue, + Asset const& asset, bool roundUp) { return mulRoundImpl( - v1, v2, issue, roundUp); + v1, v2, asset, roundUp); } // We might need to use NumberRoundModeGuard. Allow the caller @@ -1514,19 +1511,19 @@ static STAmount divRoundImpl( STAmount const& num, STAmount const& den, - Issue const& issue, + Asset const& asset, bool roundUp) { if (den == beast::zero) Throw("division by zero"); if (num == beast::zero) - return {issue}; + return {asset}; std::uint64_t numVal = num.mantissa(), denVal = den.mantissa(); int numOffset = num.exponent(), denOffset = den.exponent(); - if (num.native()) + if (num.native() || num.holds()) { while (numVal < STAmount::cMinValue) { @@ -1535,7 +1532,7 @@ divRoundImpl( } } - if (den.native()) + if (den.native() || den.holds()) { while (denVal < STAmount::cMinValue) { @@ -1560,7 +1557,8 @@ divRoundImpl( int offset = numOffset - denOffset - 17; if (resultNegative != roundUp) - canonicalizeRound(isXRP(issue), amount, offset, roundUp); + canonicalizeRound( + asset.native() || asset.holds(), amount, offset, roundUp); STAmount result = [&]() { // If appropriate, tell Number the rounding mode we are using. @@ -1569,12 +1567,12 @@ divRoundImpl( using enum Number::rounding_mode; MightSaveRound const savedRound( roundUp ^ resultNegative ? upward : downward); - return STAmount(issue, amount, offset, resultNegative); + return STAmount(asset, amount, offset, resultNegative); }(); if (roundUp && !resultNegative && !result) { - if (isXRP(issue)) + if (asset.native() || asset.holds()) { // return the smallest value above zero amount = 1; @@ -1586,7 +1584,7 @@ divRoundImpl( amount = STAmount::cMinValue; offset = STAmount::cMinOffset; } - return STAmount(issue, amount, offset, resultNegative); + return STAmount(asset, amount, offset, resultNegative); } return result; } @@ -1595,20 +1593,20 @@ STAmount divRound( STAmount const& num, STAmount const& den, - Issue const& issue, + Asset const& asset, bool roundUp) { - return divRoundImpl(num, den, issue, roundUp); + return divRoundImpl(num, den, asset, roundUp); } STAmount divRoundStrict( STAmount const& num, STAmount const& den, - Issue const& issue, + Asset const& asset, bool roundUp) { - return divRoundImpl(num, den, issue, roundUp); + return divRoundImpl(num, den, asset, roundUp); } } // namespace ripple diff --git a/src/libxrpl/protocol/STInteger.cpp b/src/libxrpl/protocol/STInteger.cpp index af0c18a5155..7dfcc50dea0 100644 --- a/src/libxrpl/protocol/STInteger.cpp +++ b/src/libxrpl/protocol/STInteger.cpp @@ -198,11 +198,23 @@ template <> Json::Value STUInt64::getJson(JsonOptions) const { - std::string str(16, 0); - auto ret = std::to_chars(str.data(), str.data() + str.size(), value_, 16); - assert(ret.ec == std::errc()); - str.resize(std::distance(str.data(), ret.ptr)); - return str; + auto convertToString = [](uint64_t const value, int const base) { + assert(base == 10 || base == 16); + std::string str( + base == 10 ? 20 : 16, 0); // Allocate space depending on base + auto ret = + std::to_chars(str.data(), str.data() + str.size(), value, base); + assert(ret.ec == std::errc()); + str.resize(std::distance(str.data(), ret.ptr)); + return str; + }; + + if (auto const& fName = getFName(); fName.shouldMeta(SField::sMD_BaseTen)) + { + return convertToString(value_, 10); // Convert to base 10 + } + + return convertToString(value_, 16); // Convert to base 16 } } // namespace ripple diff --git a/src/libxrpl/protocol/STLedgerEntry.cpp b/src/libxrpl/protocol/STLedgerEntry.cpp index 68d1455cb1d..1801149ab2a 100644 --- a/src/libxrpl/protocol/STLedgerEntry.cpp +++ b/src/libxrpl/protocol/STLedgerEntry.cpp @@ -125,6 +125,10 @@ STLedgerEntry::getJson(JsonOptions options) const ret[jss::index] = to_string(key_); + if (getType() == ltMPTOKEN_ISSUANCE) + ret[jss::mpt_issuance_id] = to_string( + makeMptID(getFieldU32(sfSequence), getAccountID(sfIssuer))); + return ret; } diff --git a/src/libxrpl/protocol/STObject.cpp b/src/libxrpl/protocol/STObject.cpp index bde83ec31a1..7e62fc25bd6 100644 --- a/src/libxrpl/protocol/STObject.cpp +++ b/src/libxrpl/protocol/STObject.cpp @@ -604,6 +604,12 @@ STObject::getFieldH160(SField const& field) const return getFieldByValue(field); } +uint192 +STObject::getFieldH192(SField const& field) const +{ + return getFieldByValue(field); +} + uint256 STObject::getFieldH256(SField const& field) const { diff --git a/src/libxrpl/protocol/STParsedJSON.cpp b/src/libxrpl/protocol/STParsedJSON.cpp index 327b9ee31c4..09b6b6679d7 100644 --- a/src/libxrpl/protocol/STParsedJSON.cpp +++ b/src/libxrpl/protocol/STParsedJSON.cpp @@ -398,8 +398,15 @@ parseLeaf( std::uint64_t val; + bool const useBase10 = + field.shouldMeta(SField::sMD_BaseTen); + + // if the field is amount, serialize as base 10 auto [p, ec] = std::from_chars( - str.data(), str.data() + str.size(), val, 16); + str.data(), + str.data() + str.size(), + val, + useBase10 ? 10 : 16); if (ec != std::errc() || (p != str.data() + str.size())) Throw("invalid data"); @@ -454,6 +461,30 @@ parseLeaf( break; } + case STI_UINT192: { + if (!value.isString()) + { + error = bad_type(json_name, fieldName); + return ret; + } + + uint192 num; + + if (auto const s = value.asString(); !num.parseHex(s)) + { + if (!s.empty()) + { + error = invalid_data(json_name, fieldName); + return ret; + } + + num.zero(); + } + + ret = detail::make_stvar(field, num); + break; + } + case STI_UINT160: { if (!value.isString()) { diff --git a/src/libxrpl/protocol/STTx.cpp b/src/libxrpl/protocol/STTx.cpp index 149186d43ce..7bd25246c53 100644 --- a/src/libxrpl/protocol/STTx.cpp +++ b/src/libxrpl/protocol/STTx.cpp @@ -543,6 +543,32 @@ isAccountFieldOkay(STObject const& st) return true; } +static bool +invalidMPTAmountInTx(STObject const& tx) +{ + auto const txType = tx[~sfTransactionType]; + if (!txType) + return false; + if (auto const* item = + TxFormats::getInstance().findByType(safe_cast(*txType))) + { + for (auto const& e : item->getSOTemplate()) + { + if (tx.isFieldPresent(e.sField()) && e.supportMPT() != soeMPTNone) + { + if (auto const& field = tx.peekAtField(e.sField()); + field.getSType() == STI_AMOUNT && + static_cast(field).holds()) + { + if (e.supportMPT() != soeMPTSupported) + return true; + } + } + } + } + return false; +} + bool passesLocalChecks(STObject const& st, std::string& reason) { @@ -560,6 +586,13 @@ passesLocalChecks(STObject const& st, std::string& reason) reason = "Cannot submit pseudo transactions."; return false; } + + if (invalidMPTAmountInTx(st)) + { + reason = "Amount can not be MPT."; + return false; + } + return true; } diff --git a/src/libxrpl/protocol/STVar.cpp b/src/libxrpl/protocol/STVar.cpp index c8466259f32..f185595eadb 100644 --- a/src/libxrpl/protocol/STVar.cpp +++ b/src/libxrpl/protocol/STVar.cpp @@ -115,141 +115,119 @@ STVar::STVar(SerialIter& sit, SField const& name, int depth) { if (depth > 10) Throw("Maximum nesting depth of STVar exceeded"); - switch (name.fieldType) - { - case STI_NOTPRESENT: - construct(name); - return; - case STI_UINT8: - construct(sit, name); - return; - case STI_UINT16: - construct(sit, name); - return; - case STI_UINT32: - construct(sit, name); - return; - case STI_UINT64: - construct(sit, name); - return; - case STI_AMOUNT: - construct(sit, name); - return; - case STI_UINT128: - construct(sit, name); - return; - case STI_UINT160: - construct(sit, name); - return; - case STI_UINT256: - construct(sit, name); - return; - case STI_VECTOR256: - construct(sit, name); - return; - case STI_VL: - construct(sit, name); - return; - case STI_ACCOUNT: - construct(sit, name); - return; - case STI_PATHSET: - construct(sit, name); - return; - case STI_OBJECT: - construct(sit, name, depth); - return; - case STI_ARRAY: - construct(sit, name, depth); - return; - case STI_ISSUE: - construct(sit, name); - return; - case STI_XCHAIN_BRIDGE: - construct(sit, name); - return; - case STI_CURRENCY: - construct(sit, name); - return; - default: - Throw("Unknown object type"); - } + constructST(name.fieldType, depth, sit, name); } STVar::STVar(SerializedTypeID id, SField const& name) { assert((id == STI_NOTPRESENT) || (id == name.fieldType)); + constructST(id, 0, name); +} + +void +STVar::destroy() +{ + if (on_heap()) + delete p_; + else + p_->~STBase(); + + p_ = nullptr; +} + +template + requires ValidConstructSTArgs +void +STVar::constructST(SerializedTypeID id, int depth, Args&&... args) +{ + auto constructWithDepth = [&]() { + if constexpr (std::is_same_v< + std::tuple...>, + std::tuple>) + { + construct(std::forward(args)...); + } + else if constexpr (std::is_same_v< + std::tuple...>, + std::tuple>) + { + construct(std::forward(args)..., depth); + } + else + { + constexpr bool alwaysFalse = + !std::is_same_v, std::tuple>; + static_assert(alwaysFalse, "Invalid STVar constructor arguments"); + } + }; + switch (id) { - case STI_NOTPRESENT: - construct(name); + case STI_NOTPRESENT: { + // Last argument is always SField + SField const& field = + std::get(std::forward_as_tuple(args...)); + construct(field); return; + } case STI_UINT8: - construct(name); + construct(std::forward(args)...); return; case STI_UINT16: - construct(name); + construct(std::forward(args)...); return; case STI_UINT32: - construct(name); + construct(std::forward(args)...); return; case STI_UINT64: - construct(name); + construct(std::forward(args)...); return; case STI_AMOUNT: - construct(name); + construct(std::forward(args)...); return; case STI_UINT128: - construct(name); + construct(std::forward(args)...); return; case STI_UINT160: - construct(name); + construct(std::forward(args)...); + return; + case STI_UINT192: + construct(std::forward(args)...); return; case STI_UINT256: - construct(name); + construct(std::forward(args)...); return; case STI_VECTOR256: - construct(name); + construct(std::forward(args)...); return; case STI_VL: - construct(name); + construct(std::forward(args)...); return; case STI_ACCOUNT: - construct(name); + construct(std::forward(args)...); return; case STI_PATHSET: - construct(name); + construct(std::forward(args)...); return; case STI_OBJECT: - construct(name); + constructWithDepth.template operator()(); return; case STI_ARRAY: - construct(name); + constructWithDepth.template operator()(); return; case STI_ISSUE: - construct(name); + construct(std::forward(args)...); return; case STI_XCHAIN_BRIDGE: - construct(name); + construct(std::forward(args)...); return; case STI_CURRENCY: - construct(name); + construct(std::forward(args)...); return; default: Throw("Unknown object type"); } } -void -STVar::destroy() -{ - if (on_heap()) - delete p_; - else - p_->~STBase(); - - p_ = nullptr; -} - } // namespace detail } // namespace ripple diff --git a/src/libxrpl/protocol/TER.cpp b/src/libxrpl/protocol/TER.cpp index 917bbf26a9f..788b3a86152 100644 --- a/src/libxrpl/protocol/TER.cpp +++ b/src/libxrpl/protocol/TER.cpp @@ -115,6 +115,7 @@ transResults() MAKE_ERROR(tecTOKEN_PAIR_NOT_FOUND, "Token pair is not found in Oracle object."), MAKE_ERROR(tecARRAY_EMPTY, "Array is empty."), MAKE_ERROR(tecARRAY_TOO_LARGE, "Array is too large."), + MAKE_ERROR(tecLOCKED, "Fund is locked."), MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."), MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."), @@ -205,6 +206,7 @@ transResults() MAKE_ERROR(temXCHAIN_BRIDGE_BAD_REWARD_AMOUNT, "Malformed: Bad reward amount."), MAKE_ERROR(temARRAY_EMPTY, "Malformed: Array is empty."), MAKE_ERROR(temARRAY_TOO_LARGE, "Malformed: Array is too large."), + MAKE_ERROR(temBAD_TRANSFER_FEE, "Malformed: Transfer fee is outside valid range."), MAKE_ERROR(terRETRY, "Retry transaction."), MAKE_ERROR(terFUNDS_SPENT, "DEPRECATED."), diff --git a/src/test/app/Clawback_test.cpp b/src/test/app/Clawback_test.cpp index a6909bb2f62..8a42d4c38ef 100644 --- a/src/test/app/Clawback_test.cpp +++ b/src/test/app/Clawback_test.cpp @@ -965,6 +965,7 @@ class Clawback_test : public beast::unit_test::suite using namespace test::jtx; FeatureBitset const all{supported_amendments()}; + testWithFeats(all - featureMPTokensV1); testWithFeats(all); } }; diff --git a/src/test/app/Flow_test.cpp b/src/test/app/Flow_test.cpp index 9d1257d16bf..4d1397eab83 100644 --- a/src/test/app/Flow_test.cpp +++ b/src/test/app/Flow_test.cpp @@ -1023,14 +1023,12 @@ struct Flow_test : public beast::unit_test::suite 9000000000000000ll, -17, false, - false, STAmount::unchecked{}}; STAmount tinyAmt3{ USD.issue(), 9000000000000003ll, -17, false, - false, STAmount::unchecked{}}; env(offer(gw, drops(9000000000), tinyAmt3)); @@ -1058,14 +1056,12 @@ struct Flow_test : public beast::unit_test::suite 9000000000000000ll, -17, false, - false, STAmount::unchecked{}}; STAmount tinyAmt3{ USD.issue(), 9000000000000003ll, -17, false, - false, STAmount::unchecked{}}; env(pay(gw, alice, tinyAmt1)); diff --git a/src/test/app/MPToken_test.cpp b/src/test/app/MPToken_test.cpp new file mode 100644 index 00000000000..fa888faea17 --- /dev/null +++ b/src/test/app/MPToken_test.cpp @@ -0,0 +1,1981 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 +#include +#include +#include +#include + +namespace ripple { + +class MPToken_test : public beast::unit_test::suite +{ + void + testCreateValidation(FeatureBitset features) + { + testcase("Create Validate"); + using namespace test::jtx; + Account const alice("alice"); + + // test preflight of MPTokenIssuanceCreate + { + // If the MPT amendment is not enabled, you should not be able to + // create MPTokenIssuances + Env env{*this, features - featureMPTokensV1}; + MPTTester mptAlice(env, alice); + + mptAlice.create({.ownerCount = 0, .err = temDISABLED}); + } + + // test preflight of MPTokenIssuanceCreate + { + Env env{*this, features}; + MPTTester mptAlice(env, alice); + + mptAlice.create({.flags = 0x00000001, .err = temINVALID_FLAG}); + + // tries to set a txfee while not enabling in the flag + mptAlice.create( + {.maxAmt = 100, + .assetScale = 0, + .transferFee = 1, + .metadata = "test", + .err = temMALFORMED}); + + // tries to set a txfee greater than max + mptAlice.create( + {.maxAmt = 100, + .assetScale = 0, + .transferFee = maxTransferFee + 1, + .metadata = "test", + .flags = tfMPTCanTransfer, + .err = temBAD_TRANSFER_FEE}); + + // tries to set a txfee while not enabling transfer + mptAlice.create( + {.maxAmt = 100, + .assetScale = 0, + .transferFee = maxTransferFee, + .metadata = "test", + .err = temMALFORMED}); + + // empty metadata returns error + mptAlice.create( + {.maxAmt = 100, + .assetScale = 0, + .transferFee = 0, + .metadata = "", + .err = temMALFORMED}); + + // MaximumAmout of 0 returns error + mptAlice.create( + {.maxAmt = 0, + .assetScale = 1, + .transferFee = 1, + .metadata = "test", + .err = temMALFORMED}); + + // MaximumAmount larger than 63 bit returns error + mptAlice.create( + {.maxAmt = 0xFFFF'FFFF'FFFF'FFF0, // 18'446'744'073'709'551'600 + .assetScale = 0, + .transferFee = 0, + .metadata = "test", + .err = temMALFORMED}); + mptAlice.create( + {.maxAmt = maxMPTokenAmount + 1, // 9'223'372'036'854'775'808 + .assetScale = 0, + .transferFee = 0, + .metadata = "test", + .err = temMALFORMED}); + } + } + + void + testCreateEnabled(FeatureBitset features) + { + testcase("Create Enabled"); + + using namespace test::jtx; + Account const alice("alice"); + + { + // If the MPT amendment IS enabled, you should be able to create + // MPTokenIssuances + Env env{*this, features}; + MPTTester mptAlice(env, alice); + mptAlice.create( + {.maxAmt = maxMPTokenAmount, // 9'223'372'036'854'775'807 + .assetScale = 1, + .transferFee = 10, + .metadata = "123", + .ownerCount = 1, + .flags = tfMPTCanLock | tfMPTRequireAuth | tfMPTCanEscrow | + tfMPTCanTrade | tfMPTCanTransfer | tfMPTCanClawback}); + + // Get the hash for the most recent transaction. + std::string const txHash{ + env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; + + Json::Value const result = env.rpc("tx", txHash)[jss::result]; + BEAST_EXPECT( + result[sfMaximumAmount.getJsonName()] == "9223372036854775807"); + } + } + + void + testDestroyValidation(FeatureBitset features) + { + testcase("Destroy Validate"); + + using namespace test::jtx; + Account const alice("alice"); + Account const bob("bob"); + // MPTokenIssuanceDestroy (preflight) + { + Env env{*this, features - featureMPTokensV1}; + MPTTester mptAlice(env, alice); + auto const id = makeMptID(env.seq(alice), alice); + mptAlice.destroy({.id = id, .ownerCount = 0, .err = temDISABLED}); + + env.enableFeature(featureMPTokensV1); + + mptAlice.destroy( + {.id = id, .flags = 0x00000001, .err = temINVALID_FLAG}); + } + + // MPTokenIssuanceDestroy (preclaim) + { + Env env{*this, features}; + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.destroy( + {.id = makeMptID(env.seq(alice), alice), + .ownerCount = 0, + .err = tecOBJECT_NOT_FOUND}); + + mptAlice.create({.ownerCount = 1}); + + // a non-issuer tries to destroy a mptissuance they didn't issue + mptAlice.destroy({.issuer = bob, .err = tecNO_PERMISSION}); + + // Make sure that issuer can't delete issuance when it still has + // outstanding balance + { + // bob now holds a mptoken object + mptAlice.authorize({.account = bob, .holderCount = 1}); + + // alice pays bob 100 tokens + mptAlice.pay(alice, bob, 100); + + mptAlice.destroy({.err = tecHAS_OBLIGATIONS}); + } + } + } + + void + testDestroyEnabled(FeatureBitset features) + { + testcase("Destroy Enabled"); + + using namespace test::jtx; + Account const alice("alice"); + + // If the MPT amendment IS enabled, you should be able to destroy + // MPTokenIssuances + Env env{*this, features}; + MPTTester mptAlice(env, alice); + + mptAlice.create({.ownerCount = 1}); + + mptAlice.destroy({.ownerCount = 0}); + } + + void + testAuthorizeValidation(FeatureBitset features) + { + testcase("Validate authorize transaction"); + + using namespace test::jtx; + Account const alice("alice"); + Account const bob("bob"); + Account const cindy("cindy"); + // Validate amendment enable in MPTokenAuthorize (preflight) + { + Env env{*this, features - featureMPTokensV1}; + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.authorize( + {.account = bob, + .id = makeMptID(env.seq(alice), alice), + .err = temDISABLED}); + } + + // Validate fields in MPTokenAuthorize (preflight) + { + Env env{*this, features}; + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1}); + + // The only valid MPTokenAuthorize flag is tfMPTUnauthorize, which + // has a value of 1 + mptAlice.authorize( + {.account = bob, .flags = 0x00000002, .err = temINVALID_FLAG}); + + mptAlice.authorize( + {.account = bob, .holder = bob, .err = temMALFORMED}); + + mptAlice.authorize({.holder = alice, .err = temMALFORMED}); + } + + // Try authorizing when MPTokenIssuance doesn't exist in + // MPTokenAuthorize (preclaim) + { + Env env{*this, features}; + MPTTester mptAlice(env, alice, {.holders = {bob}}); + auto const id = makeMptID(env.seq(alice), alice); + + mptAlice.authorize( + {.holder = bob, .id = id, .err = tecOBJECT_NOT_FOUND}); + + mptAlice.authorize( + {.account = bob, .id = id, .err = tecOBJECT_NOT_FOUND}); + } + + // Test bad scenarios without allowlisting in MPTokenAuthorize + // (preclaim) + { + Env env{*this, features}; + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1}); + + // bob submits a tx with a holder field + mptAlice.authorize( + {.account = bob, .holder = alice, .err = tecNO_PERMISSION}); + + // alice tries to hold onto her own token + mptAlice.authorize({.account = alice, .err = tecNO_PERMISSION}); + + // the mpt does not enable allowlisting + mptAlice.authorize({.holder = bob, .err = tecNO_AUTH}); + + // bob now holds a mptoken object + mptAlice.authorize({.account = bob, .holderCount = 1}); + + // bob cannot create the mptoken the second time + mptAlice.authorize({.account = bob, .err = tecDUPLICATE}); + + // Check that bob cannot delete MPToken when his balance is + // non-zero + { + // alice pays bob 100 tokens + mptAlice.pay(alice, bob, 100); + + // bob tries to delete his MPToken, but fails since he still + // holds tokens + mptAlice.authorize( + {.account = bob, + .flags = tfMPTUnauthorize, + .err = tecHAS_OBLIGATIONS}); + + // bob pays back alice 100 tokens + mptAlice.pay(bob, alice, 100); + } + + // bob deletes/unauthorizes his MPToken + mptAlice.authorize({.account = bob, .flags = tfMPTUnauthorize}); + + // bob receives error when he tries to delete his MPToken that has + // already been deleted + mptAlice.authorize( + {.account = bob, + .holderCount = 0, + .flags = tfMPTUnauthorize, + .err = tecOBJECT_NOT_FOUND}); + } + + // Test bad scenarios with allow-listing in MPTokenAuthorize (preclaim) + { + Env env{*this, features}; + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTRequireAuth}); + + // alice submits a tx without specifying a holder's account + mptAlice.authorize({.err = tecNO_PERMISSION}); + + // alice submits a tx to authorize a holder that hasn't created + // a mptoken yet + mptAlice.authorize({.holder = bob, .err = tecOBJECT_NOT_FOUND}); + + // alice specifys a holder acct that doesn't exist + mptAlice.authorize({.holder = cindy, .err = tecNO_DST}); + + // bob now holds a mptoken object + mptAlice.authorize({.account = bob, .holderCount = 1}); + + // alice tries to unauthorize bob. + // although tx is successful, + // but nothing happens because bob hasn't been authorized yet + mptAlice.authorize({.holder = bob, .flags = tfMPTUnauthorize}); + + // alice authorizes bob + // make sure bob's mptoken has set lsfMPTAuthorized + mptAlice.authorize({.holder = bob}); + + // alice tries authorizes bob again. + // tx is successful, but bob is already authorized, + // so no changes + mptAlice.authorize({.holder = bob}); + + // bob deletes his mptoken + mptAlice.authorize( + {.account = bob, .holderCount = 0, .flags = tfMPTUnauthorize}); + } + + // Test mptoken reserve requirement - first two mpts free (doApply) + { + Env env{*this, features}; + auto const acctReserve = env.current()->fees().accountReserve(0); + auto const incReserve = env.current()->fees().increment; + + // 1 drop + BEAST_EXPECT(incReserve > XRPAmount(1)); + MPTTester mptAlice1( + env, + alice, + {.holders = {bob}, + .xrpHolders = acctReserve + (incReserve - 1)}); + mptAlice1.create(); + + MPTTester mptAlice2(env, alice, {.fund = false}); + mptAlice2.create(); + + MPTTester mptAlice3(env, alice, {.fund = false}); + mptAlice3.create({.ownerCount = 3}); + + // first mpt for free + mptAlice1.authorize({.account = bob, .holderCount = 1}); + + // second mpt free + mptAlice2.authorize({.account = bob, .holderCount = 2}); + + mptAlice3.authorize( + {.account = bob, .err = tecINSUFFICIENT_RESERVE}); + + env(pay( + env.master, bob, drops(incReserve + incReserve + incReserve))); + env.close(); + + mptAlice3.authorize({.account = bob, .holderCount = 3}); + } + } + + void + testAuthorizeEnabled(FeatureBitset features) + { + testcase("Authorize Enabled"); + + using namespace test::jtx; + Account const alice("alice"); + Account const bob("bob"); + // Basic authorization without allowlisting + { + Env env{*this, features}; + + // alice create mptissuance without allowisting + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1}); + + // bob creates a mptoken + mptAlice.authorize({.account = bob, .holderCount = 1}); + + // bob deletes his mptoken + mptAlice.authorize( + {.account = bob, .holderCount = 0, .flags = tfMPTUnauthorize}); + } + + // With allowlisting + { + Env env{*this, features}; + + // alice creates a mptokenissuance that requires authorization + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTRequireAuth}); + + // bob creates a mptoken + mptAlice.authorize({.account = bob, .holderCount = 1}); + + // alice authorizes bob + mptAlice.authorize({.account = alice, .holder = bob}); + + // Unauthorize bob's mptoken + mptAlice.authorize( + {.account = alice, + .holder = bob, + .holderCount = 1, + .flags = tfMPTUnauthorize}); + + mptAlice.authorize( + {.account = bob, .holderCount = 0, .flags = tfMPTUnauthorize}); + } + + // Holder can have dangling MPToken even if issuance has been destroyed. + // Make sure they can still delete/unauthorize the MPToken + { + Env env{*this, features}; + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1}); + + // bob creates a mptoken + mptAlice.authorize({.account = bob, .holderCount = 1}); + + // alice deletes her issuance + mptAlice.destroy({.ownerCount = 0}); + + // bob can delete his mptoken even though issuance is no longer + // existent + mptAlice.authorize( + {.account = bob, .holderCount = 0, .flags = tfMPTUnauthorize}); + } + } + + void + testSetValidation(FeatureBitset features) + { + testcase("Validate set transaction"); + + using namespace test::jtx; + Account const alice("alice"); // issuer + Account const bob("bob"); // holder + Account const cindy("cindy"); + // Validate fields in MPTokenIssuanceSet (preflight) + { + Env env{*this, features - featureMPTokensV1}; + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.set( + {.account = bob, + .id = makeMptID(env.seq(alice), alice), + .err = temDISABLED}); + + env.enableFeature(featureMPTokensV1); + + mptAlice.create({.ownerCount = 1, .holderCount = 0}); + + mptAlice.authorize({.account = bob, .holderCount = 1}); + + // test invalid flag - only valid flags are tfMPTLock (1) and Unlock + // (2) + mptAlice.set( + {.account = alice, + .flags = 0x00000008, + .err = temINVALID_FLAG}); + + // set both lock and unlock flags at the same time will fail + mptAlice.set( + {.account = alice, + .flags = tfMPTLock | tfMPTUnlock, + .err = temINVALID_FLAG}); + + // if the holder is the same as the acct that submitted the tx, + // tx fails + mptAlice.set( + {.account = alice, + .holder = alice, + .flags = tfMPTLock, + .err = temMALFORMED}); + } + + // Validate fields in MPTokenIssuanceSet (preclaim) + // test when a mptokenissuance has disabled locking + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1}); + + // alice tries to lock a mptissuance that has disabled locking + mptAlice.set( + {.account = alice, + .flags = tfMPTLock, + .err = tecNO_PERMISSION}); + + // alice tries to unlock mptissuance that has disabled locking + mptAlice.set( + {.account = alice, + .flags = tfMPTUnlock, + .err = tecNO_PERMISSION}); + + // issuer tries to lock a bob's mptoken that has disabled + // locking + mptAlice.set( + {.account = alice, + .holder = bob, + .flags = tfMPTLock, + .err = tecNO_PERMISSION}); + + // issuer tries to unlock a bob's mptoken that has disabled + // locking + mptAlice.set( + {.account = alice, + .holder = bob, + .flags = tfMPTUnlock, + .err = tecNO_PERMISSION}); + } + + // Validate fields in MPTokenIssuanceSet (preclaim) + // test when mptokenissuance has enabled locking + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + // alice trying to set when the mptissuance doesn't exist yet + mptAlice.set( + {.id = makeMptID(env.seq(alice), alice), + .flags = tfMPTLock, + .err = tecOBJECT_NOT_FOUND}); + + // create a mptokenissuance with locking + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanLock}); + + // a non-issuer acct tries to set the mptissuance + mptAlice.set( + {.account = bob, .flags = tfMPTLock, .err = tecNO_PERMISSION}); + + // trying to set a holder who doesn't have a mptoken + mptAlice.set( + {.holder = bob, + .flags = tfMPTLock, + .err = tecOBJECT_NOT_FOUND}); + + // trying to set a holder who doesn't exist + mptAlice.set( + {.holder = cindy, .flags = tfMPTLock, .err = tecNO_DST}); + } + } + + void + testSetEnabled(FeatureBitset features) + { + testcase("Enabled set transaction"); + + using namespace test::jtx; + + // Test locking and unlocking + Env env{*this, features}; + Account const alice("alice"); // issuer + Account const bob("bob"); // holder + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + // create a mptokenissuance with locking + mptAlice.create( + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanLock}); + + mptAlice.authorize({.account = bob, .holderCount = 1}); + + // locks bob's mptoken + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); + + // trying to lock bob's mptoken again will still succeed + // but no changes to the objects + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); + + // alice locks the mptissuance + mptAlice.set({.account = alice, .flags = tfMPTLock}); + + // alice tries to lock up both mptissuance and mptoken again + // it will not change the flags and both will remain locked. + mptAlice.set({.account = alice, .flags = tfMPTLock}); + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); + + // alice unlocks bob's mptoken + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTUnlock}); + + // locks up bob's mptoken again + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); + + // alice unlocks mptissuance + mptAlice.set({.account = alice, .flags = tfMPTUnlock}); + + // alice unlocks bob's mptoken + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTUnlock}); + + // alice unlocks mptissuance and bob's mptoken again despite that + // they are already unlocked. Make sure this will not change the + // flags + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTUnlock}); + mptAlice.set({.account = alice, .flags = tfMPTUnlock}); + } + + void + testPayment(FeatureBitset features) + { + testcase("Payment"); + + using namespace test::jtx; + Account const alice("alice"); // issuer + Account const bob("bob"); // holder + Account const carol("carol"); // holder + + // preflight validation + + // MPT is disabled + { + Env env{*this, features - featureMPTokensV1}; + Account const alice("alice"); + Account const bob("bob"); + + env.fund(XRP(1'000), alice); + env.fund(XRP(1'000), bob); + STAmount mpt{MPTIssue{makeMptID(1, alice)}, UINT64_C(100)}; + + env(pay(alice, bob, mpt), ter(temDISABLED)); + } + + // MPT is disabled, unsigned request + { + Env env{*this, features - featureMPTokensV1}; + Account const alice("alice"); // issuer + Account const carol("carol"); + auto const USD = alice["USD"]; + + env.fund(XRP(1'000), alice); + env.fund(XRP(1'000), carol); + STAmount mpt{MPTIssue{makeMptID(1, alice)}, UINT64_C(100)}; + + Json::Value jv; + jv[jss::secret] = alice.name(); + jv[jss::tx_json] = pay(alice, carol, mpt); + jv[jss::tx_json][jss::Fee] = to_string(env.current()->fees().base); + auto const jrr = env.rpc("json", "submit", to_string(jv)); + BEAST_EXPECT(jrr[jss::result][jss::engine_result] == "temDISABLED"); + } + + // Invalid flag + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .holderCount = 0}); + auto const MPT = mptAlice["MPT"]; + + mptAlice.authorize({.account = bob}); + + for (auto flags : {tfNoRippleDirect, tfLimitQuality}) + env(pay(alice, bob, MPT(10)), + txflags(flags), + ter(temINVALID_FLAG)); + } + + // Invalid combination of send, sendMax, deliverMin, paths + { + Env env{*this, features}; + Account const alice("alice"); + Account const carol("carol"); + + MPTTester mptAlice(env, alice, {.holders = {carol}}); + + mptAlice.create({.ownerCount = 1, .holderCount = 0}); + + mptAlice.authorize({.account = carol}); + + // sendMax and DeliverMin are valid XRP amount, + // but is invalid combination with MPT amount + auto const MPT = mptAlice["MPT"]; + env(pay(alice, carol, MPT(100)), + sendmax(XRP(100)), + ter(temMALFORMED)); + env(pay(alice, carol, MPT(100)), + delivermin(XRP(100)), + ter(temBAD_AMOUNT)); + // sendMax MPT is invalid with IOU or XRP + auto const USD = alice["USD"]; + env(pay(alice, carol, USD(100)), + sendmax(MPT(100)), + ter(temMALFORMED)); + env(pay(alice, carol, XRP(100)), + sendmax(MPT(100)), + ter(temMALFORMED)); + env(pay(alice, carol, USD(100)), + delivermin(MPT(100)), + ter(temBAD_AMOUNT)); + env(pay(alice, carol, XRP(100)), + delivermin(MPT(100)), + ter(temBAD_AMOUNT)); + // sendmax and amount are different MPT issue + test::jtx::MPT const MPT1( + "MPT", makeMptID(env.seq(alice) + 10, alice)); + env(pay(alice, carol, MPT1(100)), + sendmax(MPT(100)), + ter(temMALFORMED)); + // paths is invalid + env(pay(alice, carol, MPT(100)), path(~USD), ter(temMALFORMED)); + } + + // build_path is invalid if MPT + { + Env env{*this, features}; + Account const alice("alice"); + Account const carol("carol"); + + MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); + + mptAlice.create({.ownerCount = 1, .holderCount = 0}); + auto const MPT = mptAlice["MPT"]; + + mptAlice.authorize({.account = carol}); + + Json::Value payment; + payment[jss::secret] = alice.name(); + payment[jss::tx_json] = pay(alice, carol, MPT(100)); + + payment[jss::build_path] = true; + auto jrr = env.rpc("json", "submit", to_string(payment)); + BEAST_EXPECT(jrr[jss::result][jss::error] == "invalidParams"); + BEAST_EXPECT( + jrr[jss::result][jss::error_message] == + "Field 'build_path' not allowed in this context."); + } + + // Can't pay negative amount + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); + + mptAlice.create({.ownerCount = 1, .holderCount = 0}); + auto const MPT = mptAlice["MPT"]; + + mptAlice.authorize({.account = bob}); + mptAlice.authorize({.account = carol}); + + mptAlice.pay(alice, bob, -1, temBAD_AMOUNT); + + mptAlice.pay(bob, carol, -1, temBAD_AMOUNT); + + mptAlice.pay(bob, alice, -1, temBAD_AMOUNT); + + env(pay(alice, bob, MPT(10)), sendmax(MPT(-1)), ter(temBAD_AMOUNT)); + } + + // Pay to self + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .holderCount = 0}); + + mptAlice.authorize({.account = bob}); + + mptAlice.pay(bob, bob, 10, temREDUNDANT); + } + + // preclaim validation + + // Destination doesn't exist + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .holderCount = 0}); + + mptAlice.authorize({.account = bob}); + + Account const bad{"bad"}; + env.memoize(bad); + + mptAlice.pay(bob, bad, 10, tecNO_DST); + } + + // apply validation + + // If RequireAuth is enabled, Payment fails if the receiver is not + // authorized + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create( + {.ownerCount = 1, + .holderCount = 0, + .flags = tfMPTRequireAuth | tfMPTCanTransfer}); + + mptAlice.authorize({.account = bob}); + + mptAlice.pay(alice, bob, 100, tecNO_AUTH); + } + + // If RequireAuth is enabled, Payment fails if the sender is not + // authorized + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create( + {.ownerCount = 1, + .holderCount = 0, + .flags = tfMPTRequireAuth | tfMPTCanTransfer}); + + // bob creates an empty MPToken + mptAlice.authorize({.account = bob}); + + // alice authorizes bob to hold funds + mptAlice.authorize({.account = alice, .holder = bob}); + + // alice sends 100 MPT to bob + mptAlice.pay(alice, bob, 100); + + // alice UNAUTHORIZES bob + mptAlice.authorize( + {.account = alice, .holder = bob, .flags = tfMPTUnauthorize}); + + // bob fails to send back to alice because he is no longer + // authorize to move his funds! + mptAlice.pay(bob, alice, 100, tecNO_AUTH); + } + + // Non-issuer cannot send to each other if MPTCanTransfer isn't set + { + Env env(*this, features); + Account const alice{"alice"}; + Account const bob{"bob"}; + Account const cindy{"cindy"}; + + MPTTester mptAlice(env, alice, {.holders = {bob, cindy}}); + + // alice creates issuance without MPTCanTransfer + mptAlice.create({.ownerCount = 1, .holderCount = 0}); + + // bob creates a MPToken + mptAlice.authorize({.account = bob}); + + // cindy creates a MPToken + mptAlice.authorize({.account = cindy}); + + // alice pays bob 100 tokens + mptAlice.pay(alice, bob, 100); + + // bob tries to send cindy 10 tokens, but fails because canTransfer + // is off + mptAlice.pay(bob, cindy, 10, tecNO_AUTH); + + // bob can send back to alice(issuer) just fine + mptAlice.pay(bob, alice, 10); + } + + // Holder is not authorized + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); + + mptAlice.create( + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); + + // issuer to holder + mptAlice.pay(alice, bob, 100, tecNO_AUTH); + + // holder to issuer + mptAlice.pay(bob, alice, 100, tecNO_AUTH); + + // holder to holder + mptAlice.pay(bob, carol, 50, tecNO_AUTH); + } + + // Payer doesn't have enough funds + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); + + mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer}); + + mptAlice.authorize({.account = bob}); + mptAlice.authorize({.account = carol}); + + mptAlice.pay(alice, bob, 100); + + // Pay to another holder + mptAlice.pay(bob, carol, 101, tecPATH_PARTIAL); + + // Pay to the issuer + mptAlice.pay(bob, alice, 101, tecPATH_PARTIAL); + } + + // MPT is locked + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); + + mptAlice.create( + {.ownerCount = 1, .flags = tfMPTCanLock | tfMPTCanTransfer}); + + mptAlice.authorize({.account = bob}); + mptAlice.authorize({.account = carol}); + + mptAlice.pay(alice, bob, 100); + mptAlice.pay(alice, carol, 100); + + // Global lock + mptAlice.set({.account = alice, .flags = tfMPTLock}); + // Can't send between holders + mptAlice.pay(bob, carol, 1, tecLOCKED); + mptAlice.pay(carol, bob, 2, tecLOCKED); + // Issuer can send + mptAlice.pay(alice, bob, 3); + // Holder can send back to issuer + mptAlice.pay(bob, alice, 4); + + // Global unlock + mptAlice.set({.account = alice, .flags = tfMPTUnlock}); + // Individual lock + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); + // Can't send between holders + mptAlice.pay(bob, carol, 5, tecLOCKED); + mptAlice.pay(carol, bob, 6, tecLOCKED); + // Issuer can send + mptAlice.pay(alice, bob, 7); + // Holder can send back to issuer + mptAlice.pay(bob, alice, 8); + } + + // Transfer fee + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); + + // Transfer fee is 10% + mptAlice.create( + {.transferFee = 10'000, + .ownerCount = 1, + .holderCount = 0, + .flags = tfMPTCanTransfer}); + + // Holders create MPToken + mptAlice.authorize({.account = bob}); + mptAlice.authorize({.account = carol}); + + // Payment between the issuer and the holder, no transfer fee. + mptAlice.pay(alice, bob, 2'000); + + // Payment between the holder and the issuer, no transfer fee. + mptAlice.pay(bob, alice, 1'000); + BEAST_EXPECT(mptAlice.checkMPTokenAmount(bob, 1'000)); + + // Payment between the holders. The sender doesn't have + // enough funds to cover the transfer fee. + mptAlice.pay(bob, carol, 1'000, tecPATH_PARTIAL); + + // Payment between the holders. The sender has enough funds + // but SendMax is not included. + mptAlice.pay(bob, carol, 100, tecPATH_PARTIAL); + + auto const MPT = mptAlice["MPT"]; + // SendMax doesn't cover the fee + env(pay(bob, carol, MPT(100)), + sendmax(MPT(109)), + ter(tecPATH_PARTIAL)); + + // Payment succeeds if sufficient SendMax is included. + // 100 to carol, 10 to issuer + env(pay(bob, carol, MPT(100)), sendmax(MPT(110))); + // 100 to carol, 10 to issuer + env(pay(bob, carol, MPT(100)), sendmax(MPT(115))); + BEAST_EXPECT(mptAlice.checkMPTokenAmount(bob, 780)); + BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 200)); + // Payment succeeds if partial payment even if + // SendMax is less than deliver amount + env(pay(bob, carol, MPT(100)), + sendmax(MPT(90)), + txflags(tfPartialPayment)); + // 82 to carol, 8 to issuer (90 / 1.1 ~ 81.81 (rounded to nearest) = + // 82) + BEAST_EXPECT(mptAlice.checkMPTokenAmount(bob, 690)); + BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 282)); + } + + // Insufficient SendMax with no transfer fee + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); + + mptAlice.create( + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); + + // Holders create MPToken + mptAlice.authorize({.account = bob}); + mptAlice.authorize({.account = carol}); + mptAlice.pay(alice, bob, 1'000); + + auto const MPT = mptAlice["MPT"]; + // SendMax is less than the amount + env(pay(bob, carol, MPT(100)), + sendmax(MPT(99)), + ter(tecPATH_PARTIAL)); + env(pay(bob, alice, MPT(100)), + sendmax(MPT(99)), + ter(tecPATH_PARTIAL)); + + // Payment succeeds if sufficient SendMax is included. + env(pay(bob, carol, MPT(100)), sendmax(MPT(100))); + BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 100)); + // Payment succeeds if partial payment + env(pay(bob, carol, MPT(100)), + sendmax(MPT(99)), + txflags(tfPartialPayment)); + BEAST_EXPECT(mptAlice.checkMPTokenAmount(carol, 199)); + } + + // DeliverMin + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); + + mptAlice.create( + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); + + // Holders create MPToken + mptAlice.authorize({.account = bob}); + mptAlice.authorize({.account = carol}); + mptAlice.pay(alice, bob, 1'000); + + auto const MPT = mptAlice["MPT"]; + // Fails even with the partial payment because + // deliver amount < deliverMin + env(pay(bob, alice, MPT(100)), + sendmax(MPT(99)), + delivermin(MPT(100)), + txflags(tfPartialPayment), + ter(tecPATH_PARTIAL)); + // Payment succeeds if deliver amount >= deliverMin + env(pay(bob, alice, MPT(100)), + sendmax(MPT(99)), + delivermin(MPT(99)), + txflags(tfPartialPayment)); + } + + // Issuer fails trying to send more than the maximum amount allowed + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create( + {.maxAmt = 100, + .ownerCount = 1, + .holderCount = 0, + .flags = tfMPTCanTransfer}); + + mptAlice.authorize({.account = bob}); + + // issuer sends holder the max amount allowed + mptAlice.pay(alice, bob, 100); + + // issuer tries to exceed max amount + mptAlice.pay(alice, bob, 1, tecPATH_PARTIAL); + } + + // Issuer fails trying to send more than the default maximum + // amount allowed + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .holderCount = 0}); + + mptAlice.authorize({.account = bob}); + + // issuer sends holder the default max amount allowed + mptAlice.pay(alice, bob, maxMPTokenAmount); + + // issuer tries to exceed max amount + mptAlice.pay(alice, bob, 1, tecPATH_PARTIAL); + } + + // Pay more than max amount fails in the json parser before + // transactor is called + { + Env env{*this, features}; + env.fund(XRP(1'000), alice, bob); + STAmount mpt{MPTIssue{makeMptID(1, alice)}, UINT64_C(100)}; + Json::Value jv; + jv[jss::secret] = alice.name(); + jv[jss::tx_json] = pay(alice, bob, mpt); + jv[jss::tx_json][jss::Amount][jss::value] = + to_string(maxMPTokenAmount + 1); + auto const jrr = env.rpc("json", "submit", to_string(jv)); + BEAST_EXPECT(jrr[jss::result][jss::error] == "invalidParams"); + } + + // Pay maximum amount with the transfer fee, SendMax, and + // partial payment + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); + + mptAlice.create( + {.maxAmt = 10'000, + .transferFee = 100, + .ownerCount = 1, + .holderCount = 0, + .flags = tfMPTCanTransfer}); + auto const MPT = mptAlice["MPT"]; + + mptAlice.authorize({.account = bob}); + mptAlice.authorize({.account = carol}); + + // issuer sends holder the max amount allowed + mptAlice.pay(alice, bob, 10'000); + + // payment between the holders + env(pay(bob, carol, MPT(10'000)), + sendmax(MPT(10'000)), + txflags(tfPartialPayment)); + // Verify the metadata + auto const meta = env.meta()->getJson( + JsonOptions::none)[sfAffectedNodes.fieldName]; + // Issuer got 10 in the transfer fees + BEAST_EXPECT( + meta[0u][sfModifiedNode.fieldName][sfFinalFields.fieldName] + [sfOutstandingAmount.fieldName] == "9990"); + // Destination account got 9'990 + BEAST_EXPECT( + meta[1u][sfModifiedNode.fieldName][sfFinalFields.fieldName] + [sfMPTAmount.fieldName] == "9990"); + // Source account spent 10'000 + BEAST_EXPECT( + meta[2u][sfModifiedNode.fieldName][sfPreviousFields.fieldName] + [sfMPTAmount.fieldName] == "10000"); + BEAST_EXPECT( + !meta[2u][sfModifiedNode.fieldName][sfFinalFields.fieldName] + .isMember(sfMPTAmount.fieldName)); + + // payment between the holders fails without + // partial payment + env(pay(bob, carol, MPT(10'000)), + sendmax(MPT(10'000)), + ter(tecPATH_PARTIAL)); + } + + // Pay maximum allowed amount + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); + + mptAlice.create( + {.maxAmt = maxMPTokenAmount, + .ownerCount = 1, + .holderCount = 0, + .flags = tfMPTCanTransfer}); + auto const MPT = mptAlice["MPT"]; + + mptAlice.authorize({.account = bob}); + mptAlice.authorize({.account = carol}); + + // issuer sends holder the max amount allowed + mptAlice.pay(alice, bob, maxMPTokenAmount); + BEAST_EXPECT( + mptAlice.checkMPTokenOutstandingAmount(maxMPTokenAmount)); + + // payment between the holders + mptAlice.pay(bob, carol, maxMPTokenAmount); + BEAST_EXPECT( + mptAlice.checkMPTokenOutstandingAmount(maxMPTokenAmount)); + // holder pays back to the issuer + mptAlice.pay(carol, alice, maxMPTokenAmount); + BEAST_EXPECT(mptAlice.checkMPTokenOutstandingAmount(0)); + } + + // Issuer fails trying to send fund after issuance was destroyed + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .holderCount = 0}); + + mptAlice.authorize({.account = bob}); + + // alice destroys issuance + mptAlice.destroy({.ownerCount = 0}); + + // alice tries to send bob fund after issuance is destroyed, should + // fail. + mptAlice.pay(alice, bob, 100, tecOBJECT_NOT_FOUND); + } + + // Non-existent issuance + { + Env env{*this, features}; + + env.fund(XRP(1'000), alice, bob); + + STAmount const mpt{MPTID{0}, 100}; + env(pay(alice, bob, mpt), ter(tecOBJECT_NOT_FOUND)); + } + + // Issuer fails trying to send to an account, which doesn't own MPT for + // an issuance that was destroyed + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + mptAlice.create({.ownerCount = 1, .holderCount = 0}); + + // alice destroys issuance + mptAlice.destroy({.ownerCount = 0}); + + // alice tries to send bob who doesn't own the MPT after issuance is + // destroyed, it should fail + mptAlice.pay(alice, bob, 100, tecOBJECT_NOT_FOUND); + } + + // Issuers issues maximum amount of MPT to a holder, the holder should + // be able to transfer the max amount to someone else + { + Env env{*this, features}; + Account const alice("alice"); + Account const carol("bob"); + Account const bob("carol"); + + MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); + + mptAlice.create( + {.maxAmt = 100, .ownerCount = 1, .flags = tfMPTCanTransfer}); + + mptAlice.authorize({.account = bob}); + mptAlice.authorize({.account = carol}); + + mptAlice.pay(alice, bob, 100); + + // transfer max amount to another holder + mptAlice.pay(bob, carol, 100); + } + + // Simple payment + { + Env env{*this, features}; + + MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); + + mptAlice.create( + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer}); + + mptAlice.authorize({.account = bob}); + mptAlice.authorize({.account = carol}); + + // issuer to holder + mptAlice.pay(alice, bob, 100); + + // holder to issuer + mptAlice.pay(bob, alice, 100); + + // holder to holder + mptAlice.pay(alice, bob, 100); + mptAlice.pay(bob, carol, 50); + } + } + + void + testMPTInvalidInTx(FeatureBitset features) + { + testcase("MPT Amount Invalid in Transaction"); + using namespace test::jtx; + + // Validate that every transaction with an amount field, + // which doesn't support MPT, fails. + + // keyed by transaction + amount field + std::set txWithAmounts; + for (auto const& format : TxFormats::getInstance()) + { + for (auto const& e : format.getSOTemplate()) + { + // Transaction has amount fields. + // Exclude pseudo-transaction SetFee. Don't consider + // the Fee field since it's included in every transaction. + if (e.supportMPT() == soeMPTNotSupported && + e.sField().getName() != jss::Fee && + format.getName() != jss::SetFee) + { + txWithAmounts.insert( + format.getName() + e.sField().fieldName); + break; + } + } + } + + Account const alice("alice"); + auto const USD = alice["USD"]; + Account const carol("carol"); + MPTIssue issue(makeMptID(1, alice)); + STAmount mpt{issue, UINT64_C(100)}; + auto const jvb = bridge(alice, USD, alice, USD); + for (auto const& feature : {features, features - featureMPTokensV1}) + { + Env env{*this, feature}; + env.fund(XRP(1'000), alice); + env.fund(XRP(1'000), carol); + auto test = [&](Json::Value const& jv, + std::string const& amtField) { + txWithAmounts.erase( + jv[jss::TransactionType].asString() + amtField); + + // tx is signed + auto jtx = env.jt(jv); + Serializer s; + jtx.stx->add(s); + auto jrr = env.rpc("submit", strHex(s.slice())); + BEAST_EXPECT( + jrr[jss::result][jss::error] == "invalidTransaction"); + + // tx is unsigned + Json::Value jv1; + jv1[jss::secret] = alice.name(); + jv1[jss::tx_json] = jv; + jrr = env.rpc("json", "submit", to_string(jv1)); + BEAST_EXPECT(jrr[jss::result][jss::error] == "invalidParams"); + + jrr = env.rpc("json", "sign", to_string(jv1)); + BEAST_EXPECT(jrr[jss::result][jss::error] == "invalidParams"); + }; + // All transactions with sfAmount, which don't support MPT + // and transactions with amount fields, which can't be MPT + + // AMMCreate + auto ammCreate = [&](SField const& field) { + Json::Value jv; + jv[jss::TransactionType] = jss::AMMCreate; + jv[jss::Account] = alice.human(); + jv[jss::Amount] = (field.fieldName == sfAmount.fieldName) + ? mpt.getJson(JsonOptions::none) + : "100000000"; + jv[jss::Amount2] = (field.fieldName == sfAmount2.fieldName) + ? mpt.getJson(JsonOptions::none) + : "100000000"; + jv[jss::TradingFee] = 0; + test(jv, field.fieldName); + }; + ammCreate(sfAmount); + ammCreate(sfAmount2); + // AMMDeposit + auto ammDeposit = [&](SField const& field) { + Json::Value jv; + jv[jss::TransactionType] = jss::AMMDeposit; + jv[jss::Account] = alice.human(); + jv[jss::Asset] = to_json(xrpIssue()); + jv[jss::Asset2] = to_json(USD.issue()); + jv[field.fieldName] = mpt.getJson(JsonOptions::none); + jv[jss::Flags] = tfSingleAsset; + test(jv, field.fieldName); + }; + for (SField const& field : + {std::ref(sfAmount), + std::ref(sfAmount2), + std::ref(sfEPrice), + std::ref(sfLPTokenOut)}) + ammDeposit(field); + // AMMWithdraw + auto ammWithdraw = [&](SField const& field) { + Json::Value jv; + jv[jss::TransactionType] = jss::AMMWithdraw; + jv[jss::Account] = alice.human(); + jv[jss::Asset] = to_json(xrpIssue()); + jv[jss::Asset2] = to_json(USD.issue()); + jv[jss::Flags] = tfSingleAsset; + jv[field.fieldName] = mpt.getJson(JsonOptions::none); + test(jv, field.fieldName); + }; + ammWithdraw(sfAmount); + for (SField const& field : + {std::ref(sfAmount2), + std::ref(sfEPrice), + std::ref(sfLPTokenIn)}) + ammWithdraw(field); + // AMMBid + auto ammBid = [&](SField const& field) { + Json::Value jv; + jv[jss::TransactionType] = jss::AMMBid; + jv[jss::Account] = alice.human(); + jv[jss::Asset] = to_json(xrpIssue()); + jv[jss::Asset2] = to_json(USD.issue()); + jv[field.fieldName] = mpt.getJson(JsonOptions::none); + test(jv, field.fieldName); + }; + ammBid(sfBidMin); + ammBid(sfBidMax); + // CheckCash + auto checkCash = [&](SField const& field) { + Json::Value jv; + jv[jss::TransactionType] = jss::CheckCash; + jv[jss::Account] = alice.human(); + jv[sfCheckID.fieldName] = to_string(uint256{1}); + jv[field.fieldName] = mpt.getJson(JsonOptions::none); + test(jv, field.fieldName); + }; + checkCash(sfAmount); + checkCash(sfDeliverMin); + // CheckCreate + { + Json::Value jv; + jv[jss::TransactionType] = jss::CheckCreate; + jv[jss::Account] = alice.human(); + jv[jss::Destination] = carol.human(); + jv[jss::SendMax] = mpt.getJson(JsonOptions::none); + test(jv, jss::SendMax.c_str()); + } + // EscrowCreate + { + Json::Value jv; + jv[jss::TransactionType] = jss::EscrowCreate; + jv[jss::Account] = alice.human(); + jv[jss::Destination] = carol.human(); + jv[jss::Amount] = mpt.getJson(JsonOptions::none); + test(jv, jss::Amount.c_str()); + } + // OfferCreate + { + Json::Value jv = offer(alice, USD(100), mpt); + test(jv, jss::TakerPays.c_str()); + jv = offer(alice, mpt, USD(100)); + test(jv, jss::TakerGets.c_str()); + } + // PaymentChannelCreate + { + Json::Value jv; + jv[jss::TransactionType] = jss::PaymentChannelCreate; + jv[jss::Account] = alice.human(); + jv[jss::Destination] = carol.human(); + jv[jss::SettleDelay] = 1; + jv[sfPublicKey.fieldName] = strHex(alice.pk().slice()); + jv[jss::Amount] = mpt.getJson(JsonOptions::none); + test(jv, jss::Amount.c_str()); + } + // PaymentChannelFund + { + Json::Value jv; + jv[jss::TransactionType] = jss::PaymentChannelFund; + jv[jss::Account] = alice.human(); + jv[sfChannel.fieldName] = to_string(uint256{1}); + jv[jss::Amount] = mpt.getJson(JsonOptions::none); + test(jv, jss::Amount.c_str()); + } + // PaymentChannelClaim + { + Json::Value jv; + jv[jss::TransactionType] = jss::PaymentChannelClaim; + jv[jss::Account] = alice.human(); + jv[sfChannel.fieldName] = to_string(uint256{1}); + jv[jss::Amount] = mpt.getJson(JsonOptions::none); + test(jv, jss::Amount.c_str()); + } + // NFTokenCreateOffer + { + Json::Value jv; + jv[jss::TransactionType] = jss::NFTokenCreateOffer; + jv[jss::Account] = alice.human(); + jv[sfNFTokenID.fieldName] = to_string(uint256{1}); + jv[jss::Amount] = mpt.getJson(JsonOptions::none); + test(jv, jss::Amount.c_str()); + } + // NFTokenAcceptOffer + { + Json::Value jv; + jv[jss::TransactionType] = jss::NFTokenAcceptOffer; + jv[jss::Account] = alice.human(); + jv[sfNFTokenBrokerFee.fieldName] = + mpt.getJson(JsonOptions::none); + test(jv, sfNFTokenBrokerFee.fieldName); + } + // NFTokenMint + { + Json::Value jv; + jv[jss::TransactionType] = jss::NFTokenMint; + jv[jss::Account] = alice.human(); + jv[sfNFTokenTaxon.fieldName] = 1; + jv[jss::Amount] = mpt.getJson(JsonOptions::none); + test(jv, jss::Amount.c_str()); + } + // TrustSet + auto trustSet = [&](SField const& field) { + Json::Value jv; + jv[jss::TransactionType] = jss::TrustSet; + jv[jss::Account] = alice.human(); + jv[jss::Flags] = 0; + jv[field.fieldName] = mpt.getJson(JsonOptions::none); + test(jv, field.fieldName); + }; + trustSet(sfLimitAmount); + trustSet(sfFee); + // XChainCommit + { + Json::Value const jv = xchain_commit(alice, jvb, 1, mpt); + test(jv, jss::Amount.c_str()); + } + // XChainClaim + { + Json::Value const jv = xchain_claim(alice, jvb, 1, mpt, alice); + test(jv, jss::Amount.c_str()); + } + // XChainCreateClaimID + { + Json::Value const jv = + xchain_create_claim_id(alice, jvb, mpt, alice); + test(jv, sfSignatureReward.fieldName); + } + // XChainAddClaimAttestation + { + Json::Value const jv = claim_attestation( + alice, + jvb, + alice, + mpt, + alice, + true, + 1, + alice, + signer(alice)); + test(jv, jss::Amount.c_str()); + } + // XChainAddAccountCreateAttestation + { + Json::Value jv = create_account_attestation( + alice, + jvb, + alice, + mpt, + XRP(10), + alice, + false, + 1, + alice, + signer(alice)); + for (auto const& field : + {sfAmount.fieldName, sfSignatureReward.fieldName}) + { + jv[field] = mpt.getJson(JsonOptions::none); + test(jv, field); + } + } + // XChainAccountCreateCommit + { + Json::Value jv = sidechain_xchain_account_create( + alice, jvb, alice, mpt, XRP(10)); + for (auto const& field : + {sfAmount.fieldName, sfSignatureReward.fieldName}) + { + jv[field] = mpt.getJson(JsonOptions::none); + test(jv, field); + } + } + // XChain[Create|Modify]Bridge + auto bridgeTx = [&](Json::StaticString const& tt, + STAmount const& rewardAmount, + STAmount const& minAccountAmount, + std::string const& field) { + Json::Value jv; + jv[jss::TransactionType] = tt; + jv[jss::Account] = alice.human(); + jv[sfXChainBridge.fieldName] = jvb; + jv[sfSignatureReward.fieldName] = + rewardAmount.getJson(JsonOptions::none); + jv[sfMinAccountCreateAmount.fieldName] = + minAccountAmount.getJson(JsonOptions::none); + test(jv, field); + }; + auto reward = STAmount{sfSignatureReward, mpt}; + auto minAmount = STAmount{sfMinAccountCreateAmount, USD(10)}; + for (SField const& field : + {std::ref(sfSignatureReward), + std::ref(sfMinAccountCreateAmount)}) + { + bridgeTx( + jss::XChainCreateBridge, + reward, + minAmount, + field.fieldName); + bridgeTx( + jss::XChainModifyBridge, + reward, + minAmount, + field.fieldName); + reward = STAmount{sfSignatureReward, USD(10)}; + minAmount = STAmount{sfMinAccountCreateAmount, mpt}; + } + } + BEAST_EXPECT(txWithAmounts.empty()); + } + + void + testTxJsonMetaFields(FeatureBitset features) + { + // checks synthetically injected mptissuanceid from `tx` response + testcase("Test synthetic fields from tx response"); + + using namespace test::jtx; + + Account const alice{"alice"}; + + Env env{*this, features}; + MPTTester mptAlice(env, alice); + + mptAlice.create(); + + std::string const txHash{ + env.tx()->getJson(JsonOptions::none)[jss::hash].asString()}; + BEAST_EXPECTS( + txHash == + "E11F0E0CA14219922B7881F060B9CEE67CFBC87E4049A441ED2AE348FF8FAC" + "0E", + txHash); + Json::Value const meta = env.rpc("tx", txHash)[jss::result][jss::meta]; + auto const id = meta[jss::mpt_issuance_id].asString(); + // Expect mpt_issuance_id field + BEAST_EXPECT(meta.isMember(jss::mpt_issuance_id)); + BEAST_EXPECT(id == to_string(mptAlice.issuanceID())); + BEAST_EXPECTS( + id == "00000004AE123A8556F3CF91154711376AFB0F894F832B3D", id); + } + + void + testClawbackValidation(FeatureBitset features) + { + testcase("MPT clawback validations"); + using namespace test::jtx; + + // Make sure clawback cannot work when featureMPTokensV1 is disabled + { + Env env(*this, features - featureMPTokensV1); + Account const alice{"alice"}; + Account const bob{"bob"}; + + env.fund(XRP(1000), alice, bob); + env.close(); + + auto const USD = alice["USD"]; + auto const mpt = ripple::test::jtx::MPT( + alice.name(), makeMptID(env.seq(alice), alice)); + + env(claw(alice, bob["USD"](5), bob), ter(temMALFORMED)); + env.close(); + + env(claw(alice, mpt(5)), ter(temDISABLED)); + env.close(); + + env(claw(alice, mpt(5), bob), ter(temDISABLED)); + env.close(); + } + + // Test preflight + { + Env env(*this, features); + Account const alice{"alice"}; + Account const bob{"bob"}; + + env.fund(XRP(1000), alice, bob); + env.close(); + + auto const USD = alice["USD"]; + auto const mpt = ripple::test::jtx::MPT( + alice.name(), makeMptID(env.seq(alice), alice)); + + // clawing back IOU from a MPT holder fails + env(claw(alice, bob["USD"](5), bob), ter(temMALFORMED)); + env.close(); + + // clawing back MPT without specifying a holder fails + env(claw(alice, mpt(5)), ter(temMALFORMED)); + env.close(); + + // clawing back zero amount fails + env(claw(alice, mpt(0), bob), ter(temBAD_AMOUNT)); + env.close(); + + // alice can't claw back from herself + env(claw(alice, mpt(5), alice), ter(temMALFORMED)); + env.close(); + + // can't clawback negative amount + env(claw(alice, mpt(-1), bob), ter(temBAD_AMOUNT)); + env.close(); + } + + // Preclaim - clawback fails when MPTCanClawback is disabled on issuance + { + Env env(*this, features); + Account const alice{"alice"}; + Account const bob{"bob"}; + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + // enable asfAllowTrustLineClawback for alice + env(fset(alice, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(alice, asfAllowTrustLineClawback)); + + // Create issuance without enabling clawback + mptAlice.create({.ownerCount = 1, .holderCount = 0}); + + mptAlice.authorize({.account = bob}); + + mptAlice.pay(alice, bob, 100); + + // alice cannot clawback before she didn't enable MPTCanClawback + // asfAllowTrustLineClawback has no effect + mptAlice.claw(alice, bob, 1, tecNO_PERMISSION); + } + + // Preclaim - test various scenarios + { + Env env(*this, features); + Account const alice{"alice"}; + Account const bob{"bob"}; + Account const carol{"carol"}; + env.fund(XRP(1000), carol); + env.close(); + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + auto const fakeMpt = ripple::test::jtx::MPT( + alice.name(), makeMptID(env.seq(alice), alice)); + + // issuer tries to clawback MPT where issuance doesn't exist + env(claw(alice, fakeMpt(5), bob), ter(tecOBJECT_NOT_FOUND)); + env.close(); + + // alice creates issuance + mptAlice.create( + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanClawback}); + + // alice tries to clawback from someone who doesn't have MPToken + mptAlice.claw(alice, bob, 1, tecOBJECT_NOT_FOUND); + + // bob creates a MPToken + mptAlice.authorize({.account = bob}); + + // clawback fails because bob currently has a balance of zero + mptAlice.claw(alice, bob, 1, tecINSUFFICIENT_FUNDS); + + // alice pays bob 100 tokens + mptAlice.pay(alice, bob, 100); + + // carol fails tries to clawback from bob because he is not the + // issuer + mptAlice.claw(carol, bob, 1, tecNO_PERMISSION); + } + + // clawback more than max amount + // fails in the json parser before + // transactor is called + { + Env env(*this, features); + Account const alice{"alice"}; + Account const bob{"bob"}; + + env.fund(XRP(1000), alice, bob); + env.close(); + + auto const mpt = ripple::test::jtx::MPT( + alice.name(), makeMptID(env.seq(alice), alice)); + + Json::Value jv = claw(alice, mpt(1), bob); + jv[jss::Amount][jss::value] = to_string(maxMPTokenAmount + 1); + Json::Value jv1; + jv1[jss::secret] = alice.name(); + jv1[jss::tx_json] = jv; + auto const jrr = env.rpc("json", "submit", to_string(jv1)); + BEAST_EXPECT(jrr[jss::result][jss::error] == "invalidParams"); + } + } + + void + testClawback(FeatureBitset features) + { + testcase("MPT Clawback"); + using namespace test::jtx; + + { + Env env(*this, features); + Account const alice{"alice"}; + Account const bob{"bob"}; + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + // alice creates issuance + mptAlice.create( + {.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanClawback}); + + // bob creates a MPToken + mptAlice.authorize({.account = bob}); + + // alice pays bob 100 tokens + mptAlice.pay(alice, bob, 100); + + mptAlice.claw(alice, bob, 1); + + mptAlice.claw(alice, bob, 1000); + + // clawback fails because bob currently has a balance of zero + mptAlice.claw(alice, bob, 1, tecINSUFFICIENT_FUNDS); + } + + // Test that globally locked funds can be clawed + { + Env env(*this, features); + Account const alice{"alice"}; + Account const bob{"bob"}; + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + // alice creates issuance + mptAlice.create( + {.ownerCount = 1, + .holderCount = 0, + .flags = tfMPTCanLock | tfMPTCanClawback}); + + // bob creates a MPToken + mptAlice.authorize({.account = bob}); + + // alice pays bob 100 tokens + mptAlice.pay(alice, bob, 100); + + mptAlice.set({.account = alice, .flags = tfMPTLock}); + + mptAlice.claw(alice, bob, 100); + } + + // Test that individually locked funds can be clawed + { + Env env(*this, features); + Account const alice{"alice"}; + Account const bob{"bob"}; + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + // alice creates issuance + mptAlice.create( + {.ownerCount = 1, + .holderCount = 0, + .flags = tfMPTCanLock | tfMPTCanClawback}); + + // bob creates a MPToken + mptAlice.authorize({.account = bob}); + + // alice pays bob 100 tokens + mptAlice.pay(alice, bob, 100); + + mptAlice.set({.account = alice, .holder = bob, .flags = tfMPTLock}); + + mptAlice.claw(alice, bob, 100); + } + + // Test that unauthorized funds can be clawed back + { + Env env(*this, features); + Account const alice{"alice"}; + Account const bob{"bob"}; + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + + // alice creates issuance + mptAlice.create( + {.ownerCount = 1, + .holderCount = 0, + .flags = tfMPTCanClawback | tfMPTRequireAuth}); + + // bob creates a MPToken + mptAlice.authorize({.account = bob}); + + // alice authorizes bob + mptAlice.authorize({.account = alice, .holder = bob}); + + // alice pays bob 100 tokens + mptAlice.pay(alice, bob, 100); + + // alice unauthorizes bob + mptAlice.authorize( + {.account = alice, .holder = bob, .flags = tfMPTUnauthorize}); + + mptAlice.claw(alice, bob, 100); + } + } + +public: + void + run() override + { + using namespace test::jtx; + FeatureBitset const all{supported_amendments()}; + + // MPTokenIssuanceCreate + testCreateValidation(all); + testCreateEnabled(all); + + // MPTokenIssuanceDestroy + testDestroyValidation(all); + testDestroyEnabled(all); + + // MPTokenAuthorize + testAuthorizeValidation(all); + testAuthorizeEnabled(all); + + // MPTokenIssuanceSet + testSetValidation(all); + testSetEnabled(all); + + // MPT clawback + testClawbackValidation(all); + testClawback(all); + + // Test Direct Payment + testPayment(all); + + // Test MPT Amount is invalid in Tx, which don't support MPT + testMPTInvalidInTx(all); + + // Test parsed MPTokenIssuanceID in API response metadata + testTxJsonMetaFields(all); + } +}; + +BEAST_DEFINE_TESTSUITE_PRIO(MPToken, tx, ripple, 2); + +} // namespace ripple diff --git a/src/test/app/SetAuth_test.cpp b/src/test/app/SetAuth_test.cpp index adb909314d3..3dd8ab590a4 100644 --- a/src/test/app/SetAuth_test.cpp +++ b/src/test/app/SetAuth_test.cpp @@ -38,8 +38,8 @@ struct SetAuth_test : public beast::unit_test::suite using namespace jtx; Json::Value jv; jv[jss::Account] = account.human(); - jv[jss::LimitAmount] = - STAmount({to_currency(currency), dest}).getJson(JsonOptions::none); + jv[jss::LimitAmount] = STAmount(Issue{to_currency(currency), dest}) + .getJson(JsonOptions::none); jv[jss::TransactionType] = jss::TrustSet; jv[jss::Flags] = tfSetfAuth; return jv; diff --git a/src/test/app/TrustAndBalance_test.cpp b/src/test/app/TrustAndBalance_test.cpp index bf7c8629b69..b438d797276 100644 --- a/src/test/app/TrustAndBalance_test.cpp +++ b/src/test/app/TrustAndBalance_test.cpp @@ -400,7 +400,6 @@ class TrustAndBalance_test : public beast::unit_test::suite carol["USD"].issue(), 6500000000000000ull, -14, - false, true, STAmount::unchecked{}))); env.require(balance(carol, gw["USD"](35))); diff --git a/src/test/jtx.h b/src/test/jtx.h index 6de7cd480fa..49790e34022 100644 --- a/src/test/jtx.h +++ b/src/test/jtx.h @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include diff --git a/src/test/jtx/Env.h b/src/test/jtx/Env.h index 2c5f2f37062..d90d2bc1228 100644 --- a/src/test/jtx/Env.h +++ b/src/test/jtx/Env.h @@ -446,6 +446,12 @@ class Env PrettyAmount balance(Account const& account, Issue const& issue) const; + /** Return the number of objects owned by an account. + * Returns 0 if the account does not exist. + */ + std::uint32_t + ownerCount(Account const& account) const; + /** Return an account root. @return empty if the account does not exist. */ diff --git a/src/test/jtx/amount.h b/src/test/jtx/amount.h index 459ec5b5c65..9468b791f3d 100644 --- a/src/test/jtx/amount.h +++ b/src/test/jtx/amount.h @@ -306,15 +306,19 @@ class IOU return {currency, account.id()}; } - /** Implicit conversion to Issue. + /** Implicit conversion to Issue or Asset. This allows passing an IOU - value where an Issue is expected. + value where an Issue or Asset is expected. */ operator Issue() const { return issue(); } + operator Asset() const + { + return issue(); + } template < class T, @@ -355,6 +359,67 @@ operator<<(std::ostream& os, IOU const& iou); //------------------------------------------------------------------------------ +/** Converts to MPT Issue or STAmount. + + Examples: + MPT Converts to the underlying Issue + MPT(10) Returns STAmount of 10 of + the underlying MPT +*/ +class MPT +{ +public: + std::string name; + ripple::MPTID issuanceID; + + MPT(std::string const& n, ripple::MPTID const& issuanceID_) + : name(n), issuanceID(issuanceID_) + { + } + + ripple::MPTID const& + mpt() const + { + return issuanceID; + } + + /** Implicit conversion to MPTIssue. + + This allows passing an MPT + value where an MPTIssue is expected. + */ + operator ripple::MPTIssue() const + { + return MPTIssue{issuanceID}; + } + + template + requires(sizeof(T) >= sizeof(int) && std::is_arithmetic_v) + PrettyAmount + operator()(T v) const + { + return {amountFromString(mpt(), std::to_string(v)), name}; + } + + PrettyAmount + operator()(epsilon_t) const; + PrettyAmount + operator()(detail::epsilon_multiple) const; + + friend BookSpec + operator~(MPT const& mpt) + { + assert(false); + Throw("MPT is not supported"); + return BookSpec{beast::zero, noCurrency()}; + } +}; + +std::ostream& +operator<<(std::ostream& os, MPT const& mpt); + +//------------------------------------------------------------------------------ + struct any_t { inline AnyAmount diff --git a/src/test/jtx/impl/mpt.cpp b/src/test/jtx/impl/mpt.cpp new file mode 100644 index 00000000000..d3611efe462 --- /dev/null +++ b/src/test/jtx/impl/mpt.cpp @@ -0,0 +1,412 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 + +#include + +namespace ripple { +namespace test { +namespace jtx { + +void +mptflags::operator()(Env& env) const +{ + env.test.expect(tester_.checkFlags(flags_, holder_)); +} + +void +mptbalance::operator()(Env& env) const +{ + env.test.expect(amount_ == tester_.getBalance(account_)); +} + +void +requireAny::operator()(Env& env) const +{ + env.test.expect(cb_()); +} + +std::unordered_map +MPTTester::makeHolders(std::vector const& holders) +{ + std::unordered_map accounts; + for (auto const& h : holders) + { + if (accounts.find(h.human()) != accounts.cend()) + Throw("Duplicate holder"); + accounts.emplace(h.human(), h); + } + return accounts; +} + +MPTTester::MPTTester(Env& env, Account const& issuer, MPTInit const& arg) + : env_(env) + , issuer_(issuer) + , holders_(makeHolders(arg.holders)) + , close_(arg.close) +{ + if (arg.fund) + { + env_.fund(arg.xrp, issuer_); + for (auto it : holders_) + env_.fund(arg.xrpHolders, it.second); + } + if (close_) + env.close(); + if (arg.fund) + { + env_.require(owners(issuer_, 0)); + for (auto it : holders_) + { + if (issuer_.id() == it.second.id()) + Throw("Issuer can't be holder"); + env_.require(owners(it.second, 0)); + } + } +} + +void +MPTTester::create(const MPTCreate& arg) +{ + if (id_) + Throw("MPT can't be reused"); + id_ = makeMptID(env_.seq(issuer_), issuer_); + Json::Value jv; + jv[sfAccount] = issuer_.human(); + jv[sfTransactionType] = jss::MPTokenIssuanceCreate; + if (arg.assetScale) + jv[sfAssetScale] = *arg.assetScale; + if (arg.transferFee) + jv[sfTransferFee] = *arg.transferFee; + if (arg.metadata) + jv[sfMPTokenMetadata] = strHex(*arg.metadata); + if (arg.maxAmt) + jv[sfMaximumAmount] = std::to_string(*arg.maxAmt); + if (submit(arg, jv) != tesSUCCESS) + { + // Verify issuance doesn't exist + env_.require(requireAny([&]() -> bool { + return env_.le(keylet::mptIssuance(*id_)) == nullptr; + })); + + id_.reset(); + } + else + env_.require(mptflags(*this, arg.flags.value_or(0))); +} + +void +MPTTester::destroy(MPTDestroy const& arg) +{ + Json::Value jv; + if (arg.issuer) + jv[sfAccount] = arg.issuer->human(); + else + jv[sfAccount] = issuer_.human(); + if (arg.id) + jv[sfMPTokenIssuanceID] = to_string(*arg.id); + else + { + if (!id_) + Throw("MPT has not been created"); + jv[sfMPTokenIssuanceID] = to_string(*id_); + } + jv[sfTransactionType] = jss::MPTokenIssuanceDestroy; + submit(arg, jv); +} + +Account const& +MPTTester::holder(std::string const& holder_) const +{ + auto const& it = holders_.find(holder_); + if (it == holders_.cend()) + Throw("Holder is not found"); + return it->second; +} + +void +MPTTester::authorize(MPTAuthorize const& arg) +{ + Json::Value jv; + if (arg.account) + jv[sfAccount] = arg.account->human(); + else + jv[sfAccount] = issuer_.human(); + jv[sfTransactionType] = jss::MPTokenAuthorize; + if (arg.id) + jv[sfMPTokenIssuanceID] = to_string(*arg.id); + else + { + if (!id_) + Throw("MPT has not been created"); + jv[sfMPTokenIssuanceID] = to_string(*id_); + } + if (arg.holder) + jv[sfHolder] = arg.holder->human(); + if (auto const result = submit(arg, jv); result == tesSUCCESS) + { + // Issuer authorizes + if (!arg.account || *arg.account == issuer_) + { + auto const flags = getFlags(arg.holder); + // issuer un-authorizes the holder + if (arg.flags.value_or(0) == tfMPTUnauthorize) + env_.require(mptflags(*this, flags, arg.holder)); + // issuer authorizes the holder + else + env_.require( + mptflags(*this, flags | lsfMPTAuthorized, arg.holder)); + } + // Holder authorizes + else if (arg.flags.value_or(0) != tfMPTUnauthorize) + { + auto const flags = getFlags(arg.account); + // holder creates a token + env_.require(mptflags(*this, flags, arg.account)); + env_.require(mptbalance(*this, *arg.account, 0)); + } + else + { + // Verify that the MPToken doesn't exist. + forObject( + [&](SLEP const& sle) { return env_.test.BEAST_EXPECT(!sle); }, + arg.account); + } + } + else if ( + arg.account && *arg.account != issuer_ && + arg.flags.value_or(0) != tfMPTUnauthorize && id_) + { + if (result == tecDUPLICATE) + { + // Verify that MPToken already exists + env_.require(requireAny([&]() -> bool { + return env_.le(keylet::mptoken(*id_, arg.account->id())) != + nullptr; + })); + } + else + { + // Verify MPToken doesn't exist if holder failed authorizing(unless + // it already exists) + env_.require(requireAny([&]() -> bool { + return env_.le(keylet::mptoken(*id_, arg.account->id())) == + nullptr; + })); + } + } +} + +void +MPTTester::set(MPTSet const& arg) +{ + Json::Value jv; + if (arg.account) + jv[sfAccount] = arg.account->human(); + else + jv[sfAccount] = issuer_.human(); + jv[sfTransactionType] = jss::MPTokenIssuanceSet; + if (arg.id) + jv[sfMPTokenIssuanceID] = to_string(*arg.id); + else + { + if (!id_) + Throw("MPT has not been created"); + jv[sfMPTokenIssuanceID] = to_string(*id_); + } + if (arg.holder) + jv[sfHolder] = arg.holder->human(); + if (submit(arg, jv) == tesSUCCESS && arg.flags.value_or(0)) + { + auto require = [&](std::optional const& holder, + bool unchanged) { + auto flags = getFlags(holder); + if (!unchanged) + { + if (*arg.flags & tfMPTLock) + flags |= lsfMPTLocked; + else if (*arg.flags & tfMPTUnlock) + flags &= ~lsfMPTLocked; + else + Throw("Invalid flags"); + } + env_.require(mptflags(*this, flags, holder)); + }; + if (arg.account) + require(std::nullopt, arg.holder.has_value()); + if (arg.holder) + require(*arg.holder, false); + } +} + +bool +MPTTester::forObject( + std::function const& cb, + std::optional const& holder_) const +{ + if (!id_) + Throw("MPT has not been created"); + auto const key = holder_ ? keylet::mptoken(*id_, holder_->id()) + : keylet::mptIssuance(*id_); + if (auto const sle = env_.le(key)) + return cb(sle); + return false; +} + +[[nodiscard]] bool +MPTTester::checkMPTokenAmount( + Account const& holder_, + std::int64_t expectedAmount) const +{ + return forObject( + [&](SLEP const& sle) { return expectedAmount == (*sle)[sfMPTAmount]; }, + holder_); +} + +[[nodiscard]] bool +MPTTester::checkMPTokenOutstandingAmount(std::int64_t expectedAmount) const +{ + return forObject([&](SLEP const& sle) { + return expectedAmount == (*sle)[sfOutstandingAmount]; + }); +} + +[[nodiscard]] bool +MPTTester::checkFlags( + uint32_t const expectedFlags, + std::optional const& holder) const +{ + return expectedFlags == getFlags(holder); +} + +void +MPTTester::pay( + Account const& src, + Account const& dest, + std::int64_t amount, + std::optional err) +{ + if (!id_) + Throw("MPT has not been created"); + auto const srcAmt = getBalance(src); + auto const destAmt = getBalance(dest); + auto const outstnAmt = getBalance(issuer_); + env_(jtx::pay(src, dest, mpt(amount)), ter(err.value_or(tesSUCCESS))); + if (env_.ter() != tesSUCCESS) + amount = 0; + if (close_) + env_.close(); + if (src == issuer_) + { + env_.require(mptbalance(*this, src, srcAmt + amount)); + env_.require(mptbalance(*this, dest, destAmt + amount)); + } + else if (dest == issuer_) + { + env_.require(mptbalance(*this, src, srcAmt - amount)); + env_.require(mptbalance(*this, dest, destAmt - amount)); + } + else + { + STAmount const saAmount = {*id_, amount}; + auto const actual = + multiply(saAmount, transferRate(*env_.current(), *id_)) + .mpt() + .value(); + // Sender pays the transfer fee if any + env_.require(mptbalance(*this, src, srcAmt - actual)); + env_.require(mptbalance(*this, dest, destAmt + amount)); + // Outstanding amount is reduced by the transfer fee if any + env_.require(mptbalance(*this, issuer_, outstnAmt - (actual - amount))); + } +} + +void +MPTTester::claw( + Account const& issuer, + Account const& holder, + std::int64_t amount, + std::optional err) +{ + if (!id_) + Throw("MPT has not been created"); + auto const issuerAmt = getBalance(issuer); + auto const holderAmt = getBalance(holder); + env_(jtx::claw(issuer, mpt(amount), holder), ter(err.value_or(tesSUCCESS))); + if (env_.ter() != tesSUCCESS) + amount = 0; + if (close_) + env_.close(); + + env_.require( + mptbalance(*this, issuer, issuerAmt - std::min(holderAmt, amount))); + env_.require( + mptbalance(*this, holder, holderAmt - std::min(holderAmt, amount))); +} + +PrettyAmount +MPTTester::mpt(std::int64_t amount) const +{ + if (!id_) + Throw("MPT has not been created"); + return ripple::test::jtx::MPT(issuer_.name(), *id_)(amount); +} + +std::int64_t +MPTTester::getBalance(Account const& account) const +{ + if (!id_) + Throw("MPT has not been created"); + if (account == issuer_) + { + if (auto const sle = env_.le(keylet::mptIssuance(*id_))) + return sle->getFieldU64(sfOutstandingAmount); + } + else + { + if (auto const sle = env_.le(keylet::mptoken(*id_, account.id()))) + return sle->getFieldU64(sfMPTAmount); + } + return 0; +} + +std::uint32_t +MPTTester::getFlags(std::optional const& holder) const +{ + std::uint32_t flags = 0; + if (!forObject( + [&](SLEP const& sle) { + flags = sle->getFlags(); + return true; + }, + holder)) + Throw("Failed to get the flags"); + return flags; +} + +MPT +MPTTester::operator[](const std::string& name) +{ + return MPT(name, issuanceID()); +} + +} // namespace jtx +} // namespace test +} // namespace ripple diff --git a/src/test/jtx/impl/trust.cpp b/src/test/jtx/impl/trust.cpp index 641a0f79f28..dee4b282367 100644 --- a/src/test/jtx/impl/trust.cpp +++ b/src/test/jtx/impl/trust.cpp @@ -64,13 +64,19 @@ trust( } Json::Value -claw(Account const& account, STAmount const& amount) +claw( + Account const& account, + STAmount const& amount, + std::optional const& mptHolder) { Json::Value jv; jv[jss::Account] = account.human(); jv[jss::Amount] = amount.getJson(JsonOptions::none); jv[jss::TransactionType] = jss::Clawback; + if (mptHolder) + jv[sfHolder.jsonName] = mptHolder->human(); + return jv; } diff --git a/src/test/jtx/mpt.h b/src/test/jtx/mpt.h new file mode 100644 index 00000000000..16a08d8bad9 --- /dev/null +++ b/src/test/jtx/mpt.h @@ -0,0 +1,254 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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_TEST_JTX_MPT_H_INCLUDED +#define RIPPLE_TEST_JTX_MPT_H_INCLUDED + +#include +#include +#include + +#include + +namespace ripple { +namespace test { +namespace jtx { + +class MPTTester; + +// Check flags settings on MPT create +class mptflags +{ +private: + MPTTester& tester_; + std::uint32_t flags_; + std::optional holder_; + +public: + mptflags( + MPTTester& tester, + std::uint32_t flags, + std::optional const& holder = std::nullopt) + : tester_(tester), flags_(flags), holder_(holder) + { + } + + void + operator()(Env& env) const; +}; + +// Check mptissuance or mptoken amount balances on payment +class mptbalance +{ +private: + MPTTester const& tester_; + Account const& account_; + std::int64_t const amount_; + +public: + mptbalance(MPTTester& tester, Account const& account, std::int64_t amount) + : tester_(tester), account_(account), amount_(amount) + { + } + + void + operator()(Env& env) const; +}; + +class requireAny +{ +private: + std::function cb_; + +public: + requireAny(std::function const& cb) : cb_(cb) + { + } + + void + operator()(Env& env) const; +}; + +struct MPTInit +{ + std::vector holders = {}; + PrettyAmount const& xrp = XRP(10'000); + PrettyAmount const& xrpHolders = XRP(10'000); + bool fund = true; + bool close = true; +}; + +struct MPTCreate +{ + std::optional maxAmt = std::nullopt; + std::optional assetScale = std::nullopt; + std::optional transferFee = std::nullopt; + std::optional metadata = std::nullopt; + std::optional ownerCount = std::nullopt; + std::optional holderCount = std::nullopt; + bool fund = true; + std::optional flags = {0}; + std::optional err = std::nullopt; +}; + +struct MPTDestroy +{ + std::optional issuer = std::nullopt; + std::optional id = std::nullopt; + std::optional ownerCount = std::nullopt; + std::optional holderCount = std::nullopt; + std::optional flags = std::nullopt; + std::optional err = std::nullopt; +}; + +struct MPTAuthorize +{ + std::optional account = std::nullopt; + std::optional holder = std::nullopt; + std::optional id = std::nullopt; + std::optional ownerCount = std::nullopt; + std::optional holderCount = std::nullopt; + std::optional flags = std::nullopt; + std::optional err = std::nullopt; +}; + +struct MPTSet +{ + std::optional account = std::nullopt; + std::optional holder = std::nullopt; + std::optional id = std::nullopt; + std::optional ownerCount = std::nullopt; + std::optional holderCount = std::nullopt; + std::optional flags = std::nullopt; + std::optional err = std::nullopt; +}; + +class MPTTester +{ + Env& env_; + Account const& issuer_; + std::unordered_map const holders_; + std::optional id_; + bool close_; + +public: + MPTTester(Env& env, Account const& issuer, MPTInit const& constr = {}); + + void + create(MPTCreate const& arg = MPTCreate{}); + + void + destroy(MPTDestroy const& arg = MPTDestroy{}); + + void + authorize(MPTAuthorize const& arg = MPTAuthorize{}); + + void + set(MPTSet const& set = {}); + + [[nodiscard]] bool + checkMPTokenAmount(Account const& holder, std::int64_t expectedAmount) + const; + + [[nodiscard]] bool + checkMPTokenOutstandingAmount(std::int64_t expectedAmount) const; + + [[nodiscard]] bool + checkFlags( + uint32_t const expectedFlags, + std::optional const& holder = std::nullopt) const; + + Account const& + issuer() const + { + return issuer_; + } + Account const& + holder(std::string const& h) const; + + void + pay(Account const& src, + Account const& dest, + std::int64_t amount, + std::optional err = std::nullopt); + + void + claw( + Account const& issuer, + Account const& holder, + std::int64_t amount, + std::optional err = std::nullopt); + + PrettyAmount + mpt(std::int64_t amount) const; + + MPTID const& + issuanceID() const + { + if (!env_.test.BEAST_EXPECT(id_)) + Throw("Uninitialized issuanceID"); + return *id_; + } + + std::int64_t + getBalance(Account const& account) const; + + MPT + operator[](std::string const& name); + +private: + using SLEP = std::shared_ptr; + bool + forObject( + std::function const& cb, + std::optional const& holder = std::nullopt) const; + + template + TER + submit(A const& arg, Json::Value const& jv) + { + env_( + jv, + txflags(arg.flags.value_or(0)), + ter(arg.err.value_or(tesSUCCESS))); + auto const err = env_.ter(); + if (close_) + env_.close(); + if (arg.ownerCount) + env_.require(owners(issuer_, *arg.ownerCount)); + if (arg.holderCount) + { + for (auto it : holders_) + env_.require(owners(it.second, *arg.holderCount)); + } + return err; + } + + static std::unordered_map + makeHolders(std::vector const& holders); + + std::uint32_t + getFlags(std::optional const& holder) const; +}; + +} // namespace jtx +} // namespace test +} // namespace ripple + +#endif diff --git a/src/test/jtx/trust.h b/src/test/jtx/trust.h index f9fddf4871a..0d02c6e76c4 100644 --- a/src/test/jtx/trust.h +++ b/src/test/jtx/trust.h @@ -41,7 +41,10 @@ trust( std::uint32_t flags); Json::Value -claw(Account const& account, STAmount const& amount); +claw( + Account const& account, + STAmount const& amount, + std::optional const& mptHolder = std::nullopt); } // namespace jtx } // namespace test diff --git a/src/test/ledger/PaymentSandbox_test.cpp b/src/test/ledger/PaymentSandbox_test.cpp index e3ede19b4b6..dd9b5c5d88b 100644 --- a/src/test/ledger/PaymentSandbox_test.cpp +++ b/src/test/ledger/PaymentSandbox_test.cpp @@ -316,14 +316,12 @@ class PaymentSandbox_test : public beast::unit_test::suite STAmount::cMinValue, STAmount::cMinOffset + 1, false, - false, STAmount::unchecked{}); STAmount hugeAmt( issue, STAmount::cMaxValue, STAmount::cMaxOffset - 1, false, - false, STAmount::unchecked{}); ApplyViewImpl av(&*env.current(), tapNONE); diff --git a/src/test/protocol/Quality_test.cpp b/src/test/protocol/Quality_test.cpp index 741a341d980..64cf0c71b3a 100644 --- a/src/test/protocol/Quality_test.cpp +++ b/src/test/protocol/Quality_test.cpp @@ -29,7 +29,7 @@ class Quality_test : public beast::unit_test::suite // Create a raw, non-integral amount from mantissa and exponent STAmount static raw(std::uint64_t mantissa, int exponent) { - return STAmount({Currency(3), AccountID(3)}, mantissa, exponent); + return STAmount(Issue{Currency(3), AccountID(3)}, mantissa, exponent); } template diff --git a/src/test/protocol/STAmount_test.cpp b/src/test/protocol/STAmount_test.cpp index e48d0500ba6..b512c42a643 100644 --- a/src/test/protocol/STAmount_test.cpp +++ b/src/test/protocol/STAmount_test.cpp @@ -62,7 +62,6 @@ class STAmount_test : public beast::unit_test::suite amount.issue(), mantissa, amount.exponent(), - amount.native(), amount.negative(), STAmount::unchecked{}}; } @@ -82,7 +81,6 @@ class STAmount_test : public beast::unit_test::suite amount.issue(), mantissa, amount.exponent(), - amount.native(), amount.negative(), STAmount::unchecked{}}; } diff --git a/src/test/protocol/STObject_test.cpp b/src/test/protocol/STObject_test.cpp index 41c3800bce4..071a5f4f63c 100644 --- a/src/test/protocol/STObject_test.cpp +++ b/src/test/protocol/STObject_test.cpp @@ -394,6 +394,7 @@ class STObject_test : public beast::unit_test::suite auto const& sf1Outer = sfSequence; auto const& sf2Outer = sfExpiration; auto const& sf3Outer = sfQualityIn; + auto const& sf4Outer = sfAmount; auto const& sf4 = sfSignature; auto const& sf5 = sfPublicKey; @@ -425,6 +426,7 @@ class STObject_test : public beast::unit_test::suite {sf1Outer, soeREQUIRED}, {sf2Outer, soeOPTIONAL}, {sf3Outer, soeDEFAULT}, + {sf4Outer, soeOPTIONAL}, {sf4, soeOPTIONAL}, {sf5, soeDEFAULT}, }; @@ -492,6 +494,16 @@ class STObject_test : public beast::unit_test::suite BEAST_EXPECT(st[sf1Outer] == 4); BEAST_EXPECT(st[sf2Outer] == 4); BEAST_EXPECT(st[sf2Outer] == st[sf1Outer]); + st[sf1Outer] += 1; + BEAST_EXPECT(st[sf1Outer] == 5); + st[sf4Outer] = STAmount{1}; + BEAST_EXPECT(st[sf4Outer] == STAmount{1}); + st[sf4Outer] += STAmount{1}; + BEAST_EXPECT(st[sf4Outer] == STAmount{2}); + st[sf1Outer] -= 1; + BEAST_EXPECT(st[sf1Outer] == 4); + st[sf4Outer] -= STAmount{1}; + BEAST_EXPECT(st[sf4Outer] == STAmount{1}); } // Write templated object @@ -540,6 +552,16 @@ class STObject_test : public beast::unit_test::suite BEAST_EXPECT(st[sf3Outer] == 0); BEAST_EXPECT(*st[~sf3Outer] == 0); BEAST_EXPECT(!!st[~sf3Outer]); + st[sf1Outer] += 1; + BEAST_EXPECT(st[sf1Outer] == 1); + st[sf4Outer] = STAmount{1}; + BEAST_EXPECT(st[sf4Outer] == STAmount{1}); + st[sf4Outer] += STAmount{1}; + BEAST_EXPECT(st[sf4Outer] == STAmount{2}); + st[sf1Outer] -= 1; + BEAST_EXPECT(st[sf1Outer] == 0); + st[sf4Outer] -= STAmount{1}; + BEAST_EXPECT(st[sf4Outer] == STAmount{1}); } // coercion operator to std::optional diff --git a/src/test/protocol/STTx_test.cpp b/src/test/protocol/STTx_test.cpp index e0f6796af33..54037eaa5ba 100644 --- a/src/test/protocol/STTx_test.cpp +++ b/src/test/protocol/STTx_test.cpp @@ -1361,6 +1361,31 @@ class STTx_test : public beast::unit_test::suite 0x10, 0x00, 0x73, 0x00, 0x81, 0x14, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0xe5, 0xfe}; + constexpr unsigned char payload4[] = { + 0x12, 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, 0x20, 0x1e, 0x00, + 0x4f, 0x00, 0x00, 0x20, 0x1f, 0x03, 0xf6, 0x00, 0x00, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x68, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x73, 0x00, 0x81, 0x14, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe5, 0xfe, 0xf3, 0xe7, 0xe5, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x1e, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x20, 0x1f, 0x03, 0xf6, + 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x59, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x12, 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x1e, 0x00, 0x4f, 0x00, 0x00, 0x20, 0x1f, 0x03, 0xf6, + 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x35, 0x24, 0x59, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x54, 0x72, 0x61, 0x6e, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x24, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe5, 0xfe, 0xf3, 0xe7, 0xe5, 0x65, 0x24, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x1e, 0x00, 0x6f, 0x00, 0x00, 0x20, + 0xf6, 0x00, 0x00, 0x03, 0x1f, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x35, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x73, 0x00, 0x81, 0x14, + 0x00, 0x10, 0x00, 0x73, 0x00, 0x81, 0x14, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0xe5, 0xfe}; + // Construct an STObject with 11 levels of object nesting so the // maximum nesting level exception is thrown. { @@ -1574,6 +1599,18 @@ class STTx_test : public beast::unit_test::suite fail("An exception should have been thrown"); } catch (std::exception const& ex) + { + BEAST_EXPECT( + strcmp(ex.what(), "gFID: uncommon name out of range 0") == 0); + } + + try + { + ripple::SerialIter sit{payload4}; + auto stx = std::make_shared(sit); + fail("An exception should have been thrown"); + } + catch (std::exception const& ex) { BEAST_EXPECT(strcmp(ex.what(), "Unknown field") == 0); } diff --git a/src/test/rpc/LedgerRPC_test.cpp b/src/test/rpc/LedgerRPC_test.cpp index 70e4ffbe8dc..792da88b5bc 100644 --- a/src/test/rpc/LedgerRPC_test.cpp +++ b/src/test/rpc/LedgerRPC_test.cpp @@ -2361,6 +2361,79 @@ class LedgerRPC_test : public beast::unit_test::suite } } + void + testLedgerEntryMPT() + { + testcase("ledger_entry Request MPT"); + using namespace test::jtx; + using namespace std::literals::chrono_literals; + Env env{*this}; + Account const alice{"alice"}; + Account const bob("bob"); + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + mptAlice.create( + {.transferFee = 10, + .metadata = "123", + .ownerCount = 1, + .flags = tfMPTCanLock | tfMPTRequireAuth | tfMPTCanEscrow | + tfMPTCanTrade | tfMPTCanTransfer | tfMPTCanClawback}); + mptAlice.authorize({.account = bob, .holderCount = 1}); + + std::string const ledgerHash{to_string(env.closed()->info().hash)}; + + std::string const badMptID = + "00000193B9DDCAF401B5B3B26875986043F82CD0D13B4315"; + { + // Request the MPTIssuance using its MPTIssuanceID. + Json::Value jvParams; + jvParams[jss::mpt_issuance] = strHex(mptAlice.issuanceID()); + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT( + jrr[jss::node][sfMPTokenMetadata.jsonName] == + strHex(std::string{"123"})); + BEAST_EXPECT( + jrr[jss::node][jss::mpt_issuance_id] == + strHex(mptAlice.issuanceID())); + } + { + // Request an index that is not a MPTIssuance. + Json::Value jvParams; + jvParams[jss::mpt_issuance] = badMptID; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "entryNotFound", ""); + } + { + // Request the MPToken using its owner + mptIssuanceID. + Json::Value jvParams; + jvParams[jss::mptoken] = Json::objectValue; + jvParams[jss::mptoken][jss::account] = bob.human(); + jvParams[jss::mptoken][jss::mpt_issuance_id] = + strHex(mptAlice.issuanceID()); + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT( + jrr[jss::node][sfMPTokenIssuanceID.jsonName] == + strHex(mptAlice.issuanceID())); + } + { + // Request the MPToken using a bad mptIssuanceID. + Json::Value jvParams; + jvParams[jss::mptoken] = Json::objectValue; + jvParams[jss::mptoken][jss::account] = bob.human(); + jvParams[jss::mptoken][jss::mpt_issuance_id] = badMptID; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "entryNotFound", ""); + } + } + public: void run() override @@ -2388,6 +2461,7 @@ class LedgerRPC_test : public beast::unit_test::suite testLedgerEntryDID(); testInvalidOracleLedgerEntry(); testOracleLedgerEntry(); + testLedgerEntryMPT(); forAllApiVersions(std::bind_front( &LedgerRPC_test::testLedgerEntryInvalidParams, this)); diff --git a/src/xrpld/app/ledger/detail/LedgerToJson.cpp b/src/xrpld/app/ledger/detail/LedgerToJson.cpp index 9824b31d794..3f6869df1d8 100644 --- a/src/xrpld/app/ledger/detail/LedgerToJson.cpp +++ b/src/xrpld/app/ledger/detail/LedgerToJson.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -156,6 +157,12 @@ fillJsonTx( fill.ledger, txn, {txn->getTransactionID(), fill.ledger.seq(), *stMeta}); + + // If applicable, insert mpt issuance id + RPC::insertMPTokenIssuanceID( + txJson[jss::meta], + txn, + {txn->getTransactionID(), fill.ledger.seq(), *stMeta}); } if (!fill.ledger.open()) @@ -187,6 +194,12 @@ fillJsonTx( fill.ledger, txn, {txn->getTransactionID(), fill.ledger.seq(), *stMeta}); + + // If applicable, insert mpt issuance id + RPC::insertMPTokenIssuanceID( + txJson[jss::metaData], + txn, + {txn->getTransactionID(), fill.ledger.seq(), *stMeta}); } } diff --git a/src/xrpld/app/misc/NetworkOPs.cpp b/src/xrpld/app/misc/NetworkOPs.cpp index a95afd56933..46a7dfcaacd 100644 --- a/src/xrpld/app/misc/NetworkOPs.cpp +++ b/src/xrpld/app/misc/NetworkOPs.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -2962,6 +2963,8 @@ NetworkOPsImp::transJson( jvObj[jss::meta] = meta->get().getJson(JsonOptions::none); RPC::insertDeliveredAmount( jvObj[jss::meta], *ledger, transaction, meta->get()); + RPC::insertMPTokenIssuanceID( + jvObj[jss::meta], transaction, meta->get()); } if (!ledger->open()) diff --git a/src/xrpld/app/paths/Credit.cpp b/src/xrpld/app/paths/Credit.cpp index c11f628a11d..b3870937367 100644 --- a/src/xrpld/app/paths/Credit.cpp +++ b/src/xrpld/app/paths/Credit.cpp @@ -31,7 +31,7 @@ creditLimit( AccountID const& issuer, Currency const& currency) { - STAmount result({currency, account}); + STAmount result(Issue{currency, account}); auto sleRippleState = view.read(keylet::line(account, issuer, currency)); @@ -64,7 +64,7 @@ creditBalance( AccountID const& issuer, Currency const& currency) { - STAmount result({currency, account}); + STAmount result(Issue{currency, account}); auto sleRippleState = view.read(keylet::line(account, issuer, currency)); diff --git a/src/xrpld/app/paths/PathRequest.cpp b/src/xrpld/app/paths/PathRequest.cpp index 4cd9f7d71f7..bb6a104bca2 100644 --- a/src/xrpld/app/paths/PathRequest.cpp +++ b/src/xrpld/app/paths/PathRequest.cpp @@ -562,7 +562,7 @@ PathRequest::findPaths( }(); STAmount saMaxAmount = saSendMax.value_or( - STAmount({issue.currency, sourceAccount}, 1u, 0, true)); + STAmount(Issue{issue.currency, sourceAccount}, 1u, 0, true)); JLOG(m_journal.debug()) << iIdentifier << " Paths found, calling rippleCalc"; diff --git a/src/xrpld/app/paths/Pathfinder.cpp b/src/xrpld/app/paths/Pathfinder.cpp index a2c1be4cc7c..5122bc7d6b8 100644 --- a/src/xrpld/app/paths/Pathfinder.cpp +++ b/src/xrpld/app/paths/Pathfinder.cpp @@ -176,9 +176,10 @@ Pathfinder::Pathfinder( , mSrcCurrency(uSrcCurrency) , mSrcIssuer(uSrcIssuer) , mSrcAmount(srcAmount.value_or(STAmount( - {uSrcCurrency, - uSrcIssuer.value_or( - isXRP(uSrcCurrency) ? xrpAccount() : uSrcAccount)}, + Issue{ + uSrcCurrency, + uSrcIssuer.value_or( + isXRP(uSrcCurrency) ? xrpAccount() : uSrcAccount)}, 1u, 0, true))) diff --git a/src/xrpld/app/tx/detail/Clawback.cpp b/src/xrpld/app/tx/detail/Clawback.cpp index 15d76526094..f1040790a42 100644 --- a/src/xrpld/app/tx/detail/Clawback.cpp +++ b/src/xrpld/app/tx/detail/Clawback.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -27,17 +28,16 @@ namespace ripple { +template +static NotTEC +preflightHelper(PreflightContext const& ctx); + +template <> NotTEC -Clawback::preflight(PreflightContext const& ctx) +preflightHelper(PreflightContext const& ctx) { - if (!ctx.rules.enabled(featureClawback)) - return temDISABLED; - - if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) - return ret; - - if (ctx.tx.getFlags() & tfClawbackMask) - return temINVALID_FLAG; + if (ctx.tx.isFieldPresent(sfHolder)) + return temMALFORMED; AccountID const issuer = ctx.tx[sfAccount]; STAmount const clawAmount = ctx.tx[sfAmount]; @@ -48,25 +48,73 @@ Clawback::preflight(PreflightContext const& ctx) if (issuer == holder || isXRP(clawAmount) || clawAmount <= beast::zero) return temBAD_AMOUNT; - return preflight2(ctx); + return tesSUCCESS; } -TER -Clawback::preclaim(PreclaimContext const& ctx) +template <> +NotTEC +preflightHelper(PreflightContext const& ctx) { - AccountID const issuer = ctx.tx[sfAccount]; - STAmount const clawAmount = ctx.tx[sfAmount]; - AccountID const& holder = clawAmount.getIssuer(); + if (!ctx.rules.enabled(featureMPTokensV1)) + return temDISABLED; - auto const sleIssuer = ctx.view.read(keylet::account(issuer)); - auto const sleHolder = ctx.view.read(keylet::account(holder)); - if (!sleIssuer || !sleHolder) - return terNO_ACCOUNT; + auto const mptHolder = ctx.tx[~sfHolder]; + auto const clawAmount = ctx.tx[sfAmount]; - if (sleHolder->isFieldPresent(sfAMMID)) - return tecAMM_ACCOUNT; + if (!mptHolder) + return temMALFORMED; + + // issuer is the same as holder + if (ctx.tx[sfAccount] == *mptHolder) + return temMALFORMED; + + if (clawAmount.mpt() > MPTAmount{maxMPTokenAmount} || + clawAmount <= beast::zero) + return temBAD_AMOUNT; + + return tesSUCCESS; +} + +NotTEC +Clawback::preflight(PreflightContext const& ctx) +{ + if (!ctx.rules.enabled(featureClawback)) + return temDISABLED; - std::uint32_t const issuerFlagsIn = sleIssuer->getFieldU32(sfFlags); + if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) + return ret; + + if (ctx.tx.getFlags() & tfClawbackMask) + return temINVALID_FLAG; + + if (auto const ret = std::visit( + [&](T const&) { return preflightHelper(ctx); }, + ctx.tx[sfAmount].asset().value()); + !isTesSuccess(ret)) + return ret; + + return preflight2(ctx); +} + +template +static TER +preclaimHelper( + PreclaimContext const& ctx, + SLE const& sleIssuer, + AccountID const& issuer, + AccountID const& holder, + STAmount const& clawAmount); + +template <> +TER +preclaimHelper( + PreclaimContext const& ctx, + SLE const& sleIssuer, + AccountID const& issuer, + AccountID const& holder, + STAmount const& clawAmount) +{ + std::uint32_t const issuerFlagsIn = sleIssuer.getFieldU32(sfFlags); // If AllowTrustLineClawback is not set or NoFreeze is set, return no // permission @@ -110,11 +158,76 @@ Clawback::preclaim(PreclaimContext const& ctx) return tesSUCCESS; } +template <> TER -Clawback::doApply() +preclaimHelper( + PreclaimContext const& ctx, + SLE const& sleIssuer, + AccountID const& issuer, + AccountID const& holder, + STAmount const& clawAmount) { - AccountID const& issuer = account_; - STAmount clawAmount = ctx_.tx[sfAmount]; + auto const issuanceKey = + keylet::mptIssuance(clawAmount.get().getMptID()); + auto const sleIssuance = ctx.view.read(issuanceKey); + if (!sleIssuance) + return tecOBJECT_NOT_FOUND; + + if (!((*sleIssuance)[sfFlags] & lsfMPTCanClawback)) + return tecNO_PERMISSION; + + if (sleIssuance->getAccountID(sfIssuer) != issuer) + return tecNO_PERMISSION; + + if (!ctx.view.exists(keylet::mptoken(issuanceKey.key, holder))) + return tecOBJECT_NOT_FOUND; + + if (accountHolds( + ctx.view, + holder, + clawAmount.get(), + fhIGNORE_FREEZE, + ahIGNORE_AUTH, + ctx.j) <= beast::zero) + return tecINSUFFICIENT_FUNDS; + + return tesSUCCESS; +} + +TER +Clawback::preclaim(PreclaimContext const& ctx) +{ + AccountID const issuer = ctx.tx[sfAccount]; + auto const clawAmount = ctx.tx[sfAmount]; + AccountID const holder = + clawAmount.holds() ? clawAmount.getIssuer() : ctx.tx[sfHolder]; + + auto const sleIssuer = ctx.view.read(keylet::account(issuer)); + auto const sleHolder = ctx.view.read(keylet::account(holder)); + if (!sleIssuer || !sleHolder) + return terNO_ACCOUNT; + + if (sleHolder->isFieldPresent(sfAMMID)) + return tecAMM_ACCOUNT; + + return std::visit( + [&](T const&) { + return preclaimHelper( + ctx, *sleIssuer, issuer, holder, clawAmount); + }, + ctx.tx[sfAmount].asset().value()); +} + +template +static TER +applyHelper(ApplyContext& ctx); + +template <> +TER +applyHelper(ApplyContext& ctx) +{ + AccountID const issuer = ctx.tx[sfAccount]; + STAmount clawAmount = ctx.tx[sfAmount]; AccountID const holder = clawAmount.getIssuer(); // cannot be reference // Replace the `issuer` field with issuer's account @@ -124,20 +237,54 @@ Clawback::doApply() // Get the spendable balance. Must use `accountHolds`. STAmount const spendableAmount = accountHolds( - view(), + ctx.view(), holder, clawAmount.getCurrency(), clawAmount.getIssuer(), fhIGNORE_FREEZE, - j_); + ctx.journal); return rippleCredit( - view(), + ctx.view(), holder, issuer, std::min(spendableAmount, clawAmount), true, - j_); + ctx.journal); +} + +template <> +TER +applyHelper(ApplyContext& ctx) +{ + AccountID const issuer = ctx.tx[sfAccount]; + auto clawAmount = ctx.tx[sfAmount]; + AccountID const holder = ctx.tx[sfHolder]; + + // Get the spendable balance. Must use `accountHolds`. + STAmount const spendableAmount = accountHolds( + ctx.view(), + holder, + clawAmount.get(), + fhIGNORE_FREEZE, + ahIGNORE_AUTH, + ctx.journal); + + return rippleCredit( + ctx.view(), + holder, + issuer, + std::min(spendableAmount, clawAmount), + /*checkIssuer*/ false, + ctx.journal); +} + +TER +Clawback::doApply() +{ + return std::visit( + [&](T const&) { return applyHelper(ctx_); }, + ctx_.tx[sfAmount].asset().value()); } } // namespace ripple diff --git a/src/xrpld/app/tx/detail/InvariantCheck.cpp b/src/xrpld/app/tx/detail/InvariantCheck.cpp index f855ad8578c..e8bbd0283b5 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.cpp +++ b/src/xrpld/app/tx/detail/InvariantCheck.cpp @@ -478,6 +478,8 @@ LedgerEntryTypesMatch::visitEntry( case ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID: case ltDID: case ltORACLE: + case ltMPTOKEN_ISSUANCE: + case ltMPTOKEN: break; default: invalidTypeAdded_ = true; @@ -882,6 +884,9 @@ ValidClawback::visitEntry( { if (before && before->getType() == ltRIPPLE_STATE) trustlinesChanged++; + + if (before && before->getType() == ltMPTOKEN) + mptokensChanged++; } bool @@ -904,18 +909,28 @@ ValidClawback::finalize( return false; } - AccountID const issuer = tx.getAccountID(sfAccount); - STAmount const amount = tx.getFieldAmount(sfAmount); - AccountID const& holder = amount.getIssuer(); - STAmount const holderBalance = accountHolds( - view, holder, amount.getCurrency(), issuer, fhIGNORE_FREEZE, j); - - if (holderBalance.signum() < 0) + if (mptokensChanged > 1) { JLOG(j.fatal()) - << "Invariant failed: trustline balance is negative"; + << "Invariant failed: more than one mptokens changed."; return false; } + + if (trustlinesChanged == 1) + { + AccountID const issuer = tx.getAccountID(sfAccount); + STAmount const& amount = tx.getFieldAmount(sfAmount); + AccountID const& holder = amount.getIssuer(); + STAmount const holderBalance = accountHolds( + view, holder, amount.getCurrency(), issuer, fhIGNORE_FREEZE, j); + + if (holderBalance.signum() < 0) + { + JLOG(j.fatal()) + << "Invariant failed: trustline balance is negative"; + return false; + } + } } else { @@ -925,9 +940,182 @@ ValidClawback::finalize( "despite failure of the transaction."; return false; } + + if (mptokensChanged != 0) + { + JLOG(j.fatal()) << "Invariant failed: some mptokens were changed " + "despite failure of the transaction."; + return false; + } } return true; } +//------------------------------------------------------------------------------ + +void +ValidMPTIssuance::visitEntry( + bool isDelete, + std::shared_ptr const& before, + std::shared_ptr const& after) +{ + if (after && after->getType() == ltMPTOKEN_ISSUANCE) + { + if (isDelete) + mptIssuancesDeleted_++; + else if (!before) + mptIssuancesCreated_++; + } + + if (after && after->getType() == ltMPTOKEN) + { + if (isDelete) + mptokensDeleted_++; + else if (!before) + mptokensCreated_++; + } +} + +bool +ValidMPTIssuance::finalize( + STTx const& tx, + TER const result, + XRPAmount const _fee, + ReadView const& _view, + beast::Journal const& j) +{ + if (result == tesSUCCESS) + { + if (tx.getTxnType() == ttMPTOKEN_ISSUANCE_CREATE) + { + if (mptIssuancesCreated_ == 0) + { + JLOG(j.fatal()) << "Invariant failed: MPT issuance creation " + "succeeded without creating a MPT issuance"; + } + else if (mptIssuancesDeleted_ != 0) + { + JLOG(j.fatal()) << "Invariant failed: MPT issuance creation " + "succeeded while removing MPT issuances"; + } + else if (mptIssuancesCreated_ > 1) + { + JLOG(j.fatal()) << "Invariant failed: MPT issuance creation " + "succeeded but created multiple issuances"; + } + + return mptIssuancesCreated_ == 1 && mptIssuancesDeleted_ == 0; + } + + if (tx.getTxnType() == ttMPTOKEN_ISSUANCE_DESTROY) + { + if (mptIssuancesDeleted_ == 0) + { + JLOG(j.fatal()) << "Invariant failed: MPT issuance deletion " + "succeeded without removing a MPT issuance"; + } + else if (mptIssuancesCreated_ > 0) + { + JLOG(j.fatal()) << "Invariant failed: MPT issuance deletion " + "succeeded while creating MPT issuances"; + } + else if (mptIssuancesDeleted_ > 1) + { + JLOG(j.fatal()) << "Invariant failed: MPT issuance deletion " + "succeeded but deleted multiple issuances"; + } + + return mptIssuancesCreated_ == 0 && mptIssuancesDeleted_ == 1; + } + + if (tx.getTxnType() == ttMPTOKEN_AUTHORIZE) + { + bool const submittedByIssuer = tx.isFieldPresent(sfHolder); + + if (mptIssuancesCreated_ > 0) + { + JLOG(j.fatal()) << "Invariant failed: MPT authorize " + "succeeded but created MPT issuances"; + return false; + } + else if (mptIssuancesDeleted_ > 0) + { + JLOG(j.fatal()) << "Invariant failed: MPT authorize " + "succeeded but deleted issuances"; + return false; + } + else if ( + submittedByIssuer && + (mptokensCreated_ > 0 || mptokensDeleted_ > 0)) + { + JLOG(j.fatal()) + << "Invariant failed: MPT authorize submitted by issuer " + "succeeded but created/deleted mptokens"; + return false; + } + else if ( + !submittedByIssuer && + (mptokensCreated_ + mptokensDeleted_ != 1)) + { + // if the holder submitted this tx, then a mptoken must be + // either created or deleted. + JLOG(j.fatal()) + << "Invariant failed: MPT authorize submitted by holder " + "succeeded but created/deleted bad number of mptokens"; + return false; + } + + return true; + } + + if (tx.getTxnType() == ttMPTOKEN_ISSUANCE_SET) + { + if (mptIssuancesDeleted_ > 0) + { + JLOG(j.fatal()) << "Invariant failed: MPT issuance set " + "succeeded while removing MPT issuances"; + } + else if (mptIssuancesCreated_ > 0) + { + JLOG(j.fatal()) << "Invariant failed: MPT issuance set " + "succeeded while creating MPT issuances"; + } + else if (mptokensDeleted_ > 0) + { + JLOG(j.fatal()) << "Invariant failed: MPT issuance set " + "succeeded while removing MPTokens"; + } + else if (mptokensCreated_ > 0) + { + JLOG(j.fatal()) << "Invariant failed: MPT issuance set " + "succeeded while creating MPTokens"; + } + + return mptIssuancesCreated_ == 0 && mptIssuancesDeleted_ == 0 && + mptokensCreated_ == 0 && mptokensDeleted_ == 0; + } + } + + if (mptIssuancesCreated_ != 0) + { + JLOG(j.fatal()) << "Invariant failed: a MPT issuance was created"; + } + else if (mptIssuancesDeleted_ != 0) + { + JLOG(j.fatal()) << "Invariant failed: a MPT issuance was deleted"; + } + else if (mptokensCreated_ != 0) + { + JLOG(j.fatal()) << "Invariant failed: a MPToken was created"; + } + else if (mptokensDeleted_ != 0) + { + JLOG(j.fatal()) << "Invariant failed: a MPToken was deleted"; + } + + return mptIssuancesCreated_ == 0 && mptIssuancesDeleted_ == 0 && + mptokensCreated_ == 0 && mptokensDeleted_ == 0; +} + } // namespace ripple diff --git a/src/xrpld/app/tx/detail/InvariantCheck.h b/src/xrpld/app/tx/detail/InvariantCheck.h index 1b3234bae69..23ec8005556 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.h +++ b/src/xrpld/app/tx/detail/InvariantCheck.h @@ -433,6 +433,31 @@ class NFTokenCountTracking class ValidClawback { std::uint32_t trustlinesChanged = 0; + std::uint32_t mptokensChanged = 0; + +public: + void + visitEntry( + bool, + std::shared_ptr const&, + std::shared_ptr const&); + + bool + finalize( + STTx const&, + TER const, + XRPAmount const, + ReadView const&, + beast::Journal const&); +}; + +class ValidMPTIssuance +{ + std::uint32_t mptIssuancesCreated_ = 0; + std::uint32_t mptIssuancesDeleted_ = 0; + + std::uint32_t mptokensCreated_ = 0; + std::uint32_t mptokensDeleted_ = 0; public: void @@ -465,7 +490,8 @@ using InvariantChecks = std::tuple< ValidNewAccountRoot, ValidNFTokenPage, NFTokenCountTracking, - ValidClawback>; + ValidClawback, + ValidMPTIssuance>; /** * @brief get a tuple of all invariant checks diff --git a/src/xrpld/app/tx/detail/MPTokenAuthorize.cpp b/src/xrpld/app/tx/detail/MPTokenAuthorize.cpp new file mode 100644 index 00000000000..8042c9c6982 --- /dev/null +++ b/src/xrpld/app/tx/detail/MPTokenAuthorize.cpp @@ -0,0 +1,267 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 +#include +#include +#include +#include + +namespace ripple { + +NotTEC +MPTokenAuthorize::preflight(PreflightContext const& ctx) +{ + if (!ctx.rules.enabled(featureMPTokensV1)) + return temDISABLED; + + if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) + return ret; + + if (ctx.tx.getFlags() & tfMPTokenAuthorizeMask) + return temINVALID_FLAG; + + if (ctx.tx[sfAccount] == ctx.tx[~sfHolder]) + return temMALFORMED; + + return preflight2(ctx); +} + +TER +MPTokenAuthorize::preclaim(PreclaimContext const& ctx) +{ + auto const accountID = ctx.tx[sfAccount]; + auto const holderID = ctx.tx[~sfHolder]; + + // if non-issuer account submits this tx, then they are trying either: + // 1. Unauthorize/delete MPToken + // 2. Use/create MPToken + // + // Note: `accountID` is holder's account + // `holderID` is NOT used + if (!holderID) + { + std::shared_ptr sleMpt = ctx.view.read( + keylet::mptoken(ctx.tx[sfMPTokenIssuanceID], accountID)); + + // There is an edge case where all holders have zero balance, issuance + // is legally destroyed, then outstanding MPT(s) are deleted afterwards. + // Thus, there is no need to check for the existence of the issuance if + // the MPT is being deleted with a zero balance. Check for unauthorize + // before fetching the MPTIssuance object. + + // if holder wants to delete/unauthorize a mpt + if (ctx.tx.getFlags() & tfMPTUnauthorize) + { + if (!sleMpt) + return tecOBJECT_NOT_FOUND; + + if ((*sleMpt)[sfMPTAmount] != 0) + { + auto const sleMptIssuance = ctx.view.read( + keylet::mptIssuance(ctx.tx[sfMPTokenIssuanceID])); + if (!sleMptIssuance) + return tefINTERNAL; + + return tecHAS_OBLIGATIONS; + } + + return tesSUCCESS; + } + + // Now test when the holder wants to hold/create/authorize a new MPT + auto const sleMptIssuance = + ctx.view.read(keylet::mptIssuance(ctx.tx[sfMPTokenIssuanceID])); + + if (!sleMptIssuance) + return tecOBJECT_NOT_FOUND; + + if (accountID == (*sleMptIssuance)[sfIssuer]) + return tecNO_PERMISSION; + + // if holder wants to use and create a mpt + if (sleMpt) + return tecDUPLICATE; + + return tesSUCCESS; + } + + if (!ctx.view.exists(keylet::account(*holderID))) + return tecNO_DST; + + auto const sleMptIssuance = + ctx.view.read(keylet::mptIssuance(ctx.tx[sfMPTokenIssuanceID])); + if (!sleMptIssuance) + return tecOBJECT_NOT_FOUND; + + std::uint32_t const mptIssuanceFlags = sleMptIssuance->getFieldU32(sfFlags); + + // If tx is submitted by issuer, they would either try to do the following + // for allowlisting: + // 1. authorize an account + // 2. unauthorize an account + // + // Note: `accountID` is issuer's account + // `holderID` is holder's account + if (accountID != (*sleMptIssuance)[sfIssuer]) + return tecNO_PERMISSION; + + // If tx is submitted by issuer, it only applies for MPT with + // lsfMPTRequireAuth set + if (!(mptIssuanceFlags & lsfMPTRequireAuth)) + return tecNO_AUTH; + + // The holder must create the MPT before the issuer can authorize it. + if (!ctx.view.exists( + keylet::mptoken(ctx.tx[sfMPTokenIssuanceID], *holderID))) + return tecOBJECT_NOT_FOUND; + + return tesSUCCESS; +} + +TER +MPTokenAuthorize::authorize( + ApplyView& view, + beast::Journal journal, + MPTAuthorizeArgs const& args) +{ + auto const sleAcct = view.peek(keylet::account(args.account)); + if (!sleAcct) + return tecINTERNAL; + + // If the account that submitted the tx is a holder + // Note: `account_` is holder's account + // `holderID` is NOT used + if (!args.holderID) + { + // When a holder wants to unauthorize/delete a MPT, the ledger must + // - delete mptokenKey from owner directory + // - delete the MPToken + if (args.flags & tfMPTUnauthorize) + { + auto const mptokenKey = + keylet::mptoken(args.mptIssuanceID, args.account); + auto const sleMpt = view.peek(mptokenKey); + if (!sleMpt || (*sleMpt)[sfMPTAmount] != 0) + return tecINTERNAL; + + if (!view.dirRemove( + keylet::ownerDir(args.account), + (*sleMpt)[sfOwnerNode], + sleMpt->key(), + false)) + return tecINTERNAL; + + adjustOwnerCount(view, sleAcct, -1, journal); + + view.erase(sleMpt); + return tesSUCCESS; + } + + // A potential holder wants to authorize/hold a mpt, the ledger must: + // - add the new mptokenKey to the owner directory + // - create the MPToken object for the holder + + // The reserve that is required to create the MPToken. Note + // that although the reserve increases with every item + // an account owns, in the case of MPTokens we only + // *enforce* a reserve if the user owns more than two + // items. This is similar to the reserve requirements of trust lines. + std::uint32_t const uOwnerCount = sleAcct->getFieldU32(sfOwnerCount); + XRPAmount const reserveCreate( + (uOwnerCount < 2) ? XRPAmount(beast::zero) + : view.fees().accountReserve(uOwnerCount + 1)); + + if (args.priorBalance < reserveCreate) + return tecINSUFFICIENT_RESERVE; + + auto const mptokenKey = + keylet::mptoken(args.mptIssuanceID, args.account); + + auto const ownerNode = view.dirInsert( + keylet::ownerDir(args.account), + mptokenKey, + describeOwnerDir(args.account)); + + if (!ownerNode) + return tecDIR_FULL; + + auto mptoken = std::make_shared(mptokenKey); + (*mptoken)[sfAccount] = args.account; + (*mptoken)[sfMPTokenIssuanceID] = args.mptIssuanceID; + (*mptoken)[sfFlags] = 0; + (*mptoken)[sfOwnerNode] = *ownerNode; + view.insert(mptoken); + + // Update owner count. + adjustOwnerCount(view, sleAcct, 1, journal); + + return tesSUCCESS; + } + + auto const sleMptIssuance = + view.read(keylet::mptIssuance(args.mptIssuanceID)); + if (!sleMptIssuance) + return tecINTERNAL; + + // If the account that submitted this tx is the issuer of the MPT + // Note: `account_` is issuer's account + // `holderID` is holder's account + if (args.account != (*sleMptIssuance)[sfIssuer]) + return tecINTERNAL; + + auto const sleMpt = + view.peek(keylet::mptoken(args.mptIssuanceID, *args.holderID)); + if (!sleMpt) + return tecINTERNAL; + + std::uint32_t const flagsIn = sleMpt->getFieldU32(sfFlags); + std::uint32_t flagsOut = flagsIn; + + // Issuer wants to unauthorize the holder, unset lsfMPTAuthorized on + // their MPToken + if (args.flags & tfMPTUnauthorize) + flagsOut &= ~lsfMPTAuthorized; + // Issuer wants to authorize a holder, set lsfMPTAuthorized on their + // MPToken + else + flagsOut |= lsfMPTAuthorized; + + if (flagsIn != flagsOut) + sleMpt->setFieldU32(sfFlags, flagsOut); + + view.update(sleMpt); + return tesSUCCESS; +} + +TER +MPTokenAuthorize::doApply() +{ + auto const& tx = ctx_.tx; + return authorize( + ctx_.view(), + ctx_.journal, + {.priorBalance = mPriorBalance, + .mptIssuanceID = tx[sfMPTokenIssuanceID], + .account = account_, + .flags = tx.getFlags(), + .holderID = tx[~sfHolder]}); +} + +} // namespace ripple diff --git a/src/xrpld/app/tx/detail/MPTokenAuthorize.h b/src/xrpld/app/tx/detail/MPTokenAuthorize.h new file mode 100644 index 00000000000..79dc1734b5b --- /dev/null +++ b/src/xrpld/app/tx/detail/MPTokenAuthorize.h @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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_TX_MPTOKENAUTHORIZE_H_INCLUDED +#define RIPPLE_TX_MPTOKENAUTHORIZE_H_INCLUDED + +#include + +namespace ripple { + +struct MPTAuthorizeArgs +{ + XRPAmount const& priorBalance; + uint192 const& mptIssuanceID; + AccountID const& account; + std::uint32_t flags; + std::optional holderID; +}; + +class MPTokenAuthorize : public Transactor +{ +public: + static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; + + explicit MPTokenAuthorize(ApplyContext& ctx) : Transactor(ctx) + { + } + + static NotTEC + preflight(PreflightContext const& ctx); + + static TER + preclaim(PreclaimContext const& ctx); + + static TER + authorize( + ApplyView& view, + beast::Journal journal, + MPTAuthorizeArgs const& args); + + TER + doApply() override; +}; + +} // namespace ripple + +#endif diff --git a/src/xrpld/app/tx/detail/MPTokenIssuanceCreate.cpp b/src/xrpld/app/tx/detail/MPTokenIssuanceCreate.cpp new file mode 100644 index 00000000000..1297a918e1d --- /dev/null +++ b/src/xrpld/app/tx/detail/MPTokenIssuanceCreate.cpp @@ -0,0 +1,142 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 +#include +#include +#include +#include + +namespace ripple { + +NotTEC +MPTokenIssuanceCreate::preflight(PreflightContext const& ctx) +{ + if (!ctx.rules.enabled(featureMPTokensV1)) + return temDISABLED; + + if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) + return ret; + + if (ctx.tx.getFlags() & tfMPTokenIssuanceCreateMask) + return temINVALID_FLAG; + + if (auto const fee = ctx.tx[~sfTransferFee]) + { + if (fee > maxTransferFee) + return temBAD_TRANSFER_FEE; + + // If a non-zero TransferFee is set then the tfTransferable flag + // must also be set. + if (fee > 0u && !ctx.tx.isFlag(tfMPTCanTransfer)) + return temMALFORMED; + } + + if (auto const metadata = ctx.tx[~sfMPTokenMetadata]) + { + if (metadata->length() == 0 || + metadata->length() > maxMPTokenMetadataLength) + return temMALFORMED; + } + + // Check if maximumAmount is within unsigned 63 bit range + if (auto const maxAmt = ctx.tx[~sfMaximumAmount]) + { + if (maxAmt == 0) + return temMALFORMED; + + if (maxAmt > maxMPTokenAmount) + return temMALFORMED; + } + return preflight2(ctx); +} + +TER +MPTokenIssuanceCreate::create( + ApplyView& view, + beast::Journal journal, + MPTCreateArgs const& args) +{ + auto const acct = view.peek(keylet::account(args.account)); + if (!acct) + return tecINTERNAL; + + if (args.priorBalance < + view.fees().accountReserve((*acct)[sfOwnerCount] + 1)) + return tecINSUFFICIENT_RESERVE; + + auto const mptIssuanceKeylet = + keylet::mptIssuance(args.sequence, args.account); + + // create the MPTokenIssuance + { + auto const ownerNode = view.dirInsert( + keylet::ownerDir(args.account), + mptIssuanceKeylet, + describeOwnerDir(args.account)); + + if (!ownerNode) + return tecDIR_FULL; + + auto mptIssuance = std::make_shared(mptIssuanceKeylet); + (*mptIssuance)[sfFlags] = args.flags & ~tfUniversal; + (*mptIssuance)[sfIssuer] = args.account; + (*mptIssuance)[sfOutstandingAmount] = 0; + (*mptIssuance)[sfOwnerNode] = *ownerNode; + (*mptIssuance)[sfSequence] = args.sequence; + + if (args.maxAmount) + (*mptIssuance)[sfMaximumAmount] = *args.maxAmount; + + if (args.assetScale) + (*mptIssuance)[sfAssetScale] = *args.assetScale; + + if (args.transferFee) + (*mptIssuance)[sfTransferFee] = *args.transferFee; + + if (args.metadata) + (*mptIssuance)[sfMPTokenMetadata] = *args.metadata; + + view.insert(mptIssuance); + } + + // Update owner count. + adjustOwnerCount(view, acct, 1, journal); + + return tesSUCCESS; +} + +TER +MPTokenIssuanceCreate::doApply() +{ + auto const& tx = ctx_.tx; + return create( + ctx_.view(), + ctx_.journal, + {.priorBalance = mPriorBalance, + .account = account_, + .sequence = tx.getSeqProxy().value(), + .flags = tx.getFlags(), + .maxAmount = tx[~sfMaximumAmount], + .assetScale = tx[~sfAssetScale], + .transferFee = tx[~sfTransferFee], + .metadata = tx[~sfMPTokenMetadata]}); +} + +} // namespace ripple diff --git a/src/xrpld/app/tx/detail/MPTokenIssuanceCreate.h b/src/xrpld/app/tx/detail/MPTokenIssuanceCreate.h new file mode 100644 index 00000000000..1346c3e31d7 --- /dev/null +++ b/src/xrpld/app/tx/detail/MPTokenIssuanceCreate.h @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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_TX_MPTOKENISSUANCECREATE_H_INCLUDED +#define RIPPLE_TX_MPTOKENISSUANCECREATE_H_INCLUDED + +#include + +namespace ripple { + +struct MPTCreateArgs +{ + XRPAmount const& priorBalance; + AccountID const& account; + std::uint32_t sequence; + std::uint32_t flags; + std::optional maxAmount; + std::optional assetScale; + std::optional transferFee; + std::optional const& metadata; +}; + +class MPTokenIssuanceCreate : public Transactor +{ +public: + static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; + + explicit MPTokenIssuanceCreate(ApplyContext& ctx) : Transactor(ctx) + { + } + + static NotTEC + preflight(PreflightContext const& ctx); + + TER + doApply() override; + + static TER + create(ApplyView& view, beast::Journal journal, MPTCreateArgs const& args); +}; + +} // namespace ripple + +#endif diff --git a/src/xrpld/app/tx/detail/MPTokenIssuanceDestroy.cpp b/src/xrpld/app/tx/detail/MPTokenIssuanceDestroy.cpp new file mode 100644 index 00000000000..a0f0b9d8602 --- /dev/null +++ b/src/xrpld/app/tx/detail/MPTokenIssuanceDestroy.cpp @@ -0,0 +1,84 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 + +#include +#include +#include +#include + +namespace ripple { + +NotTEC +MPTokenIssuanceDestroy::preflight(PreflightContext const& ctx) +{ + if (!ctx.rules.enabled(featureMPTokensV1)) + return temDISABLED; + + // check flags + if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) + return ret; + + if (ctx.tx.getFlags() & tfMPTokenIssuanceDestroyMask) + return temINVALID_FLAG; + + return preflight2(ctx); +} + +TER +MPTokenIssuanceDestroy::preclaim(PreclaimContext const& ctx) +{ + // ensure that issuance exists + auto const sleMPT = + ctx.view.read(keylet::mptIssuance(ctx.tx[sfMPTokenIssuanceID])); + if (!sleMPT) + return tecOBJECT_NOT_FOUND; + + // ensure it is issued by the tx submitter + if ((*sleMPT)[sfIssuer] != ctx.tx[sfAccount]) + return tecNO_PERMISSION; + + // ensure it has no outstanding balances + if ((*sleMPT)[~sfOutstandingAmount] != 0) + return tecHAS_OBLIGATIONS; + + return tesSUCCESS; +} + +TER +MPTokenIssuanceDestroy::doApply() +{ + auto const mpt = + view().peek(keylet::mptIssuance(ctx_.tx[sfMPTokenIssuanceID])); + if (account_ != mpt->getAccountID(sfIssuer)) + return tecINTERNAL; + + if (!view().dirRemove( + keylet::ownerDir(account_), (*mpt)[sfOwnerNode], mpt->key(), false)) + return tefBAD_LEDGER; + + view().erase(mpt); + + adjustOwnerCount(view(), view().peek(keylet::account(account_)), -1, j_); + + return tesSUCCESS; +} + +} // namespace ripple diff --git a/src/xrpld/app/tx/detail/MPTokenIssuanceDestroy.h b/src/xrpld/app/tx/detail/MPTokenIssuanceDestroy.h new file mode 100644 index 00000000000..69abb99feb0 --- /dev/null +++ b/src/xrpld/app/tx/detail/MPTokenIssuanceDestroy.h @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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_TX_MPTOKENISSUANCEDESTROY_H_INCLUDED +#define RIPPLE_TX_MPTOKENISSUANCEDESTROY_H_INCLUDED + +#include + +namespace ripple { + +class MPTokenIssuanceDestroy : public Transactor +{ +public: + static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; + + explicit MPTokenIssuanceDestroy(ApplyContext& ctx) : Transactor(ctx) + { + } + + static NotTEC + preflight(PreflightContext const& ctx); + + static TER + preclaim(PreclaimContext const& ctx); + + TER + doApply() override; +}; + +} // namespace ripple + +#endif diff --git a/src/xrpld/app/tx/detail/MPTokenIssuanceSet.cpp b/src/xrpld/app/tx/detail/MPTokenIssuanceSet.cpp new file mode 100644 index 00000000000..4e395c30be6 --- /dev/null +++ b/src/xrpld/app/tx/detail/MPTokenIssuanceSet.cpp @@ -0,0 +1,118 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 +#include +#include +#include +#include + +namespace ripple { + +NotTEC +MPTokenIssuanceSet::preflight(PreflightContext const& ctx) +{ + if (!ctx.rules.enabled(featureMPTokensV1)) + return temDISABLED; + + if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) + return ret; + + auto const txFlags = ctx.tx.getFlags(); + + // check flags + if (txFlags & tfMPTokenIssuanceSetMask) + return temINVALID_FLAG; + // fails if both flags are set + else if ((txFlags & tfMPTLock) && (txFlags & tfMPTUnlock)) + return temINVALID_FLAG; + + auto const accountID = ctx.tx[sfAccount]; + auto const holderID = ctx.tx[~sfHolder]; + if (holderID && accountID == holderID) + return temMALFORMED; + + return preflight2(ctx); +} + +TER +MPTokenIssuanceSet::preclaim(PreclaimContext const& ctx) +{ + // ensure that issuance exists + auto const sleMptIssuance = + ctx.view.read(keylet::mptIssuance(ctx.tx[sfMPTokenIssuanceID])); + if (!sleMptIssuance) + return tecOBJECT_NOT_FOUND; + + // if the mpt has disabled locking + if (!((*sleMptIssuance)[sfFlags] & lsfMPTCanLock)) + return tecNO_PERMISSION; + + // ensure it is issued by the tx submitter + if ((*sleMptIssuance)[sfIssuer] != ctx.tx[sfAccount]) + return tecNO_PERMISSION; + + if (auto const holderID = ctx.tx[~sfHolder]) + { + // make sure holder account exists + if (!ctx.view.exists(keylet::account(*holderID))) + return tecNO_DST; + + // the mptoken must exist + if (!ctx.view.exists( + keylet::mptoken(ctx.tx[sfMPTokenIssuanceID], *holderID))) + return tecOBJECT_NOT_FOUND; + } + + return tesSUCCESS; +} + +TER +MPTokenIssuanceSet::doApply() +{ + auto const mptIssuanceID = ctx_.tx[sfMPTokenIssuanceID]; + auto const txFlags = ctx_.tx.getFlags(); + auto const holderID = ctx_.tx[~sfHolder]; + std::shared_ptr sle; + + if (holderID) + sle = view().peek(keylet::mptoken(mptIssuanceID, *holderID)); + else + sle = view().peek(keylet::mptIssuance(mptIssuanceID)); + + if (!sle) + return tecINTERNAL; + + std::uint32_t const flagsIn = sle->getFieldU32(sfFlags); + std::uint32_t flagsOut = flagsIn; + + if (txFlags & tfMPTLock) + flagsOut |= lsfMPTLocked; + else if (txFlags & tfMPTUnlock) + flagsOut &= ~lsfMPTLocked; + + if (flagsIn != flagsOut) + sle->setFieldU32(sfFlags, flagsOut); + + view().update(sle); + + return tesSUCCESS; +} + +} // namespace ripple diff --git a/src/xrpld/app/tx/detail/MPTokenIssuanceSet.h b/src/xrpld/app/tx/detail/MPTokenIssuanceSet.h new file mode 100644 index 00000000000..895be973120 --- /dev/null +++ b/src/xrpld/app/tx/detail/MPTokenIssuanceSet.h @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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_TX_MPTOKENISSUANCESET_H_INCLUDED +#define RIPPLE_TX_MPTOKENISSUANCESET_H_INCLUDED + +#include + +namespace ripple { + +class MPTokenIssuanceSet : public Transactor +{ +public: + static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; + + explicit MPTokenIssuanceSet(ApplyContext& ctx) : Transactor(ctx) + { + } + + static NotTEC + preflight(PreflightContext const& ctx); + + static TER + preclaim(PreclaimContext const& ctx); + + TER + doApply() override; +}; + +} // namespace ripple + +#endif diff --git a/src/xrpld/app/tx/detail/Payment.cpp b/src/xrpld/app/tx/detail/Payment.cpp index 46a76bffc28..25ec119d6ae 100644 --- a/src/xrpld/app/tx/detail/Payment.cpp +++ b/src/xrpld/app/tx/detail/Payment.cpp @@ -19,9 +19,10 @@ #include #include -#include +#include #include #include +#include #include #include #include @@ -43,6 +44,24 @@ Payment::makeTxConsequences(PreflightContext const& ctx) return TxConsequences{ctx.tx, calculateMaxXRPSpend(ctx.tx)}; } +STAmount +getMaxSourceAmount( + AccountID const& account, + STAmount const& dstAmount, + std::optional const& sendMax) +{ + if (sendMax) + return *sendMax; + else if (dstAmount.native() || dstAmount.holds()) + return dstAmount; + else + return STAmount( + Issue{dstAmount.get().currency, account}, + dstAmount.mantissa(), + dstAmount.exponent(), + dstAmount < beast::zero); +} + NotTEC Payment::preflight(PreflightContext const& ctx) { @@ -52,117 +71,127 @@ Payment::preflight(PreflightContext const& ctx) auto& tx = ctx.tx; auto& j = ctx.j; - std::uint32_t const uTxFlags = tx.getFlags(); + STAmount const dstAmount(tx.getFieldAmount(sfAmount)); + bool const mptDirect = dstAmount.holds(); - if (uTxFlags & tfPaymentMask) + if (mptDirect && !ctx.rules.enabled(featureMPTokensV1)) + return temDISABLED; + + std::uint32_t const txFlags = tx.getFlags(); + + std::uint32_t paymentMask = mptDirect ? tfMPTPaymentMask : tfPaymentMask; + + if (txFlags & paymentMask) { JLOG(j.trace()) << "Malformed transaction: " << "Invalid flags set."; return temINVALID_FLAG; } - bool const partialPaymentAllowed = uTxFlags & tfPartialPayment; - bool const limitQuality = uTxFlags & tfLimitQuality; - bool const defaultPathsAllowed = !(uTxFlags & tfNoRippleDirect); - bool const bPaths = tx.isFieldPresent(sfPaths); - bool const bMax = tx.isFieldPresent(sfSendMax); + if (mptDirect && ctx.tx.isFieldPresent(sfPaths)) + return temMALFORMED; - STAmount const saDstAmount(tx.getFieldAmount(sfAmount)); + bool const partialPaymentAllowed = txFlags & tfPartialPayment; + bool const limitQuality = txFlags & tfLimitQuality; + bool const defaultPathsAllowed = !(txFlags & tfNoRippleDirect); + bool const hasPaths = tx.isFieldPresent(sfPaths); + bool const hasMax = tx.isFieldPresent(sfSendMax); + + auto const deliverMin = tx[~sfDeliverMin]; - STAmount maxSourceAmount; auto const account = tx.getAccountID(sfAccount); + STAmount const maxSourceAmount = + getMaxSourceAmount(account, dstAmount, tx[~sfSendMax]); - if (bMax) - maxSourceAmount = tx.getFieldAmount(sfSendMax); - else if (saDstAmount.native()) - maxSourceAmount = saDstAmount; - else - maxSourceAmount = STAmount( - {saDstAmount.getCurrency(), account}, - saDstAmount.mantissa(), - saDstAmount.exponent(), - saDstAmount < beast::zero); + if ((mptDirect && dstAmount.asset() != maxSourceAmount.asset()) || + (!mptDirect && maxSourceAmount.holds())) + { + JLOG(j.trace()) << "Malformed transaction: " + << "inconsistent issues: " << dstAmount.getFullText() + << " " << maxSourceAmount.getFullText() << " " + << deliverMin.value_or(STAmount{}).getFullText(); + return temMALFORMED; + } - auto const& uSrcCurrency = maxSourceAmount.getCurrency(); - auto const& uDstCurrency = saDstAmount.getCurrency(); + auto const& srcAsset = maxSourceAmount.asset(); + auto const& dstAsset = dstAmount.asset(); - // isZero() is XRP. FIX! - bool const bXRPDirect = uSrcCurrency.isZero() && uDstCurrency.isZero(); + bool const xrpDirect = srcAsset.native() && dstAsset.native(); - if (!isLegalNet(saDstAmount) || !isLegalNet(maxSourceAmount)) + if (!isLegalNet(dstAmount) || !isLegalNet(maxSourceAmount)) return temBAD_AMOUNT; - auto const uDstAccountID = tx.getAccountID(sfDestination); + auto const dstAccountID = tx.getAccountID(sfDestination); - if (!uDstAccountID) + if (!dstAccountID) { JLOG(j.trace()) << "Malformed transaction: " << "Payment destination account not specified."; return temDST_NEEDED; } - if (bMax && maxSourceAmount <= beast::zero) + if (hasMax && maxSourceAmount <= beast::zero) { JLOG(j.trace()) << "Malformed transaction: " << "bad max amount: " << maxSourceAmount.getFullText(); return temBAD_AMOUNT; } - if (saDstAmount <= beast::zero) + if (dstAmount <= beast::zero) { - JLOG(j.trace()) << "Malformed transaction: " << "bad dst amount: " - << saDstAmount.getFullText(); + JLOG(j.trace()) << "Malformed transaction: " + << "bad dst amount: " << dstAmount.getFullText(); return temBAD_AMOUNT; } - if (badCurrency() == uSrcCurrency || badCurrency() == uDstCurrency) + if (badCurrency() == srcAsset || badCurrency() == dstAsset) { JLOG(j.trace()) << "Malformed transaction: " << "Bad currency."; return temBAD_CURRENCY; } - if (account == uDstAccountID && uSrcCurrency == uDstCurrency && !bPaths) + if (account == dstAccountID && srcAsset == dstAsset && !hasPaths) { // You're signing yourself a payment. - // If bPaths is true, you might be trying some arbitrage. + // If hasPaths is true, you might be trying some arbitrage. JLOG(j.trace()) << "Malformed transaction: " << "Redundant payment from " << to_string(account) - << " to self without path for " - << to_string(uDstCurrency); + << " to self without path for " << to_string(dstAsset); return temREDUNDANT; } - if (bXRPDirect && bMax) + if (xrpDirect && hasMax) { // Consistent but redundant transaction. JLOG(j.trace()) << "Malformed transaction: " << "SendMax specified for XRP to XRP."; return temBAD_SEND_XRP_MAX; } - if (bXRPDirect && bPaths) + if ((xrpDirect || mptDirect) && hasPaths) { // XRP is sent without paths. JLOG(j.trace()) << "Malformed transaction: " - << "Paths specified for XRP to XRP."; + << "Paths specified for XRP to XRP or MPT to MPT."; return temBAD_SEND_XRP_PATHS; } - if (bXRPDirect && partialPaymentAllowed) + if (xrpDirect && partialPaymentAllowed) { // Consistent but redundant transaction. JLOG(j.trace()) << "Malformed transaction: " << "Partial payment specified for XRP to XRP."; return temBAD_SEND_XRP_PARTIAL; } - if (bXRPDirect && limitQuality) + if ((xrpDirect || mptDirect) && limitQuality) { // Consistent but redundant transaction. - JLOG(j.trace()) << "Malformed transaction: " - << "Limit quality specified for XRP to XRP."; + JLOG(j.trace()) + << "Malformed transaction: " + << "Limit quality specified for XRP to XRP or MPT to MPT."; return temBAD_SEND_XRP_LIMIT; } - if (bXRPDirect && !defaultPathsAllowed) + if ((xrpDirect || mptDirect) && !defaultPathsAllowed) { // Consistent but redundant transaction. - JLOG(j.trace()) << "Malformed transaction: " - << "No ripple direct specified for XRP to XRP."; + JLOG(j.trace()) + << "Malformed transaction: " + << "No ripple direct specified for XRP to XRP or MPT to MPT."; return temBAD_SEND_XRP_NO_DIRECT; } - auto const deliverMin = tx[~sfDeliverMin]; if (deliverMin) { if (!partialPaymentAllowed) @@ -181,7 +210,7 @@ Payment::preflight(PreflightContext const& ctx) << " amount. " << dMin.getFullText(); return temBAD_AMOUNT; } - if (dMin.issue() != saDstAmount.issue()) + if (dMin.asset() != dstAmount.asset()) { JLOG(j.trace()) << "Malformed transaction: Dst issue differs " @@ -189,7 +218,7 @@ Payment::preflight(PreflightContext const& ctx) << jss::DeliverMin.c_str() << ". " << dMin.getFullText(); return temBAD_AMOUNT; } - if (dMin > saDstAmount) + if (dMin > dstAmount) { JLOG(j.trace()) << "Malformed transaction: Dst amount less than " @@ -205,21 +234,21 @@ TER Payment::preclaim(PreclaimContext const& ctx) { // Ripple if source or destination is non-native or if there are paths. - std::uint32_t const uTxFlags = ctx.tx.getFlags(); - bool const partialPaymentAllowed = uTxFlags & tfPartialPayment; - auto const paths = ctx.tx.isFieldPresent(sfPaths); + std::uint32_t const txFlags = ctx.tx.getFlags(); + bool const partialPaymentAllowed = txFlags & tfPartialPayment; + auto const hasPaths = ctx.tx.isFieldPresent(sfPaths); auto const sendMax = ctx.tx[~sfSendMax]; - AccountID const uDstAccountID(ctx.tx[sfDestination]); - STAmount const saDstAmount(ctx.tx[sfAmount]); + AccountID const dstAccountID(ctx.tx[sfDestination]); + STAmount const dstAmount(ctx.tx[sfAmount]); - auto const k = keylet::account(uDstAccountID); + auto const k = keylet::account(dstAccountID); auto const sleDst = ctx.view.read(k); if (!sleDst) { // Destination account does not exist. - if (!saDstAmount.native()) + if (!dstAmount.native()) { JLOG(ctx.j.trace()) << "Delay transaction: Destination account does not exist."; @@ -239,7 +268,7 @@ Payment::preclaim(PreclaimContext const& ctx) // transaction would succeed. return telNO_DST_PARTIAL; } - else if (saDstAmount < STAmount(ctx.view.fees().accountReserve(0))) + else if (dstAmount < STAmount(ctx.view.fees().accountReserve(0))) { // accountReserve is the minimum amount that an account can have. // Reserve is not scaled by load. @@ -269,7 +298,7 @@ Payment::preclaim(PreclaimContext const& ctx) } // Payment with at least one intermediate step and uses transitive balances. - if ((paths || sendMax || !saDstAmount.native()) && ctx.view.open()) + if ((hasPaths || sendMax || !dstAmount.native()) && ctx.view.open()) { STPathSet const& paths = ctx.tx.getFieldPathSet(sfPaths); @@ -291,32 +320,24 @@ Payment::doApply() auto const deliverMin = ctx_.tx[~sfDeliverMin]; // Ripple if source or destination is non-native or if there are paths. - std::uint32_t const uTxFlags = ctx_.tx.getFlags(); - bool const partialPaymentAllowed = uTxFlags & tfPartialPayment; - bool const limitQuality = uTxFlags & tfLimitQuality; - bool const defaultPathsAllowed = !(uTxFlags & tfNoRippleDirect); - auto const paths = ctx_.tx.isFieldPresent(sfPaths); + std::uint32_t const txFlags = ctx_.tx.getFlags(); + bool const partialPaymentAllowed = txFlags & tfPartialPayment; + bool const limitQuality = txFlags & tfLimitQuality; + bool const defaultPathsAllowed = !(txFlags & tfNoRippleDirect); + auto const hasPaths = ctx_.tx.isFieldPresent(sfPaths); auto const sendMax = ctx_.tx[~sfSendMax]; - AccountID const uDstAccountID(ctx_.tx.getAccountID(sfDestination)); - STAmount const saDstAmount(ctx_.tx.getFieldAmount(sfAmount)); - STAmount maxSourceAmount; - if (sendMax) - maxSourceAmount = *sendMax; - else if (saDstAmount.native()) - maxSourceAmount = saDstAmount; - else - maxSourceAmount = STAmount( - {saDstAmount.getCurrency(), account_}, - saDstAmount.mantissa(), - saDstAmount.exponent(), - saDstAmount < beast::zero); + AccountID const dstAccountID(ctx_.tx.getAccountID(sfDestination)); + STAmount const dstAmount(ctx_.tx.getFieldAmount(sfAmount)); + bool const mptDirect = dstAmount.holds(); + STAmount const maxSourceAmount = + getMaxSourceAmount(account_, dstAmount, sendMax); JLOG(j_.trace()) << "maxSourceAmount=" << maxSourceAmount.getFullText() - << " saDstAmount=" << saDstAmount.getFullText(); + << " dstAmount=" << dstAmount.getFullText(); // Open a ledger for editing. - auto const k = keylet::account(uDstAccountID); + auto const k = keylet::account(dstAccountID); SLE::pointer sleDst = view().peek(k); if (!sleDst) @@ -327,7 +348,7 @@ Payment::doApply() // Create the account. sleDst = std::make_shared(k); - sleDst->setAccountID(sfAccount, uDstAccountID); + sleDst->setAccountID(sfAccount, dstAccountID); sleDst->setFieldU32(sfSequence, seqno); view().insert(sleDst); @@ -346,14 +367,15 @@ Payment::doApply() bool const depositPreauth = view().rules().enabled(featureDepositPreauth); - bool const bRipple = paths || sendMax || !saDstAmount.native(); + bool const ripple = + (hasPaths || sendMax || !dstAmount.native()) && !mptDirect; // If the destination has lsfDepositAuth set, then only direct XRP // payments (no intermediate steps) are allowed to the destination. - if (!depositPreauth && bRipple && reqDepositAuth) + if (!depositPreauth && ripple && reqDepositAuth) return tecNO_PERMISSION; - if (bRipple) + if (ripple) { // Ripple payment with at least one intermediate step and uses // transitive balances. @@ -364,10 +386,10 @@ Payment::doApply() // authorization has two ways to get an IOU Payment in: // 1. If Account == Destination, or // 2. If Account is deposit preauthorized by destination. - if (uDstAccountID != account_) + if (dstAccountID != account_) { if (!view().exists( - keylet::depositPreauth(uDstAccountID, account_))) + keylet::depositPreauth(dstAccountID, account_))) return tecNO_PERMISSION; } } @@ -386,8 +408,8 @@ Payment::doApply() rc = path::RippleCalc::rippleCalculate( pv, maxSourceAmount, - saDstAmount, - uDstAccountID, + dstAmount, + dstAccountID, account_, ctx_.tx.getFieldPathSet(sfPaths), ctx_.app.logs(), @@ -400,7 +422,7 @@ Payment::doApply() // TODO: is this right? If the amount is the correct amount, was // the delivered amount previously set? - if (rc.result() == tesSUCCESS && rc.actualAmountOut != saDstAmount) + if (rc.result() == tesSUCCESS && rc.actualAmountOut != dstAmount) { if (deliverMin && rc.actualAmountOut < *deliverMin) rc.setResult(tecPATH_PARTIAL); @@ -418,8 +440,75 @@ Payment::doApply() terResult = tecPATH_DRY; return terResult; } + else if (mptDirect) + { + JLOG(j_.trace()) << " dstAmount=" << dstAmount.getFullText(); + auto const& mptIssue = dstAmount.get(); + + if (auto const ter = requireAuth(view(), mptIssue, account_); + ter != tesSUCCESS) + return ter; + + if (auto const ter = requireAuth(view(), mptIssue, dstAccountID); + ter != tesSUCCESS) + return ter; + + if (auto const ter = + canTransfer(view(), mptIssue, account_, dstAccountID); + ter != tesSUCCESS) + return ter; + + auto const& issuer = mptIssue.getIssuer(); + + // Transfer rate + Rate rate{QUALITY_ONE}; + // Payment between the holders + if (account_ != issuer && dstAccountID != issuer) + { + // If globally/individually locked then + // - can't send between holders + // - holder can send back to issuer + // - issuer can send to holder + if (isFrozen(view(), account_, mptIssue) || + isFrozen(view(), dstAccountID, mptIssue)) + return tecLOCKED; + + // Get the rate for a payment between the holders. + rate = transferRate(view(), mptIssue.getMptID()); + } + + // Amount to deliver. + STAmount amountDeliver = dstAmount; + // Factor in the transfer rate. + // No rounding. It'll change once MPT integrated into DEX. + STAmount requiredMaxSourceAmount = multiply(dstAmount, rate); + + // Send more than the account wants to pay or less than + // the account wants to deliver (if no SendMax). + // Adjust the amount to deliver. + if (partialPaymentAllowed && requiredMaxSourceAmount > maxSourceAmount) + { + requiredMaxSourceAmount = maxSourceAmount; + // No rounding. It'll change once MPT integrated into DEX. + amountDeliver = divide(maxSourceAmount, rate); + } + + if (requiredMaxSourceAmount > maxSourceAmount || + (deliverMin && amountDeliver < *deliverMin)) + return tecPATH_PARTIAL; + + PaymentSandbox pv(&view()); + auto res = accountSend( + pv, account_, dstAccountID, amountDeliver, ctx_.journal); + if (res == tesSUCCESS) + pv.apply(ctx_.rawView()); + else if (res == tecINSUFFICIENT_FUNDS || res == tecPATH_DRY) + res = tecPATH_PARTIAL; + + return res; + } - assert(saDstAmount.native()); + assert(dstAmount.native()); // Direct XRP payment. @@ -427,25 +516,25 @@ Payment::doApply() if (!sleSrc) return tefINTERNAL; - // uOwnerCount is the number of entries in this ledger for this + // ownerCount is the number of entries in this ledger for this // account that require a reserve. - auto const uOwnerCount = sleSrc->getFieldU32(sfOwnerCount); + auto const ownerCount = sleSrc->getFieldU32(sfOwnerCount); // This is the total reserve in drops. - auto const reserve = view().fees().accountReserve(uOwnerCount); + auto const reserve = view().fees().accountReserve(ownerCount); // mPriorBalance is the balance on the sending account BEFORE the // fees were charged. We want to make sure we have enough reserve // to send. Allow final spend to use reserve for fee. auto const mmm = std::max(reserve, ctx_.tx.getFieldAmount(sfFee).xrp()); - if (mPriorBalance < saDstAmount.xrp() + mmm) + if (mPriorBalance < dstAmount.xrp() + mmm) { // Vote no. However the transaction might succeed, if applied in // a different order. - JLOG(j_.trace()) << "Delay transaction: Insufficient funds: " << " " - << to_string(mPriorBalance) << " / " - << to_string(saDstAmount.xrp() + mmm) << " (" + JLOG(j_.trace()) << "Delay transaction: Insufficient funds: " + << " " << to_string(mPriorBalance) << " / " + << to_string(dstAmount.xrp() + mmm) << " (" << to_string(reserve) << ")"; return tecUNFUNDED_PAYMENT; @@ -478,14 +567,14 @@ Payment::doApply() // We choose the base reserve as our bound because it is // a small number that seldom changes but is always sufficient // to get the account un-wedged. - if (uDstAccountID != account_) + if (dstAccountID != account_) { - if (!view().exists(keylet::depositPreauth(uDstAccountID, account_))) + if (!view().exists(keylet::depositPreauth(dstAccountID, account_))) { // Get the base reserve. XRPAmount const dstReserve{view().fees().accountReserve(0)}; - if (saDstAmount > dstReserve || + if (dstAmount > dstReserve || sleDst->getFieldAmount(sfBalance) > dstReserve) return tecNO_PERMISSION; } @@ -493,9 +582,9 @@ Payment::doApply() } // Do the arithmetic for the transfer and make the ledger change. - sleSrc->setFieldAmount(sfBalance, mSourceBalance - saDstAmount); + sleSrc->setFieldAmount(sfBalance, mSourceBalance - dstAmount); sleDst->setFieldAmount( - sfBalance, sleDst->getFieldAmount(sfBalance) + saDstAmount); + sfBalance, sleDst->getFieldAmount(sfBalance) + dstAmount); // Re-arm the password change fee if we can and need to. if ((sleDst->getFlags() & lsfPasswordSpent)) diff --git a/src/xrpld/app/tx/detail/SetTrust.cpp b/src/xrpld/app/tx/detail/SetTrust.cpp index 3a7fe9cca0d..954fc6543f1 100644 --- a/src/xrpld/app/tx/detail/SetTrust.cpp +++ b/src/xrpld/app/tx/detail/SetTrust.cpp @@ -537,7 +537,7 @@ SetTrust::doApply() else { // Zero balance in currency. - STAmount saBalance({currency, noAccount()}); + STAmount saBalance(Issue{currency, noAccount()}); auto const k = keylet::line(account_, uDstAccountID, currency); diff --git a/src/xrpld/app/tx/detail/applySteps.cpp b/src/xrpld/app/tx/detail/applySteps.cpp index f39c61abeac..f59cd73378b 100644 --- a/src/xrpld/app/tx/detail/applySteps.cpp +++ b/src/xrpld/app/tx/detail/applySteps.cpp @@ -39,6 +39,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include diff --git a/src/xrpld/ledger/View.h b/src/xrpld/ledger/View.h index 09f374d2c29..74027752486 100644 --- a/src/xrpld/ledger/View.h +++ b/src/xrpld/ledger/View.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -78,9 +79,18 @@ hasExpired(ReadView const& view, std::optional const& exp); /** Controls the treatment of frozen account balances */ enum FreezeHandling { fhIGNORE_FREEZE, fhZERO_IF_FROZEN }; +/** Controls the treatment of unauthorized MPT balances */ +enum AuthHandling { ahIGNORE_AUTH, ahZERO_IF_UNAUTHORIZED }; + [[nodiscard]] bool isGlobalFrozen(ReadView const& view, AccountID const& issuer); +[[nodiscard]] bool +isGlobalFrozen(ReadView const& view, MPTIssue const& mptIssue); + +[[nodiscard]] bool +isGlobalFrozen(ReadView const& view, Asset const& asset); + [[nodiscard]] bool isIndividualFrozen( ReadView const& view, @@ -97,6 +107,25 @@ isIndividualFrozen( return isIndividualFrozen(view, account, issue.currency, issue.account); } +[[nodiscard]] bool +isIndividualFrozen( + ReadView const& view, + AccountID const& account, + MPTIssue const& mptIssue); + +[[nodiscard]] inline bool +isIndividualFrozen( + ReadView const& view, + AccountID const& account, + Asset const& asset) +{ + return std::visit( + [&](auto const& issue) { + return isIndividualFrozen(view, account, issue); + }, + asset.value()); +} + [[nodiscard]] bool isFrozen( ReadView const& view, @@ -110,6 +139,20 @@ isFrozen(ReadView const& view, AccountID const& account, Issue const& issue) return isFrozen(view, account, issue.currency, issue.account); } +[[nodiscard]] bool +isFrozen( + ReadView const& view, + AccountID const& account, + MPTIssue const& mptIssue); + +[[nodiscard]] inline bool +isFrozen(ReadView const& view, AccountID const& account, Asset const& asset) +{ + return std::visit( + [&](auto const& issue) { return isFrozen(view, account, issue); }, + asset.value()); +} + // Returns the amount an account can spend without going into debt. // // <-- saAmount: amount of currency held by account. May be negative. @@ -130,6 +173,15 @@ accountHolds( FreezeHandling zeroIfFrozen, beast::Journal j); +[[nodiscard]] STAmount +accountHolds( + ReadView const& view, + AccountID const& account, + MPTIssue const& mptIssue, + FreezeHandling zeroIfFrozen, + AuthHandling zeroIfUnauthorized, + beast::Journal j); + // Returns the amount an account can spend of the currency type saDefault, or // returns saDefault if this account is the issuer of the currency in // question. Should be used in favor of accountHolds when questioning how much @@ -206,9 +258,22 @@ forEachItemAfter( return forEachItemAfter(view, keylet::ownerDir(id), after, hint, limit, f); } +/** Returns IOU issuer transfer fee as Rate. Rate specifies + * the fee as fractions of 1 billion. For example, 1% transfer rate + * is represented as 1,010,000,000. + * @param issuer The IOU issuer + */ [[nodiscard]] Rate transferRate(ReadView const& view, AccountID const& issuer); +/** Returns MPT transfer fee as Rate. Rate specifies + * the fee as fractions of 1 billion. For example, 1% transfer rate + * is represented as 1,010,000,000. + * @param issuanceID MPTokenIssuanceID of MPTTokenIssuance object + */ +[[nodiscard]] Rate +transferRate(ReadView const& view, MPTID const& issuanceID); + /** Returns `true` if the directory is empty @param key The key of the directory */ @@ -410,21 +475,28 @@ offerDelete(ApplyView& view, std::shared_ptr const& sle, beast::Journal j); // - Create trust line of needed. // --> bCheckIssuer : normally require issuer to be involved. // [[nodiscard]] // nodiscard commented out so DirectStep.cpp compiles. + +/** Calls static rippleCreditIOU if saAmount represents Issue. + * Calls static rippleCreditMPT if saAmount represents MPTIssue. + */ TER rippleCredit( ApplyView& view, AccountID const& uSenderID, AccountID const& uReceiverID, - const STAmount& saAmount, + STAmount const& saAmount, bool bCheckIssuer, beast::Journal j); +/** Calls static accountSendIOU if saAmount represents Issue. + * Calls static accountSendMPT if saAmount represents MPTIssue. + */ [[nodiscard]] TER accountSend( ApplyView& view, AccountID const& from, AccountID const& to, - const STAmount& saAmount, + STAmount const& saAmount, beast::Journal j, WaiveTransferFee waiveFee = WaiveTransferFee::No); @@ -452,12 +524,28 @@ transferXRP( STAmount const& amount, beast::Journal j); -/** Check if the account requires authorization. +/** Check if the account lacks required authorization. * Return tecNO_AUTH or tecNO_LINE if it does * and tesSUCCESS otherwise. */ [[nodiscard]] TER requireAuth(ReadView const& view, Issue const& issue, AccountID const& account); +[[nodiscard]] TER +requireAuth( + ReadView const& view, + MPTIssue const& mptIssue, + AccountID const& account); + +/** Check if the destination account is allowed + * to receive MPT. Return tecNO_AUTH if it doesn't + * and tesSUCCESS otherwise. + */ +[[nodiscard]] TER +canTransfer( + ReadView const& view, + MPTIssue const& mptIssue, + AccountID const& from, + AccountID const& to); /** Deleter function prototype. Returns the status of the entry deletion * (if should not be skipped) and if the entry should be skipped. The status diff --git a/src/xrpld/ledger/detail/View.cpp b/src/xrpld/ledger/detail/View.cpp index 55baeadff66..ae4eb095017 100644 --- a/src/xrpld/ledger/detail/View.cpp +++ b/src/xrpld/ledger/detail/View.cpp @@ -177,6 +177,27 @@ isGlobalFrozen(ReadView const& view, AccountID const& issuer) return false; } +bool +isGlobalFrozen(ReadView const& view, MPTIssue const& mptIssue) +{ + if (auto const sle = view.read(keylet::mptIssuance(mptIssue.getMptID()))) + return sle->getFlags() & lsfMPTLocked; + return false; +} + +bool +isGlobalFrozen(ReadView const& view, Asset const& asset) +{ + return std::visit( + [&](TIss const& issue) { + if constexpr (std::is_same_v) + return isGlobalFrozen(view, issue.getIssuer()); + else + return isGlobalFrozen(view, issue); + }, + asset.value()); +} + bool isIndividualFrozen( ReadView const& view, @@ -197,6 +218,18 @@ isIndividualFrozen( return false; } +bool +isIndividualFrozen( + ReadView const& view, + AccountID const& account, + MPTIssue const& mptIssue) +{ + if (auto const sle = + view.read(keylet::mptoken(mptIssue.getMptID(), account))) + return sle->getFlags() & lsfMPTLocked; + return false; +} + // Can the specified account spend the specified currency issued by // the specified issuer or does the freeze flag prohibit it? bool @@ -222,6 +255,16 @@ isFrozen( return false; } +bool +isFrozen( + ReadView const& view, + AccountID const& account, + MPTIssue const& mptIssue) +{ + return isGlobalFrozen(view, mptIssue) || + isIndividualFrozen(view, account, mptIssue); +} + STAmount accountHolds( ReadView const& view, @@ -241,13 +284,13 @@ accountHolds( auto const sle = view.read(keylet::line(account, issuer, currency)); if (!sle) { - amount.clear({currency, issuer}); + amount.clear(Issue{currency, issuer}); } else if ( (zeroIfFrozen == fhZERO_IF_FROZEN) && isFrozen(view, account, currency, issuer)) { - amount.clear(Issue(currency, issuer)); + amount.clear(Issue{currency, issuer}); } else { @@ -277,6 +320,46 @@ accountHolds( view, account, issue.currency, issue.account, zeroIfFrozen, j); } +STAmount +accountHolds( + ReadView const& view, + AccountID const& account, + MPTIssue const& mptIssue, + FreezeHandling zeroIfFrozen, + AuthHandling zeroIfUnauthorized, + beast::Journal j) +{ + STAmount amount; + + auto const sleMpt = + view.read(keylet::mptoken(mptIssue.getMptID(), account)); + if (!sleMpt) + amount.clear(mptIssue); + else if ( + zeroIfFrozen == fhZERO_IF_FROZEN && isFrozen(view, account, mptIssue)) + amount.clear(mptIssue); + else + { + amount = STAmount{mptIssue, sleMpt->getFieldU64(sfMPTAmount)}; + + // only if auth check is needed, as it needs to do an additional read + // operation + if (zeroIfUnauthorized == ahZERO_IF_UNAUTHORIZED) + { + auto const sleIssuance = + view.read(keylet::mptIssuance(mptIssue.getMptID())); + + // if auth is enabled on the issuance and mpt is not authorized, + // clear amount + if (sleIssuance && sleIssuance->isFlag(lsfMPTRequireAuth) && + !sleMpt->isFlag(lsfMPTAuthorized)) + amount.clear(mptIssue); + } + } + + return amount; +} + STAmount accountFunds( ReadView const& view, @@ -493,6 +576,19 @@ transferRate(ReadView const& view, AccountID const& issuer) return parityRate; } +Rate +transferRate(ReadView const& view, MPTID const& issuanceID) +{ + // fee is 0-50,000 (0-50%), rate is 1,000,000,000-2,000,000,000 + // For example, if transfer fee is 50% then 10,000 * 50,000 = 500,000 + // which represents 50% of 1,000,000,000 + if (auto const sle = view.read(keylet::mptIssuance(issuanceID)); + sle && sle->isFieldPresent(sfTransferFee)) + return Rate{1'000'000'000u + 10'000 * sle->getFieldU16(sfTransferFee)}; + + return parityRate; +} + bool areCompatible( ReadView const& validLedger, @@ -818,9 +914,8 @@ trustCreate( bSetHigh ? sfHighLimit : sfLowLimit, saLimit); sleRippleState->setFieldAmount( bSetHigh ? sfLowLimit : sfHighLimit, - STAmount( - {saBalance.getCurrency(), - bSetDst ? uSrcAccountID : uDstAccountID})); + STAmount(Issue{ + saBalance.getCurrency(), bSetDst ? uSrcAccountID : uDstAccountID})); if (uQualityIn) sleRippleState->setFieldU32( @@ -944,8 +1039,8 @@ offerDelete(ApplyView& view, std::shared_ptr const& sle, beast::Journal j) // - Redeeming IOUs and/or sending sender's own IOUs. // - Create trust line if needed. // --> bCheckIssuer : normally require issuer to be involved. -TER -rippleCredit( +static TER +rippleCreditIOU( ApplyView& view, AccountID const& uSenderID, AccountID const& uReceiverID, @@ -983,7 +1078,7 @@ rippleCredit( saBalance -= saAmount; - JLOG(j.trace()) << "rippleCredit: " << to_string(uSenderID) << " -> " + JLOG(j.trace()) << "rippleCreditIOU: " << to_string(uSenderID) << " -> " << to_string(uReceiverID) << " : before=" << saBefore.getFullText() << " amount=" << saAmount.getFullText() @@ -1053,12 +1148,12 @@ rippleCredit( return tesSUCCESS; } - STAmount const saReceiverLimit({currency, uReceiverID}); + STAmount const saReceiverLimit(Issue{currency, uReceiverID}); STAmount saBalance{saAmount}; saBalance.setIssuer(noAccount()); - JLOG(j.debug()) << "rippleCredit: " + JLOG(j.debug()) << "rippleCreditIOU: " "create line: " << to_string(uSenderID) << " -> " << to_string(uReceiverID) << " : " << saAmount.getFullText(); @@ -1090,7 +1185,7 @@ rippleCredit( // --> saAmount: Amount/currency/issuer to deliver to receiver. // <-- saActual: Amount actually cost. Sender pays fees. static TER -rippleSend( +rippleSendIOU( ApplyView& view, AccountID const& uSenderID, AccountID const& uReceiverID, @@ -1108,7 +1203,7 @@ rippleSend( { // Direct send: redeeming IOUs and/or sending own IOUs. auto const ter = - rippleCredit(view, uSenderID, uReceiverID, saAmount, false, j); + rippleCreditIOU(view, uSenderID, uReceiverID, saAmount, false, j); if (view.rules().enabled(featureDeletableAccounts) && ter != tesSUCCESS) return ter; saActual = saAmount; @@ -1123,21 +1218,22 @@ rippleSend( ? saAmount : multiply(saAmount, transferRate(view, issuer)); - JLOG(j.debug()) << "rippleSend> " << to_string(uSenderID) << " - > " + JLOG(j.debug()) << "rippleSendIOU> " << to_string(uSenderID) << " - > " << to_string(uReceiverID) << " : deliver=" << saAmount.getFullText() << " cost=" << saActual.getFullText(); - TER terResult = rippleCredit(view, issuer, uReceiverID, saAmount, true, j); + TER terResult = + rippleCreditIOU(view, issuer, uReceiverID, saAmount, true, j); if (tesSUCCESS == terResult) - terResult = rippleCredit(view, uSenderID, issuer, saActual, true, j); + terResult = rippleCreditIOU(view, uSenderID, issuer, saActual, true, j); return terResult; } -TER -accountSend( +static TER +accountSendIOU( ApplyView& view, AccountID const& uSenderID, AccountID const& uReceiverID, @@ -1147,14 +1243,14 @@ accountSend( { if (view.rules().enabled(fixAMMv1_1)) { - if (saAmount < beast::zero) + if (saAmount < beast::zero || saAmount.holds()) { return tecINTERNAL; } } else { - assert(saAmount >= beast::zero); + assert(saAmount >= beast::zero && !saAmount.holds()); } /* If we aren't sending anything or if the sender is the same as the @@ -1167,11 +1263,11 @@ accountSend( { STAmount saActual; - JLOG(j.trace()) << "accountSend: " << to_string(uSenderID) << " -> " + JLOG(j.trace()) << "accountSendIOU: " << to_string(uSenderID) << " -> " << to_string(uReceiverID) << " : " << saAmount.getFullText(); - return rippleSend( + return rippleSendIOU( view, uSenderID, uReceiverID, saAmount, saActual, j, waiveFee); } @@ -1200,9 +1296,9 @@ accountSend( if (receiver) receiver_bal = receiver->getFieldAmount(sfBalance).getFullText(); - stream << "accountSend> " << to_string(uSenderID) << " (" << sender_bal - << ") -> " << to_string(uReceiverID) << " (" << receiver_bal - << ") : " << saAmount.getFullText(); + stream << "accountSendIOU> " << to_string(uSenderID) << " (" + << sender_bal << ") -> " << to_string(uReceiverID) << " (" + << receiver_bal << ") : " << saAmount.getFullText(); } if (sender) @@ -1246,14 +1342,182 @@ accountSend( if (receiver) receiver_bal = receiver->getFieldAmount(sfBalance).getFullText(); - stream << "accountSend< " << to_string(uSenderID) << " (" << sender_bal - << ") -> " << to_string(uReceiverID) << " (" << receiver_bal - << ") : " << saAmount.getFullText(); + stream << "accountSendIOU< " << to_string(uSenderID) << " (" + << sender_bal << ") -> " << to_string(uReceiverID) << " (" + << receiver_bal << ") : " << saAmount.getFullText(); } return terResult; } +static TER +rippleCreditMPT( + ApplyView& view, + AccountID const& uSenderID, + AccountID const& uReceiverID, + STAmount const& saAmount, + beast::Journal j) +{ + auto const mptID = keylet::mptIssuance(saAmount.get().getMptID()); + auto const issuer = saAmount.getIssuer(); + auto sleIssuance = view.peek(mptID); + if (!sleIssuance) + return tecOBJECT_NOT_FOUND; + if (uSenderID == issuer) + { + (*sleIssuance)[sfOutstandingAmount] += saAmount.mpt().value(); + view.update(sleIssuance); + } + else + { + auto const mptokenID = keylet::mptoken(mptID.key, uSenderID); + if (auto sle = view.peek(mptokenID)) + { + auto const amt = sle->getFieldU64(sfMPTAmount); + auto const pay = saAmount.mpt().value(); + if (amt < pay) + return tecINSUFFICIENT_FUNDS; + (*sle)[sfMPTAmount] = amt - pay; + view.update(sle); + } + else + return tecNO_AUTH; + } + + if (uReceiverID == issuer) + { + auto const outstanding = sleIssuance->getFieldU64(sfOutstandingAmount); + auto const redeem = saAmount.mpt().value(); + if (outstanding >= redeem) + { + sleIssuance->setFieldU64(sfOutstandingAmount, outstanding - redeem); + view.update(sleIssuance); + } + else + return tecINTERNAL; + } + else + { + auto const mptokenID = keylet::mptoken(mptID.key, uReceiverID); + if (auto sle = view.peek(mptokenID)) + { + (*sle)[sfMPTAmount] += saAmount.mpt().value(); + view.update(sle); + } + else + return tecNO_AUTH; + } + return tesSUCCESS; +} + +static TER +rippleSendMPT( + ApplyView& view, + AccountID const& uSenderID, + AccountID const& uReceiverID, + STAmount const& saAmount, + STAmount& saActual, + beast::Journal j, + WaiveTransferFee waiveFee) +{ + assert(uSenderID != uReceiverID); + + // Safe to get MPT since rippleSendMPT is only called by accountSendMPT + auto const issuer = saAmount.getIssuer(); + + auto const sle = + view.read(keylet::mptIssuance(saAmount.get().getMptID())); + if (!sle) + return tecOBJECT_NOT_FOUND; + + if (uSenderID == issuer || uReceiverID == issuer) + { + // if sender is issuer, check that the new OutstandingAmount will not + // exceed MaximumAmount + if (uSenderID == issuer) + { + auto const sendAmount = saAmount.mpt().value(); + auto const maximumAmount = + sle->at(~sfMaximumAmount).value_or(maxMPTokenAmount); + if (sendAmount > maximumAmount || + sle->getFieldU64(sfOutstandingAmount) > + maximumAmount - sendAmount) + return tecPATH_DRY; + } + + // Direct send: redeeming MPTs and/or sending own MPTs. + auto const ter = + rippleCreditMPT(view, uSenderID, uReceiverID, saAmount, j); + if (ter != tesSUCCESS) + return ter; + saActual = saAmount; + return tesSUCCESS; + } + + // Sending 3rd party MPTs: transit. + saActual = (waiveFee == WaiveTransferFee::Yes) + ? saAmount + : multiply( + saAmount, + transferRate(view, saAmount.get().getMptID())); + + JLOG(j.debug()) << "rippleSendMPT> " << to_string(uSenderID) << " - > " + << to_string(uReceiverID) + << " : deliver=" << saAmount.getFullText() + << " cost=" << saActual.getFullText(); + + if (auto const terResult = + rippleCreditMPT(view, issuer, uReceiverID, saAmount, j); + terResult != tesSUCCESS) + return terResult; + + return rippleCreditMPT(view, uSenderID, issuer, saActual, j); +} + +static TER +accountSendMPT( + ApplyView& view, + AccountID const& uSenderID, + AccountID const& uReceiverID, + STAmount const& saAmount, + beast::Journal j, + WaiveTransferFee waiveFee) +{ + assert(saAmount >= beast::zero && saAmount.holds()); + + /* If we aren't sending anything or if the sender is the same as the + * receiver then we don't need to do anything. + */ + if (!saAmount || (uSenderID == uReceiverID)) + return tesSUCCESS; + + STAmount saActual{saAmount.asset()}; + + return rippleSendMPT( + view, uSenderID, uReceiverID, saAmount, saActual, j, waiveFee); +} + +TER +accountSend( + ApplyView& view, + AccountID const& uSenderID, + AccountID const& uReceiverID, + STAmount const& saAmount, + beast::Journal j, + WaiveTransferFee waiveFee) +{ + return std::visit( + [&](TIss const& issue) { + if constexpr (std::is_same_v) + return accountSendIOU( + view, uSenderID, uReceiverID, saAmount, j, waiveFee); + else + return accountSendMPT( + view, uSenderID, uReceiverID, saAmount, j, waiveFee); + }, + saAmount.asset().value()); +} + static bool updateTrustLine( ApplyView& view, @@ -1375,7 +1639,7 @@ issueIOU( // NIKB TODO: The limit uses the receiver's account as the issuer and // this is unnecessarily inefficient as copying which could be avoided // is now required. Consider available options. - STAmount const limit({issue.currency, account}); + STAmount const limit(Issue{issue.currency, account}); STAmount final_balance = amount; final_balance.setIssuer(noAccount()); @@ -1535,6 +1799,59 @@ requireAuth(ReadView const& view, Issue const& issue, AccountID const& account) return tesSUCCESS; } +TER +requireAuth( + ReadView const& view, + MPTIssue const& mptIssue, + AccountID const& account) +{ + auto const mptID = keylet::mptIssuance(mptIssue.getMptID()); + auto const sleIssuance = view.read(mptID); + + if (!sleIssuance) + return tecOBJECT_NOT_FOUND; + + auto const mptIssuer = sleIssuance->getAccountID(sfIssuer); + + // issuer is always "authorized" + if (mptIssuer == account) + return tesSUCCESS; + + auto const mptokenID = keylet::mptoken(mptID.key, account); + auto const sleToken = view.read(mptokenID); + + // if account has no MPToken, fail + if (!sleToken) + return tecNO_AUTH; + + // mptoken must be authorized if issuance enabled requireAuth + if (sleIssuance->getFieldU32(sfFlags) & lsfMPTRequireAuth && + !(sleToken->getFlags() & lsfMPTAuthorized)) + return tecNO_AUTH; + + return tesSUCCESS; +} + +TER +canTransfer( + ReadView const& view, + MPTIssue const& mptIssue, + AccountID const& from, + AccountID const& to) +{ + auto const mptID = keylet::mptIssuance(mptIssue.getMptID()); + auto const sleIssuance = view.read(mptID); + if (!sleIssuance) + return tecOBJECT_NOT_FOUND; + + if (!(sleIssuance->getFieldU32(sfFlags) & lsfMPTCanTransfer)) + { + if (from != (*sleIssuance)[sfIssuer] && to != (*sleIssuance)[sfIssuer]) + return TER{tecNO_AUTH}; + } + return tesSUCCESS; +} + TER cleanupOnAccountDelete( ApplyView& view, @@ -1660,4 +1977,30 @@ deleteAMMTrustLine( return tesSUCCESS; } +TER +rippleCredit( + ApplyView& view, + AccountID const& uSenderID, + AccountID const& uReceiverID, + STAmount const& saAmount, + bool bCheckIssuer, + beast::Journal j) +{ + return std::visit( + [&](TIss const& issue) { + if constexpr (std::is_same_v) + { + return rippleCreditIOU( + view, uSenderID, uReceiverID, saAmount, bCheckIssuer, j); + } + else + { + assert(!bCheckIssuer); + return rippleCreditMPT( + view, uSenderID, uReceiverID, saAmount, j); + } + }, + saAmount.asset().value()); +} + } // namespace ripple diff --git a/src/xrpld/rpc/MPTokenIssuanceID.h b/src/xrpld/rpc/MPTokenIssuanceID.h new file mode 100644 index 00000000000..ef194bd398c --- /dev/null +++ b/src/xrpld/rpc/MPTokenIssuanceID.h @@ -0,0 +1,61 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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_RPC_MPTOKENISSUANCEID_H_INCLUDED +#define RIPPLE_RPC_MPTOKENISSUANCEID_H_INCLUDED + +#include +#include +#include +#include + +#include +#include + +namespace ripple { + +namespace RPC { + +/** + Add a `mpt_issuance_id` field to the `meta` input/output parameter. + The field is only added to successful MPTokenIssuanceCreate transactions. + The mpt_issuance_id is parsed from the sequence and the issuer in the + MPTokenIssuance object. + + @{ + */ +bool +canHaveMPTokenIssuanceID( + std::shared_ptr const& serializedTx, + TxMeta const& transactionMeta); + +std::optional +getIDFromCreatedIssuance(TxMeta const& transactionMeta); + +void +insertMPTokenIssuanceID( + Json::Value& response, + std::shared_ptr const& transaction, + TxMeta const& transactionMeta); +/** @} */ + +} // namespace RPC +} // namespace ripple + +#endif diff --git a/src/xrpld/rpc/detail/MPTokenIssuanceID.cpp b/src/xrpld/rpc/detail/MPTokenIssuanceID.cpp new file mode 100644 index 00000000000..721be652622 --- /dev/null +++ b/src/xrpld/rpc/detail/MPTokenIssuanceID.cpp @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 + +#include +#include +#include +#include + +namespace ripple { + +namespace RPC { + +bool +canHaveMPTokenIssuanceID( + std::shared_ptr const& serializedTx, + TxMeta const& transactionMeta) +{ + if (!serializedTx) + return false; + + TxType const tt = serializedTx->getTxnType(); + if (tt != ttMPTOKEN_ISSUANCE_CREATE) + return false; + + // if the transaction failed nothing could have been delivered. + if (transactionMeta.getResultTER() != tesSUCCESS) + return false; + + return true; +} + +std::optional +getIDFromCreatedIssuance(TxMeta const& transactionMeta) +{ + for (STObject const& node : transactionMeta.getNodes()) + { + if (node.getFieldU16(sfLedgerEntryType) != ltMPTOKEN_ISSUANCE || + node.getFName() != sfCreatedNode) + continue; + + auto const& mptNode = + node.peekAtField(sfNewFields).downcast(); + return makeMptID( + mptNode.getFieldU32(sfSequence), mptNode.getAccountID(sfIssuer)); + } + + return std::nullopt; +} + +void +insertMPTokenIssuanceID( + Json::Value& response, + std::shared_ptr const& transaction, + TxMeta const& transactionMeta) +{ + if (!canHaveMPTokenIssuanceID(transaction, transactionMeta)) + return; + + std::optional result = getIDFromCreatedIssuance(transactionMeta); + if (result) + response[jss::mpt_issuance_id] = to_string(result.value()); +} + +} // namespace RPC +} // namespace ripple diff --git a/src/xrpld/rpc/detail/RPCHelpers.cpp b/src/xrpld/rpc/detail/RPCHelpers.cpp index fa66fecfbba..930f8d8a0e5 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.cpp +++ b/src/xrpld/rpc/detail/RPCHelpers.cpp @@ -915,7 +915,7 @@ chooseLedgerEntryType(Json::Value const& params) std::pair result{RPC::Status::OK, ltANY}; if (params.isMember(jss::type)) { - static constexpr std::array, 22> + static constexpr std::array, 24> types{ {{jss::account, ltACCOUNT_ROOT}, {jss::amendments, ltAMENDMENTS}, @@ -939,7 +939,9 @@ chooseLedgerEntryType(Json::Value const& params) {jss::ticket, ltTICKET}, {jss::xchain_owned_claim_id, ltXCHAIN_OWNED_CLAIM_ID}, {jss::xchain_owned_create_account_claim_id, - ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID}}}; + ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID}, + {jss::mpt_issuance, ltMPTOKEN_ISSUANCE}, + {jss::mptoken, ltMPTOKEN}}}; auto const& p = params[jss::type]; if (!p.isString()) diff --git a/src/xrpld/rpc/detail/TransactionSign.cpp b/src/xrpld/rpc/detail/TransactionSign.cpp index 65ee50c0891..2f10387bc81 100644 --- a/src/xrpld/rpc/detail/TransactionSign.cpp +++ b/src/xrpld/rpc/detail/TransactionSign.cpp @@ -213,7 +213,8 @@ checkPayment( if (!dstAccountID) return RPC::invalid_field_error("tx_json.Destination"); - if ((doPath == false) && params.isMember(jss::build_path)) + if (params.isMember(jss::build_path) && + ((doPath == false) || amount.holds())) return RPC::make_error( rpcINVALID_PARAMS, "Field 'build_path' not allowed in this context."); diff --git a/src/xrpld/rpc/handlers/AccountObjects.cpp b/src/xrpld/rpc/handlers/AccountObjects.cpp index c192fbf9071..63389753244 100644 --- a/src/xrpld/rpc/handlers/AccountObjects.cpp +++ b/src/xrpld/rpc/handlers/AccountObjects.cpp @@ -222,7 +222,9 @@ doAccountObjects(RPC::JsonContext& context) {jss::xchain_owned_claim_id, ltXCHAIN_OWNED_CLAIM_ID}, {jss::xchain_owned_create_account_claim_id, ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID}, - {jss::bridge, ltBRIDGE}}; + {jss::bridge, ltBRIDGE}, + {jss::mpt_issuance, ltMPTOKEN_ISSUANCE}, + {jss::mptoken, ltMPTOKEN}}; typeFilter.emplace(); typeFilter->reserve(std::size(deletionBlockers)); diff --git a/src/xrpld/rpc/handlers/AccountTx.cpp b/src/xrpld/rpc/handlers/AccountTx.cpp index a85abd86682..887694daf21 100644 --- a/src/xrpld/rpc/handlers/AccountTx.cpp +++ b/src/xrpld/rpc/handlers/AccountTx.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -349,6 +350,8 @@ populateJsonResponse( insertDeliveredAmount( jvObj[jss::meta], context, txn, *txnMeta); insertNFTSyntheticInJson(jvObj, sttx, *txnMeta); + RPC::insertMPTokenIssuanceID( + jvObj[jss::meta], sttx, *txnMeta); } else assert(false && "Missing transaction medatata"); diff --git a/src/xrpld/rpc/handlers/LedgerEntry.cpp b/src/xrpld/rpc/handlers/LedgerEntry.cpp index f461cd3100b..b8937c528eb 100644 --- a/src/xrpld/rpc/handlers/LedgerEntry.cpp +++ b/src/xrpld/rpc/handlers/LedgerEntry.cpp @@ -644,6 +644,72 @@ doLedgerEntry(RPC::JsonContext& context) uNodeIndex = keylet::oracle(*account, *documentID).key; } } + else if (context.params.isMember(jss::mpt_issuance)) + { + expectedType = ltMPTOKEN_ISSUANCE; + auto const unparsedMPTIssuanceID = + context.params[jss::mpt_issuance]; + if (unparsedMPTIssuanceID.isString()) + { + uint192 mptIssuanceID; + if (!mptIssuanceID.parseHex(unparsedMPTIssuanceID.asString())) + { + uNodeIndex = beast::zero; + jvResult[jss::error] = "malformedRequest"; + } + else + uNodeIndex = keylet::mptIssuance(mptIssuanceID).key; + } + else + { + jvResult[jss::error] = "malformedRequest"; + } + } + else if (context.params.isMember(jss::mptoken)) + { + expectedType = ltMPTOKEN; + auto const& mptJson = context.params[jss::mptoken]; + if (!mptJson.isObject()) + { + if (!uNodeIndex.parseHex(mptJson.asString())) + { + uNodeIndex = beast::zero; + jvResult[jss::error] = "malformedRequest"; + } + } + else if ( + !mptJson.isMember(jss::mpt_issuance_id) || + !mptJson.isMember(jss::account)) + { + jvResult[jss::error] = "malformedRequest"; + } + else + { + try + { + auto const mptIssuanceIdStr = + mptJson[jss::mpt_issuance_id].asString(); + + uint192 mptIssuanceID; + if (!mptIssuanceID.parseHex(mptIssuanceIdStr)) + Throw( + "Cannot parse mpt_issuance_id"); + + auto const account = parseBase58( + mptJson[jss::account].asString()); + + if (!account || account->isZero()) + jvResult[jss::error] = "malformedAddress"; + else + uNodeIndex = + keylet::mptoken(mptIssuanceID, *account).key; + } + catch (std::runtime_error const&) + { + jvResult[jss::error] = "malformedRequest"; + } + } + } else { if (context.params.isMember("params") && diff --git a/src/xrpld/rpc/handlers/Tx.cpp b/src/xrpld/rpc/handlers/Tx.cpp index ba103d186fc..98af3a809bf 100644 --- a/src/xrpld/rpc/handlers/Tx.cpp +++ b/src/xrpld/rpc/handlers/Tx.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -265,6 +266,7 @@ populateJsonResponse( insertDeliveredAmount( response[jss::meta], context, result.txn, *meta); insertNFTSyntheticInJson(response, sttx, *meta); + RPC::insertMPTokenIssuanceID(response[jss::meta], sttx, *meta); } } response[jss::validated] = result.validated; From ab5d450d3c249a8396731988eefad21e433e3618 Mon Sep 17 00:00:00 2001 From: Bob Conan Date: Tue, 29 Oct 2024 14:43:56 -0500 Subject: [PATCH 64/82] Update RELEASENOTES.md (#5154) fix the typo "concensus" -> "consensus" --- RELEASENOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 37f884b578f..c6a43f4aa7d 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -557,7 +557,7 @@ If you operate an XRP Ledger server, upgrade to version 2.0.0 by January 22, 202 - Switched to Unity builds to speed up Windows CI. [#4780](https://github.com/XRPLF/rippled/pull/4780) -- Clarified what makes concensus healthy in `FeeEscalation.md`. [#4729](https://github.com/XRPLF/rippled/pull/4729) +- Clarified what makes consensus healthy in `FeeEscalation.md`. [#4729](https://github.com/XRPLF/rippled/pull/4729) - Removed a dependency on the header for unit tests. [#4788](https://github.com/XRPLF/rippled/pull/4788) From d4a5f8390ee7fc84a62f4169d794ef3d04b303b0 Mon Sep 17 00:00:00 2001 From: yinyiqian1 Date: Tue, 29 Oct 2024 16:13:01 -0400 Subject: [PATCH 65/82] fix: reject invalid markers in account_objects RPC calls (#5046) --- src/test/rpc/AccountObjects_test.cpp | 168 ++++++++++++++++++++++ src/xrpld/rpc/detail/RPCHelpers.cpp | 18 ++- src/xrpld/rpc/handlers/AccountObjects.cpp | 17 +-- 3 files changed, 190 insertions(+), 13 deletions(-) diff --git a/src/test/rpc/AccountObjects_test.cpp b/src/test/rpc/AccountObjects_test.cpp index f58446e66c9..7326fff0c76 100644 --- a/src/test/rpc/AccountObjects_test.cpp +++ b/src/test/rpc/AccountObjects_test.cpp @@ -1220,6 +1220,173 @@ class AccountObjects_test : public beast::unit_test::suite } } + void + testAccountObjectMarker() + { + testcase("AccountObjectMarker"); + + using namespace jtx; + Env env(*this); + + Account const alice{"alice"}; + Account const bob{"bob"}; + Account const carol{"carol"}; + env.fund(XRP(10000), alice, bob, carol); + + unsigned const accountObjectSize = 30; + for (unsigned i = 0; i < accountObjectSize; i++) + env(check::create(alice, bob, XRP(10))); + + for (unsigned i = 0; i < 10; i++) + env(token::mint(carol, 0)); + + env.close(); + + unsigned const limit = 11; + Json::Value marker; + + // test account_objects with a limit and update marker + { + Json::Value params; + params[jss::account] = bob.human(); + params[jss::limit] = limit; + params[jss::ledger_index] = "validated"; + auto resp = env.rpc("json", "account_objects", to_string(params)); + auto& accountObjects = resp[jss::result][jss::account_objects]; + marker = resp[jss::result][jss::marker]; + BEAST_EXPECT(!resp[jss::result].isMember(jss::error)); + BEAST_EXPECT(accountObjects.size() == limit); + } + + // test account_objects with valid marker and update marker + { + Json::Value params; + params[jss::account] = bob.human(); + params[jss::limit] = limit; + params[jss::marker] = marker; + params[jss::ledger_index] = "validated"; + auto resp = env.rpc("json", "account_objects", to_string(params)); + auto& accountObjects = resp[jss::result][jss::account_objects]; + marker = resp[jss::result][jss::marker]; + BEAST_EXPECT(!resp[jss::result].isMember(jss::error)); + BEAST_EXPECT(accountObjects.size() == limit); + } + + // this lambda function is used to check invalid marker response. + auto testInvalidMarker = [&](std::string& marker) { + Json::Value params; + params[jss::account] = bob.human(); + params[jss::limit] = limit; + params[jss::ledger_index] = jss::validated; + params[jss::marker] = marker; + Json::Value const resp = + env.rpc("json", "account_objects", to_string(params)); + return resp[jss::result][jss::error_message] == + "Invalid field \'marker\'."; + }; + + auto const markerStr = marker.asString(); + auto const& idx = markerStr.find(','); + auto const dirIndex = markerStr.substr(0, idx); + auto const entryIndex = markerStr.substr(idx + 1); + + // test account_objects with an invalid marker that contains no ',' + { + std::string s = dirIndex + entryIndex; + BEAST_EXPECT(testInvalidMarker(s)); + } + + // test invalid marker by adding invalid string after the maker: + // "dirIndex,entryIndex,1234" + { + std::string s = markerStr + ",1234"; + BEAST_EXPECT(testInvalidMarker(s)); + } + + // test account_objects with an invalid marker containing invalid + // dirIndex by replacing some characters from the dirIndex. + { + std::string s = markerStr; + s.replace(0, 7, "FFFFFFF"); + BEAST_EXPECT(testInvalidMarker(s)); + } + + // test account_objects with an invalid marker containing invalid + // entryIndex by replacing some characters from the entryIndex. + { + std::string s = entryIndex; + s.replace(0, 7, "FFFFFFF"); + s = dirIndex + ',' + s; + BEAST_EXPECT(testInvalidMarker(s)); + } + + // test account_objects with an invalid marker containing invalid + // dirIndex with marker: ",entryIndex" + { + std::string s = ',' + entryIndex; + BEAST_EXPECT(testInvalidMarker(s)); + } + + // test account_objects with marker: "0,entryIndex", this is still + // valid, because when dirIndex = 0, we will use root key to find + // dir. + { + std::string s = "0," + entryIndex; + Json::Value params; + params[jss::account] = bob.human(); + params[jss::limit] = limit; + params[jss::marker] = s; + params[jss::ledger_index] = "validated"; + auto resp = env.rpc("json", "account_objects", to_string(params)); + auto& accountObjects = resp[jss::result][jss::account_objects]; + BEAST_EXPECT(!resp[jss::result].isMember(jss::error)); + BEAST_EXPECT(accountObjects.size() == limit); + } + + // test account_objects with an invalid marker containing invalid + // entryIndex with marker: "dirIndex," + { + std::string s = dirIndex + ','; + BEAST_EXPECT(testInvalidMarker(s)); + } + + // test account_objects with an invalid marker containing invalid + // entryIndex with marker: "dirIndex,0" + { + std::string s = dirIndex + ",0"; + BEAST_EXPECT(testInvalidMarker(s)); + } + + // continue getting account_objects with valid marker. This will be the + // last page, so response will not contain any marker. + { + Json::Value params; + params[jss::account] = bob.human(); + params[jss::limit] = limit; + params[jss::marker] = marker; + params[jss::ledger_index] = "validated"; + auto resp = env.rpc("json", "account_objects", to_string(params)); + auto& accountObjects = resp[jss::result][jss::account_objects]; + BEAST_EXPECT(!resp[jss::result].isMember(jss::error)); + BEAST_EXPECT( + accountObjects.size() == accountObjectSize - limit * 2); + BEAST_EXPECT(!resp[jss::result].isMember(jss::marker)); + } + + // test account_objects when the account only have nft pages, but + // provided invalid entry index. + { + Json::Value params; + params[jss::account] = carol.human(); + params[jss::limit] = 10; + params[jss::marker] = "0," + entryIndex; + params[jss::ledger_index] = "validated"; + auto resp = env.rpc("json", "account_objects", to_string(params)); + auto& accountObjects = resp[jss::result][jss::account_objects]; + BEAST_EXPECT(accountObjects.size() == 0); + } + } + void run() override { @@ -1229,6 +1396,7 @@ class AccountObjects_test : public beast::unit_test::suite testObjectTypes(); testNFTsMarker(); testAccountNFTs(); + testAccountObjectMarker(); } }; diff --git a/src/xrpld/rpc/detail/RPCHelpers.cpp b/src/xrpld/rpc/detail/RPCHelpers.cpp index 930f8d8a0e5..0e9481bf540 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.cpp +++ b/src/xrpld/rpc/detail/RPCHelpers.cpp @@ -158,6 +158,10 @@ getAccountObjects( std::uint32_t const limit, Json::Value& jvResult) { + // check if dirIndex is valid + if (!dirIndex.isZero() && !ledger.read({ltDIR_NODE, dirIndex})) + return false; + auto typeMatchesFilter = [](std::vector const& typeFilter, LedgerEntryType ledgerType) { auto it = std::find(typeFilter.begin(), typeFilter.end(), ledgerType); @@ -249,8 +253,18 @@ getAccountObjects( if (!dir) { // it's possible the user had nftoken pages but no - // directory entries - return mlimit < limit; + // directory entries. If there's no nftoken page, we will + // give empty array for account_objects. + if (mlimit >= limit) + jvResult[jss::account_objects] = Json::arrayValue; + + // non-zero dirIndex validity was checked in the beginning of this + // function; by this point, it should be zero. This function returns + // true regardless of nftoken page presence; if absent, account_objects + // is already set as an empty array. Notice we will only return false in + // this function when entryIndex can not be found, indicating an invalid + // marker error. + return true; } std::uint32_t i = 0; diff --git a/src/xrpld/rpc/handlers/AccountObjects.cpp b/src/xrpld/rpc/handlers/AccountObjects.cpp index 63389753244..538b1d79424 100644 --- a/src/xrpld/rpc/handlers/AccountObjects.cpp +++ b/src/xrpld/rpc/handlers/AccountObjects.cpp @@ -270,18 +270,15 @@ doAccountObjects(RPC::JsonContext& context) if (!marker.isString()) return RPC::expected_field_error(jss::marker, "string"); - std::stringstream ss(marker.asString()); - std::string s; - if (!std::getline(ss, s, ',')) + auto const& markerStr = marker.asString(); + auto const& idx = markerStr.find(','); + if (idx == std::string::npos) return RPC::invalid_field_error(jss::marker); - if (!dirIndex.parseHex(s)) + if (!dirIndex.parseHex(markerStr.substr(0, idx))) return RPC::invalid_field_error(jss::marker); - if (!std::getline(ss, s, ',')) - return RPC::invalid_field_error(jss::marker); - - if (!entryIndex.parseHex(s)) + if (!entryIndex.parseHex(markerStr.substr(idx + 1))) return RPC::invalid_field_error(jss::marker); } @@ -293,9 +290,7 @@ doAccountObjects(RPC::JsonContext& context) entryIndex, limit, result)) - { - result[jss::account_objects] = Json::arrayValue; - } + return RPC::invalid_field_error(jss::marker); result[jss::account] = toBase58(accountID); context.loadType = Resource::feeMediumBurdenRPC; From 0d887ad815f59576aac3ee5fb4b3f021c482af2d Mon Sep 17 00:00:00 2001 From: Valentin Balaschenko <13349202+vlntb@users.noreply.github.com> Date: Tue, 29 Oct 2024 20:26:20 +0000 Subject: [PATCH 66/82] docs: Add protobuf dependencies to linux setup instructions (#5156) --- docs/build/environment.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/build/environment.md b/docs/build/environment.md index a204cd2c197..7fe89ffb49f 100644 --- a/docs/build/environment.md +++ b/docs/build/environment.md @@ -23,7 +23,7 @@ direction. ``` apt update -apt install --yes curl git libssl-dev python3.10-dev python3-pip make g++-11 +apt install --yes curl git libssl-dev python3.10-dev python3-pip make g++-11 libprotobuf-dev protobuf-compiler curl --location --remote-name \ "https://github.com/Kitware/CMake/releases/download/v3.25.1/cmake-3.25.1.tar.gz" From d6dbf0e0a626aeca8def163a89f58af19dd50b50 Mon Sep 17 00:00:00 2001 From: Alloy Networks <45832257+alloynetworks@users.noreply.github.com> Date: Fri, 1 Nov 2024 00:14:55 +0200 Subject: [PATCH 67/82] Add hubs.xrpkuwait.com to bootstrap (#5169) --- cfg/rippled-example.cfg | 1 + src/xrpld/overlay/detail/OverlayImpl.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/cfg/rippled-example.cfg b/cfg/rippled-example.cfg index 0ce3406f6b9..6fabe980cc1 100644 --- a/cfg/rippled-example.cfg +++ b/cfg/rippled-example.cfg @@ -417,6 +417,7 @@ # The default list of entries is: # - r.ripple.com 51235 # - sahyadri.isrdc.in 51235 +# - hubs.xrpkuwait.com 51235 # # Examples: # diff --git a/src/xrpld/overlay/detail/OverlayImpl.cpp b/src/xrpld/overlay/detail/OverlayImpl.cpp index 970873007c2..e41a08a43d1 100644 --- a/src/xrpld/overlay/detail/OverlayImpl.cpp +++ b/src/xrpld/overlay/detail/OverlayImpl.cpp @@ -491,6 +491,9 @@ OverlayImpl::start() // Pool of servers operated by ISRDC - https://isrdc.in bootstrapIps.push_back("sahyadri.isrdc.in 51235"); + + // Pool of servers operated by @Xrpkuwait - https://xrpkuwait.com + bootstrapIps.push_back("hubs.xrpkuwait.com 51235"); } m_resolver.resolve( From 54a350be79a455fec7b91ccab1d79df0be8bc5fd Mon Sep 17 00:00:00 2001 From: yinyiqian1 Date: Mon, 4 Nov 2024 15:27:57 -0500 Subject: [PATCH 68/82] Add AMMClawback Transaction (XLS-0073d) (#5142) Amendment: - AMMClawback New Transactions: - AMMClawback Modified Transactions: - AMMCreate - AMMDeposit --- include/xrpl/protocol/Feature.h | 2 +- include/xrpl/protocol/TxFlags.h | 4 + include/xrpl/protocol/detail/features.macro | 1 + .../xrpl/protocol/detail/transactions.macro | 8 + include/xrpl/protocol/jss.h | 1 + src/libxrpl/protocol/TER.cpp | 2 +- src/test/app/AMMClawback_test.cpp | 1794 +++++++++++++++++ src/test/app/AMM_test.cpp | 351 +++- src/test/app/MPToken_test.cpp | 11 + src/test/jtx/AMM.h | 8 + src/test/jtx/impl/AMM.cpp | 20 + src/test/rpc/Status_test.cpp | 4 +- src/xrpld/app/tx/detail/AMMClawback.cpp | 290 +++ src/xrpld/app/tx/detail/AMMClawback.h | 75 + src/xrpld/app/tx/detail/AMMCreate.cpp | 8 +- src/xrpld/app/tx/detail/AMMDeposit.cpp | 31 + src/xrpld/app/tx/detail/AMMWithdraw.cpp | 271 ++- src/xrpld/app/tx/detail/AMMWithdraw.h | 98 +- src/xrpld/app/tx/detail/InvariantCheck.cpp | 7 +- src/xrpld/app/tx/detail/applySteps.cpp | 1 + 20 files changed, 2840 insertions(+), 147 deletions(-) create mode 100644 src/test/app/AMMClawback_test.cpp create mode 100644 src/xrpld/app/tx/detail/AMMClawback.cpp create mode 100644 src/xrpld/app/tx/detail/AMMClawback.h diff --git a/include/xrpl/protocol/Feature.h b/include/xrpl/protocol/Feature.h index eb975f39ae0..a2510c63000 100644 --- a/include/xrpl/protocol/Feature.h +++ b/include/xrpl/protocol/Feature.h @@ -80,7 +80,7 @@ namespace detail { // Feature.cpp. Because it's only used to reserve storage, and determine how // large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than // the actual number of amendments. A LogicError on startup will verify this. -static constexpr std::size_t numFeatures = 80; +static constexpr std::size_t numFeatures = 81; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated diff --git a/include/xrpl/protocol/TxFlags.h b/include/xrpl/protocol/TxFlags.h index 4894f48a7f9..c293798f7d7 100644 --- a/include/xrpl/protocol/TxFlags.h +++ b/include/xrpl/protocol/TxFlags.h @@ -207,6 +207,10 @@ constexpr std::uint32_t tfDepositSubTx = constexpr std::uint32_t tfWithdrawMask = ~(tfUniversal | tfWithdrawSubTx); constexpr std::uint32_t tfDepositMask = ~(tfUniversal | tfDepositSubTx); +// AMMClawback flags: +constexpr std::uint32_t tfClawTwoAssets = 0x00000001; +constexpr std::uint32_t tfAMMClawbackMask = ~(tfUniversal | tfClawTwoAssets); + // BridgeModify flags: constexpr std::uint32_t tfClearAccountCreateAmount = 0x00010000; constexpr std::uint32_t tfBridgeModifyMask = ~(tfUniversal | tfClearAccountCreateAmount); diff --git a/include/xrpl/protocol/detail/features.macro b/include/xrpl/protocol/detail/features.macro index 3a8d77e2bab..e5351be11c0 100644 --- a/include/xrpl/protocol/detail/features.macro +++ b/include/xrpl/protocol/detail/features.macro @@ -95,6 +95,7 @@ XRPL_FIX (1513, Supported::yes, VoteBehavior::DefaultYe XRPL_FEATURE(FlowCross, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(Flow, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(OwnerPaysFee, Supported::no, VoteBehavior::DefaultNo) +XRPL_FEATURE(AMMClawback, Supported::yes, VoteBehavior::DefaultYes) // The following amendments are obsolete, but must remain supported // because they could potentially get enabled. diff --git a/include/xrpl/protocol/detail/transactions.macro b/include/xrpl/protocol/detail/transactions.macro index 30e27da4167..a064abbc12b 100644 --- a/include/xrpl/protocol/detail/transactions.macro +++ b/include/xrpl/protocol/detail/transactions.macro @@ -227,6 +227,14 @@ TRANSACTION(ttCLAWBACK, 30, Clawback, ({ {sfHolder, soeOPTIONAL}, })) +/** This transaction claws back tokens from an AMM pool. */ +TRANSACTION(ttAMM_CLAWBACK, 31, AMMClawback, ({ + {sfHolder, soeREQUIRED}, + {sfAsset, soeREQUIRED}, + {sfAsset2, soeREQUIRED}, + {sfAmount, soeOPTIONAL}, +})) + /** This transaction type creates an AMM instance */ TRANSACTION(ttAMM_CREATE, 35, AMMCreate, ({ {sfAmount, soeREQUIRED}, diff --git a/include/xrpl/protocol/jss.h b/include/xrpl/protocol/jss.h index bafdde4fbcc..90e5b1c6e47 100644 --- a/include/xrpl/protocol/jss.h +++ b/include/xrpl/protocol/jss.h @@ -73,6 +73,7 @@ JSS(Escrow); // ledger type. JSS(Fee); // in/out: TransactionSign; field. JSS(FeeSettings); // ledger type. JSS(Flags); // in/out: TransactionSign; field. +JSS(Holder); // field. JSS(Invalid); // JSS(LastLedgerSequence); // in: TransactionSign; field JSS(LastUpdateTime); // field. diff --git a/src/libxrpl/protocol/TER.cpp b/src/libxrpl/protocol/TER.cpp index 788b3a86152..90809b29981 100644 --- a/src/libxrpl/protocol/TER.cpp +++ b/src/libxrpl/protocol/TER.cpp @@ -160,7 +160,7 @@ transResults() MAKE_ERROR(temMALFORMED, "Malformed transaction."), MAKE_ERROR(temBAD_AMM_TOKENS, "Malformed: Invalid LPTokens."), - MAKE_ERROR(temBAD_AMOUNT, "Can only send positive amounts."), + MAKE_ERROR(temBAD_AMOUNT, "Malformed: Bad amount."), MAKE_ERROR(temBAD_CURRENCY, "Malformed: Bad currency."), MAKE_ERROR(temBAD_EXPIRATION, "Malformed: Bad expiration."), MAKE_ERROR(temBAD_FEE, "Invalid fee, negative or not XRP."), diff --git a/src/test/app/AMMClawback_test.cpp b/src/test/app/AMMClawback_test.cpp new file mode 100644 index 00000000000..705a1274073 --- /dev/null +++ b/src/test/app/AMMClawback_test.cpp @@ -0,0 +1,1794 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +namespace ripple { +namespace test { +class AMMClawback_test : public jtx::AMMTest +{ + void + testInvalidRequest(FeatureBitset features) + { + testcase("test invalid request"); + using namespace jtx; + + // Test if holder does not exist. + { + Env env(*this, features); + Account gw{"gateway"}; + Account alice{"alice"}; + env.fund(XRP(100000), gw, alice); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + env.trust(USD(10000), alice); + env(pay(gw, alice, gw["USD"](100))); + + AMM amm(env, alice, XRP(100), USD(100)); + env.close(); + + env(amm::ammClawback( + gw, Account("unknown"), USD, XRP, std::nullopt), + ter(terNO_ACCOUNT)); + } + + // Test if asset pair provided does not exist. This should + // return terNO_AMM error. + { + Env env(*this, features); + Account gw{"gateway"}; + Account alice{"alice"}; + env.fund(XRP(100000), gw, alice); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw issues 100 USD to Alice. + auto const USD = gw["USD"]; + env.trust(USD(10000), alice); + env(pay(gw, alice, USD(100))); + env.close(); + + // Withdraw all the tokens from the AMMAccount. + // The AMMAccount will be auto deleted. + AMM amm(env, gw, XRP(100), USD(100)); + amm.withdrawAll(gw); + BEAST_EXPECT(!amm.ammExists()); + env.close(); + + // The AMM account does not exist at all now. + // It should return terNO_AMM error. + env(amm::ammClawback(gw, alice, USD, EUR, std::nullopt), + ter(terNO_AMM)); + } + + // Test if the issuer field and holder field is the same. This should + // return temMALFORMED error. + { + Env env(*this, features); + Account gw{"gateway"}; + Account alice{"alice"}; + env.fund(XRP(10000), gw, alice); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw issues 100 USD to Alice. + auto const USD = gw["USD"]; + env.trust(USD(1000), alice); + env(pay(gw, alice, USD(100))); + env.close(); + + AMM amm(env, gw, XRP(100), USD(100), ter(tesSUCCESS)); + + // Issuer can not clawback from himself. + env(amm::ammClawback(gw, gw, USD, XRP, std::nullopt), + ter(temMALFORMED)); + + // Holder can not clawback from himself. + env(amm::ammClawback(alice, alice, USD, XRP, std::nullopt), + ter(temMALFORMED)); + } + + // Test if the Asset field matches the Account field. + { + Env env(*this, features); + Account gw{"gateway"}; + Account alice{"alice"}; + env.fund(XRP(10000), gw, alice); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw issues 100 USD to Alice. + auto const USD = gw["USD"]; + env.trust(USD(1000), alice); + env(pay(gw, alice, USD(100))); + env.close(); + + AMM amm(env, gw, XRP(100), USD(100), ter(tesSUCCESS)); + + // The Asset's issuer field is alice, while the Account field is gw. + // This should return temMALFORMED because they do not match. + env(amm::ammClawback( + gw, + alice, + Issue{gw["USD"].currency, alice.id()}, + XRP, + std::nullopt), + ter(temMALFORMED)); + } + + // Test if the Amount field matches the Asset field. + { + Env env(*this, features); + Account gw{"gateway"}; + Account alice{"alice"}; + env.fund(XRP(10000), gw, alice); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw issues 100 USD to Alice. + auto const USD = gw["USD"]; + env.trust(USD(1000), alice); + env(pay(gw, alice, USD(100))); + env.close(); + + AMM amm(env, gw, XRP(100), USD(100), ter(tesSUCCESS)); + + // The Asset's issuer subfield is gw account and Amount's issuer + // subfield is alice account. Return temBAD_AMOUNT because + // they do not match. + env(amm::ammClawback( + gw, + alice, + USD, + XRP, + STAmount{Issue{gw["USD"].currency, alice.id()}, 1}), + ter(temBAD_AMOUNT)); + } + + // Test if the Amount is invalid, which is less than zero. + { + Env env(*this, features); + Account gw{"gateway"}; + Account alice{"alice"}; + env.fund(XRP(10000), gw, alice); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw issues 100 USD to Alice. + auto const USD = gw["USD"]; + env.trust(USD(1000), alice); + env(pay(gw, alice, USD(100))); + env.close(); + + AMM amm(env, gw, XRP(100), USD(100), ter(tesSUCCESS)); + + // Return temBAD_AMOUNT if the Amount value is less than 0. + env(amm::ammClawback( + gw, + alice, + USD, + XRP, + STAmount{Issue{gw["USD"].currency, gw.id()}, -1}), + ter(temBAD_AMOUNT)); + + // Return temBAD_AMOUNT if the Amount value is 0. + env(amm::ammClawback( + gw, + alice, + USD, + XRP, + STAmount{Issue{gw["USD"].currency, gw.id()}, 0}), + ter(temBAD_AMOUNT)); + } + + // Test if the issuer did not set asfAllowTrustLineClawback, AMMClawback + // transaction is prohibited. + { + Env env(*this, features); + Account gw{"gateway"}; + Account alice{"alice"}; + env.fund(XRP(10000), gw, alice); + env.close(); + + // gw issues 100 USD to Alice. + auto const USD = gw["USD"]; + env.trust(USD(1000), alice); + env(pay(gw, alice, USD(100))); + env.close(); + env.require(balance(alice, gw["USD"](100))); + env.require(balance(gw, alice["USD"](-100))); + + // gw creates AMM pool of XRP/USD. + AMM amm(env, gw, XRP(100), USD(100), ter(tesSUCCESS)); + + // If asfAllowTrustLineClawback is not set, the issuer is not + // allowed to send the AMMClawback transaction. + env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), + ter(tecNO_PERMISSION)); + } + + // Test invalid flag. + { + Env env(*this, features); + Account gw{"gateway"}; + Account alice{"alice"}; + env.fund(XRP(10000), gw, alice); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw issues 100 USD to Alice. + auto const USD = gw["USD"]; + env.trust(USD(1000), alice); + env(pay(gw, alice, USD(100))); + env.close(); + + AMM amm(env, gw, XRP(100), USD(100), ter(tesSUCCESS)); + + // Return temINVALID_FLAG when providing invalid flag. + env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), + txflags(tfTwoAssetIfEmpty), + ter(temINVALID_FLAG)); + } + + // Test if tfClawTwoAssets is set when the two assets in the AMM pool + // are not issued by the same issuer. + { + Env env(*this, features); + Account gw{"gateway"}; + Account alice{"alice"}; + env.fund(XRP(10000), gw, alice); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw issues 100 USD to Alice. + auto const USD = gw["USD"]; + env.trust(USD(1000), alice); + env(pay(gw, alice, USD(100))); + env.close(); + + // gw creates AMM pool of XRP/USD. + AMM amm(env, gw, XRP(100), USD(100), ter(tesSUCCESS)); + + // Return tecNO_PERMISSION because the issuer set tfClawTwoAssets, + // but the issuer only issues USD in the pool. The issuer is not + // allowed to set tfClawTwoAssets flag if he did not issue both + // assts in the pool. + env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), + txflags(tfClawTwoAssets), + ter(tecNO_PERMISSION)); + } + + // Test clawing back XRP is being prohibited. + { + Env env(*this, features); + Account gw{"gateway"}; + Account alice{"alice"}; + env.fund(XRP(1000000), gw, alice); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw issues 3000 USD to Alice. + auto const USD = gw["USD"]; + env.trust(USD(100000), alice); + env(pay(gw, alice, USD(3000))); + env.close(); + + // Alice creates AMM pool of XRP/USD. + AMM amm(env, alice, XRP(1000), USD(2000), ter(tesSUCCESS)); + env.close(); + + // Clawback XRP is prohibited. + env(amm::ammClawback(gw, alice, XRP, USD, std::nullopt), + ter(temMALFORMED)); + } + } + + void + testFeatureDisabled(FeatureBitset features) + { + testcase("test featureAMMClawback is not enabled."); + using namespace jtx; + if (!features[featureAMMClawback]) + { + Env env(*this, features); + Account gw{"gateway"}; + Account alice{"alice"}; + env.fund(XRP(1000000), gw, alice); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw issues 3000 USD to Alice. + auto const USD = gw["USD"]; + env.trust(USD(100000), alice); + env(pay(gw, alice, USD(3000))); + env.close(); + + // When featureAMMClawback is not enabled, AMMClawback is disabled. + // Because when featureAMMClawback is disabled, we can not create + // amm account, call amm::ammClawback directly for testing purpose. + env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), + ter(temDISABLED)); + } + } + + void + testAMMClawbackSpecificAmount(FeatureBitset features) + { + testcase("test AMMClawback specific amount"); + using namespace jtx; + + // Test AMMClawback for USD/EUR pool. The assets are issued by different + // issuer. Claw back USD, and EUR goes back to the holder. + { + Env env(*this, features); + Account gw{"gateway"}; + Account gw2{"gateway2"}; + Account alice{"alice"}; + env.fund(XRP(1000000), gw, gw2, alice); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw issues 3000 USD to Alice. + auto const USD = gw["USD"]; + env.trust(USD(100000), alice); + env(pay(gw, alice, USD(3000))); + env.close(); + env.require(balance(gw, alice["USD"](-3000))); + env.require(balance(alice, gw["USD"](3000))); + + // gw2 issues 3000 EUR to Alice. + auto const EUR = gw2["EUR"]; + env.trust(EUR(100000), alice); + env(pay(gw2, alice, EUR(3000))); + env.close(); + env.require(balance(gw2, alice["EUR"](-3000))); + env.require(balance(alice, gw2["EUR"](3000))); + + // Alice creates AMM pool of EUR/USD. + AMM amm(env, alice, EUR(1000), USD(2000), ter(tesSUCCESS)); + env.close(); + + BEAST_EXPECT(amm.expectBalances( + USD(2000), EUR(1000), IOUAmount{1414213562373095, -12})); + + // gw clawback 1000 USD from the AMM pool. + env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), + ter(tesSUCCESS)); + env.close(); + + // Alice's initial balance for USD is 3000 USD. Alice deposited 2000 + // USD into the pool, then she has 1000 USD. And 1000 USD was clawed + // back from the AMM pool, so she still has 1000 USD. + env.require(balance(gw, alice["USD"](-1000))); + env.require(balance(alice, gw["USD"](1000))); + + // Alice's initial balance for EUR is 3000 EUR. Alice deposited 1000 + // EUR into the pool, 500 EUR was withdrawn proportionally. So she + // has 2500 EUR now. + env.require(balance(gw2, alice["EUR"](-2500))); + env.require(balance(alice, gw2["EUR"](2500))); + + // 1000 USD and 500 EUR was withdrawn from the AMM pool, so the + // current balance is 1000 USD and 500 EUR. + BEAST_EXPECT(amm.expectBalances( + USD(1000), EUR(500), IOUAmount{7071067811865475, -13})); + + // Alice has half of its initial lptokens Left. + BEAST_EXPECT( + amm.expectLPTokens(alice, IOUAmount{7071067811865475, -13})); + + // gw clawback another 1000 USD from the AMM pool. The AMM pool will + // be empty and get deleted. + env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), + ter(tesSUCCESS)); + env.close(); + + // Alice should still has 1000 USD because gw clawed back from the + // AMM pool. + env.require(balance(gw, alice["USD"](-1000))); + env.require(balance(alice, gw["USD"](1000))); + + // Alice should has 3000 EUR now because another 500 EUR was + // withdrawn. + env.require(balance(gw2, alice["EUR"](-3000))); + env.require(balance(alice, gw2["EUR"](3000))); + + // amm is automatically deleted. + BEAST_EXPECT(!amm.ammExists()); + } + + // Test AMMClawback for USD/XRP pool. Claw back USD, and XRP goes back + // to the holder. + { + Env env(*this, features); + Account gw{"gateway"}; + Account alice{"alice"}; + env.fund(XRP(1000000), gw, alice); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw issues 3000 USD to Alice. + auto const USD = gw["USD"]; + env.trust(USD(100000), alice); + env(pay(gw, alice, USD(3000))); + env.close(); + env.require(balance(gw, alice["USD"](-3000))); + env.require(balance(alice, gw["USD"](3000))); + + // Alice creates AMM pool of XRP/USD. + AMM amm(env, alice, XRP(1000), USD(2000), ter(tesSUCCESS)); + env.close(); + + BEAST_EXPECT(amm.expectBalances( + USD(2000), XRP(1000), IOUAmount{1414213562373095, -9})); + + auto aliceXrpBalance = env.balance(alice, XRP); + + // gw clawback 1000 USD from the AMM pool. + env(amm::ammClawback(gw, alice, USD, XRP, USD(1000)), + ter(tesSUCCESS)); + env.close(); + + // Alice's initial balance for USD is 3000 USD. Alice deposited 2000 + // USD into the pool, then she has 1000 USD. And 1000 USD was clawed + // back from the AMM pool, so she still has 1000 USD. + env.require(balance(gw, alice["USD"](-1000))); + env.require(balance(alice, gw["USD"](1000))); + + // Alice will get 500 XRP back. + BEAST_EXPECT( + expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(500))); + + // 1000 USD and 500 XRP was withdrawn from the AMM pool, so the + // current balance is 1000 USD and 500 XRP. + BEAST_EXPECT(amm.expectBalances( + USD(1000), XRP(500), IOUAmount{7071067811865475, -10})); + + // Alice has half of its initial lptokens Left. + BEAST_EXPECT( + amm.expectLPTokens(alice, IOUAmount{7071067811865475, -10})); + + // gw clawback another 1000 USD from the AMM pool. The AMM pool will + // be empty and get deleted. + env(amm::ammClawback(gw, alice, USD, XRP, USD(1000)), + ter(tesSUCCESS)); + env.close(); + + // Alice should still has 1000 USD because gw clawed back from the + // AMM pool. + env.require(balance(gw, alice["USD"](-1000))); + env.require(balance(alice, gw["USD"](1000))); + + // Alice will get another 1000 XRP back. + BEAST_EXPECT( + expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(1000))); + + // amm is automatically deleted. + BEAST_EXPECT(!amm.ammExists()); + } + } + + void + testAMMClawbackExceedBalance(FeatureBitset features) + { + testcase( + "test AMMClawback specific amount which exceeds the current " + "balance"); + using namespace jtx; + + // Test AMMClawback for USD/EUR pool. The assets are issued by different + // issuer. Claw back USD for multiple times, and EUR goes back to the + // holder. The last AMMClawback transaction exceeds the holder's USD + // balance in AMM pool. + { + Env env(*this, features); + Account gw{"gateway"}; + Account gw2{"gateway2"}; + Account alice{"alice"}; + env.fund(XRP(1000000), gw, gw2, alice); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw issues 6000 USD to Alice. + auto const USD = gw["USD"]; + env.trust(USD(100000), alice); + env(pay(gw, alice, USD(6000))); + env.close(); + env.require(balance(alice, gw["USD"](6000))); + + // gw2 issues 6000 EUR to Alice. + auto const EUR = gw2["EUR"]; + env.trust(EUR(100000), alice); + env(pay(gw2, alice, EUR(6000))); + env.close(); + env.require(balance(alice, gw2["EUR"](6000))); + + // Alice creates AMM pool of EUR/USD + AMM amm(env, alice, EUR(5000), USD(4000), ter(tesSUCCESS)); + env.close(); + + BEAST_EXPECT(amm.expectBalances( + USD(4000), EUR(5000), IOUAmount{4472135954999580, -12})); + + // gw clawback 1000 USD from the AMM pool + env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), + ter(tesSUCCESS)); + env.close(); + + // Alice's initial balance for USD is 6000 USD. Alice deposited 4000 + // USD into the pool, then she has 2000 USD. And 1000 USD was clawed + // back from the AMM pool, so she still has 2000 USD. + env.require(balance(alice, gw["USD"](2000))); + + // Alice's initial balance for EUR is 6000 EUR. Alice deposited 5000 + // EUR into the pool, 1250 EUR was withdrawn proportionally. So she + // has 2500 EUR now. + env.require(balance(alice, gw2["EUR"](2250))); + + // 1000 USD and 1250 EUR was withdrawn from the AMM pool, so the + // current balance is 3000 USD and 3750 EUR. + BEAST_EXPECT(amm.expectBalances( + USD(3000), EUR(3750), IOUAmount{3354101966249685, -12})); + + // Alice has 3/4 of its initial lptokens Left. + BEAST_EXPECT( + amm.expectLPTokens(alice, IOUAmount{3354101966249685, -12})); + + // gw clawback another 500 USD from the AMM pool. + env(amm::ammClawback(gw, alice, USD, EUR, USD(500)), + ter(tesSUCCESS)); + env.close(); + + // Alice should still has 2000 USD because gw clawed back from the + // AMM pool. + env.require(balance(alice, gw["USD"](2000))); + + BEAST_EXPECT(amm.expectBalances( + STAmount{USD, UINT64_C(2500000000000001), -12}, + STAmount{EUR, UINT64_C(3125000000000001), -12}, + IOUAmount{2795084971874738, -12})); + + BEAST_EXPECT( + env.balance(alice, EUR) == + STAmount(EUR, UINT64_C(2874999999999999), -12)); + + // gw clawback small amount, 1 USD. + env(amm::ammClawback(gw, alice, USD, EUR, USD(1)), ter(tesSUCCESS)); + env.close(); + + // Another 1 USD / 1.25 EUR was withdrawn. + env.require(balance(alice, gw["USD"](2000))); + + BEAST_EXPECT(amm.expectBalances( + STAmount{USD, UINT64_C(2499000000000002), -12}, + STAmount{EUR, UINT64_C(3123750000000002), -12}, + IOUAmount{2793966937885989, -12})); + + BEAST_EXPECT( + env.balance(alice, EUR) == + STAmount(EUR, UINT64_C(2876249999999998), -12)); + + // gw clawback 4000 USD, exceeding the current balance. We + // will clawback all. + env(amm::ammClawback(gw, alice, USD, EUR, USD(4000)), + ter(tesSUCCESS)); + env.close(); + + env.require(balance(alice, gw["USD"](2000))); + + // All alice's EUR in the pool goes back to alice. + BEAST_EXPECT( + env.balance(alice, EUR) == + STAmount(EUR, UINT64_C(6000000000000000), -12)); + + // amm is automatically deleted. + BEAST_EXPECT(!amm.ammExists()); + } + + // Test AMMClawback for USD/XRP pool. Claw back USD for multiple times, + // and XRP goes back to the holder. The last AMMClawback transaction + // exceeds the holder's USD balance in AMM pool. In this case, gw + // creates the AMM pool USD/XRP, both alice and bob deposit into it. gw2 + // creates the AMM pool EUR/XRP. + { + Env env(*this, features); + Account gw{"gateway"}; + Account gw2{"gateway2"}; + Account alice{"alice"}; + Account bob{"bob"}; + env.fund(XRP(1000000), gw, gw2, alice, bob); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw2 sets asfAllowTrustLineClawback. + env(fset(gw2, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw2, asfAllowTrustLineClawback)); + + // gw issues 6000 USD to Alice and 5000 USD to Bob. + auto const USD = gw["USD"]; + env.trust(USD(100000), alice); + env(pay(gw, alice, USD(6000))); + env.trust(USD(100000), bob); + env(pay(gw, bob, USD(5000))); + env.close(); + + // gw2 issues 5000 EUR to Alice and 4000 EUR to Bob. + auto const EUR = gw2["EUR"]; + env.trust(EUR(100000), alice); + env(pay(gw2, alice, EUR(5000))); + env.trust(EUR(100000), bob); + env(pay(gw2, bob, EUR(4000))); + env.close(); + + // gw creates AMM pool of XRP/USD, alice and bob deposit XRP/USD. + AMM amm(env, gw, XRP(2000), USD(1000), ter(tesSUCCESS)); + BEAST_EXPECT(amm.expectBalances( + USD(1000), XRP(2000), IOUAmount{1414213562373095, -9})); + amm.deposit(alice, USD(1000), XRP(2000)); + BEAST_EXPECT(amm.expectBalances( + USD(2000), XRP(4000), IOUAmount{2828427124746190, -9})); + amm.deposit(bob, USD(1000), XRP(2000)); + BEAST_EXPECT(amm.expectBalances( + USD(3000), XRP(6000), IOUAmount{4242640687119285, -9})); + env.close(); + + // gw2 creates AMM pool of XRP/EUR, alice and bob deposit XRP/EUR. + AMM amm2(env, gw2, XRP(3000), EUR(1000), ter(tesSUCCESS)); + BEAST_EXPECT(amm2.expectBalances( + EUR(1000), XRP(3000), IOUAmount{1732050807568878, -9})); + amm2.deposit(alice, EUR(1000), XRP(3000)); + BEAST_EXPECT(amm2.expectBalances( + EUR(2000), XRP(6000), IOUAmount{3464101615137756, -9})); + amm2.deposit(bob, EUR(1000), XRP(3000)); + BEAST_EXPECT(amm2.expectBalances( + EUR(3000), XRP(9000), IOUAmount{5196152422706634, -9})); + env.close(); + + auto aliceXrpBalance = env.balance(alice, XRP); + auto bobXrpBalance = env.balance(bob, XRP); + + // gw clawback 500 USD from alice in amm + env(amm::ammClawback(gw, alice, USD, XRP, USD(500)), + ter(tesSUCCESS)); + env.close(); + + // Alice's initial balance for USD is 6000 USD. Alice deposited 1000 + // USD into the pool, then she has 5000 USD. And 500 USD was clawed + // back from the AMM pool, so she still has 5000 USD. + env.require(balance(alice, gw["USD"](5000))); + + // Bob's balance is not changed. + env.require(balance(bob, gw["USD"](4000))); + + // Alice gets 1000 XRP back. + BEAST_EXPECT( + expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(1000))); + + BEAST_EXPECT(amm.expectBalances( + USD(2500), XRP(5000), IOUAmount{3535533905932738, -9})); + BEAST_EXPECT( + amm.expectLPTokens(alice, IOUAmount{7071067811865480, -10})); + BEAST_EXPECT( + amm.expectLPTokens(bob, IOUAmount{1414213562373095, -9})); + + // gw clawback 10 USD from bob in amm. + env(amm::ammClawback(gw, bob, USD, XRP, USD(10)), ter(tesSUCCESS)); + env.close(); + + env.require(balance(alice, gw["USD"](5000))); + env.require(balance(bob, gw["USD"](4000))); + + // Bob gets 20 XRP back. + BEAST_EXPECT( + expectLedgerEntryRoot(env, bob, bobXrpBalance + XRP(20))); + BEAST_EXPECT(amm.expectBalances( + STAmount{USD, UINT64_C(2490000000000001), -12}, + XRP(4980), + IOUAmount{3521391770309008, -9})); + BEAST_EXPECT( + amm.expectLPTokens(alice, IOUAmount{7071067811865480, -10})); + BEAST_EXPECT( + amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9})); + + // gw2 clawback 200 EUR from amm2. + env(amm::ammClawback(gw2, alice, EUR, XRP, EUR(200)), + ter(tesSUCCESS)); + env.close(); + + env.require(balance(alice, gw2["EUR"](4000))); + env.require(balance(bob, gw2["EUR"](3000))); + + // Alice gets 600 XRP back. + BEAST_EXPECT(expectLedgerEntryRoot( + env, alice, aliceXrpBalance + XRP(1000) + XRP(600))); + BEAST_EXPECT(amm2.expectBalances( + EUR(2800), XRP(8400), IOUAmount{4849742261192859, -9})); + BEAST_EXPECT( + amm2.expectLPTokens(alice, IOUAmount{1385640646055103, -9})); + BEAST_EXPECT( + amm2.expectLPTokens(bob, IOUAmount{1732050807568878, -9})); + + // gw claw back 1000 USD from alice in amm, which exceeds alice's + // balance. This will clawback all the remaining LP tokens of alice + // (corresponding 500 USD / 1000 XRP). + env(amm::ammClawback(gw, alice, USD, XRP, USD(1000)), + ter(tesSUCCESS)); + env.close(); + + env.require(balance(alice, gw["USD"](5000))); + env.require(balance(bob, gw["USD"](4000))); + + // Alice gets 1000 XRP back. + BEAST_EXPECT(expectLedgerEntryRoot( + env, + alice, + aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000))); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0))); + BEAST_EXPECT( + amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9})); + BEAST_EXPECT(amm.expectBalances( + STAmount{USD, UINT64_C(1990000000000001), -12}, + XRP(3980), + IOUAmount{2814284989122460, -9})); + + // gw clawback 1000 USD from bob in amm, which also exceeds bob's + // balance in amm. All bob's lptoken in amm will be consumed, which + // corresponds to 990 USD / 1980 XRP + env(amm::ammClawback(gw, bob, USD, XRP, USD(1000)), + ter(tesSUCCESS)); + env.close(); + + env.require(balance(alice, gw["USD"](5000))); + env.require(balance(bob, gw["USD"](4000))); + + BEAST_EXPECT(expectLedgerEntryRoot( + env, + alice, + aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000))); + BEAST_EXPECT(expectLedgerEntryRoot( + env, bob, bobXrpBalance + XRP(20) + XRP(1980))); + + // Now neither alice nor bob has any lptoken in amm. + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0))); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(0))); + + // gw2 claw back 1000 EUR from alice in amm2, which exceeds alice's + // balance. All alice's lptokens will be consumed, which corresponds + // to 800EUR / 2400 XRP. + env(amm::ammClawback(gw2, alice, EUR, XRP, EUR(1000)), + ter(tesSUCCESS)); + env.close(); + + env.require(balance(alice, gw2["EUR"](4000))); + env.require(balance(bob, gw2["EUR"](3000))); + + // Alice gets another 2400 XRP back, bob's XRP balance remains the + // same. + BEAST_EXPECT(expectLedgerEntryRoot( + env, + alice, + aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000) + + XRP(2400))); + BEAST_EXPECT(expectLedgerEntryRoot( + env, bob, bobXrpBalance + XRP(20) + XRP(1980))); + + // Alice now does not have any lptoken in amm2 + BEAST_EXPECT(amm2.expectLPTokens(alice, IOUAmount(0))); + + BEAST_EXPECT(amm2.expectBalances( + EUR(2000), XRP(6000), IOUAmount{3464101615137756, -9})); + + // gw2 claw back 2000 EUR from bib in amm2, which exceeds bob's + // balance. All bob's lptokens will be consumed, which corresponds + // to 1000EUR / 3000 XRP. + env(amm::ammClawback(gw2, bob, EUR, XRP, EUR(2000)), + ter(tesSUCCESS)); + env.close(); + + env.require(balance(alice, gw2["EUR"](4000))); + env.require(balance(bob, gw2["EUR"](3000))); + + // Bob gets another 3000 XRP back. Alice's XRP balance remains the + // same. + BEAST_EXPECT(expectLedgerEntryRoot( + env, + alice, + aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000) + + XRP(2400))); + BEAST_EXPECT(expectLedgerEntryRoot( + env, bob, bobXrpBalance + XRP(20) + XRP(1980) + XRP(3000))); + + // Neither alice nor bob has any lptoken in amm2 + BEAST_EXPECT(amm2.expectLPTokens(alice, IOUAmount(0))); + BEAST_EXPECT(amm2.expectLPTokens(bob, IOUAmount(0))); + + BEAST_EXPECT(amm2.expectBalances( + EUR(1000), XRP(3000), IOUAmount{1732050807568878, -9})); + } + } + + void + testAMMClawbackAll(FeatureBitset features) + { + testcase("test AMMClawback all the tokens in the AMM pool"); + using namespace jtx; + + // Test AMMClawback for USD/EUR pool. The assets are issued by different + // issuer. Claw back all the USD for different users. + { + Env env(*this, features); + Account gw{"gateway"}; + Account gw2{"gateway2"}; + Account alice{"alice"}; + Account bob{"bob"}; + Account carol{"carol"}; + env.fund(XRP(1000000), gw, gw2, alice, bob, carol); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw2 sets asfAllowTrustLineClawback. + env(fset(gw2, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw2, asfAllowTrustLineClawback)); + + // gw issues 6000 USD to Alice, 5000 USD to Bob, and 4000 USD + // to Carol. + auto const USD = gw["USD"]; + env.trust(USD(100000), alice); + env(pay(gw, alice, USD(6000))); + env.trust(USD(100000), bob); + env(pay(gw, bob, USD(5000))); + env.trust(USD(100000), carol); + env(pay(gw, carol, USD(4000))); + env.close(); + + // gw2 issues 6000 EUR to Alice and 5000 EUR to Bob and 4000 + // EUR to Carol. + auto const EUR = gw2["EUR"]; + env.trust(EUR(100000), alice); + env(pay(gw2, alice, EUR(6000))); + env.trust(EUR(100000), bob); + env(pay(gw2, bob, EUR(5000))); + env.trust(EUR(100000), carol); + env(pay(gw2, carol, EUR(4000))); + env.close(); + + // Alice creates AMM pool of EUR/USD + AMM amm(env, alice, EUR(5000), USD(4000), ter(tesSUCCESS)); + env.close(); + + BEAST_EXPECT(amm.expectBalances( + USD(4000), EUR(5000), IOUAmount{4472135954999580, -12})); + amm.deposit(bob, USD(2000), EUR(2500)); + BEAST_EXPECT(amm.expectBalances( + USD(6000), EUR(7500), IOUAmount{6708203932499370, -12})); + amm.deposit(carol, USD(1000), EUR(1250)); + BEAST_EXPECT(amm.expectBalances( + USD(7000), EUR(8750), IOUAmount{7826237921249265, -12})); + + BEAST_EXPECT( + amm.expectLPTokens(alice, IOUAmount{4472135954999580, -12})); + BEAST_EXPECT( + amm.expectLPTokens(bob, IOUAmount{2236067977499790, -12})); + BEAST_EXPECT( + amm.expectLPTokens(carol, IOUAmount{1118033988749895, -12})); + + env.require(balance(alice, gw["USD"](2000))); + env.require(balance(alice, gw2["EUR"](1000))); + env.require(balance(bob, gw["USD"](3000))); + env.require(balance(bob, gw2["EUR"](2500))); + env.require(balance(carol, gw["USD"](3000))); + env.require(balance(carol, gw2["EUR"](2750))); + + // gw clawback all the bob's USD in amm. (2000 USD / 2500 EUR) + env(amm::ammClawback(gw, bob, USD, EUR, std::nullopt), + ter(tesSUCCESS)); + env.close(); + + BEAST_EXPECT(amm.expectBalances( + STAmount{USD, UINT64_C(4999999999999999), -12}, + STAmount{EUR, UINT64_C(6249999999999999), -12}, + IOUAmount{5590169943749475, -12})); + + BEAST_EXPECT( + amm.expectLPTokens(alice, IOUAmount{4472135954999580, -12})); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(0))); + BEAST_EXPECT( + amm.expectLPTokens(carol, IOUAmount{1118033988749895, -12})); + + // Bob will get 2500 EUR back. + env.require(balance(alice, gw["USD"](2000))); + env.require(balance(alice, gw2["EUR"](1000))); + BEAST_EXPECT( + env.balance(bob, USD) == + STAmount(USD, UINT64_C(3000000000000000), -12)); + + BEAST_EXPECT( + env.balance(bob, EUR) == + STAmount(EUR, UINT64_C(5000000000000001), -12)); + env.require(balance(carol, gw["USD"](3000))); + env.require(balance(carol, gw2["EUR"](2750))); + + // gw2 clawback all carol's EUR in amm. (1000 USD / 1250 EUR) + env(amm::ammClawback(gw2, carol, EUR, USD, std::nullopt), + ter(tesSUCCESS)); + env.close(); + BEAST_EXPECT(amm.expectBalances( + STAmount{USD, UINT64_C(3999999999999999), -12}, + STAmount{EUR, UINT64_C(4999999999999999), -12}, + IOUAmount{4472135954999580, -12})); + + BEAST_EXPECT( + amm.expectLPTokens(alice, IOUAmount{4472135954999580, -12})); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(0))); + BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount(0))); + + // gw2 clawback all alice's EUR in amm. (4000 USD / 5000 EUR) + env(amm::ammClawback(gw2, alice, EUR, USD, std::nullopt), + ter(tesSUCCESS)); + env.close(); + + env.require(balance(carol, gw2["EUR"](2750))); + env.require(balance(carol, gw["USD"](4000))); + BEAST_EXPECT(!amm.ammExists()); + } + + // Test AMMClawback for USD/XRP pool. Claw back all the USD for + // different users. + { + Env env(*this, features); + Account gw{"gateway"}; + Account alice{"alice"}; + Account bob{"bob"}; + env.fund(XRP(1000000), gw, alice, bob); + env.close(); + + // gw sets asfAllowTrustLineClawback + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw issues 600000 USD to Alice and 500000 USD to Bob. + auto const USD = gw["USD"]; + env.trust(USD(1000000), alice); + env(pay(gw, alice, USD(600000))); + env.trust(USD(1000000), bob); + env(pay(gw, bob, USD(500000))); + env.close(); + + // gw creates AMM pool of XRP/USD, alice and bob deposit XRP/USD. + AMM amm(env, gw, XRP(2000), USD(10000), ter(tesSUCCESS)); + BEAST_EXPECT(amm.expectBalances( + USD(10000), XRP(2000), IOUAmount{4472135954999580, -9})); + amm.deposit(alice, USD(1000), XRP(200)); + BEAST_EXPECT(amm.expectBalances( + USD(11000), XRP(2200), IOUAmount{4919349550499538, -9})); + amm.deposit(bob, USD(2000), XRP(400)); + BEAST_EXPECT(amm.expectBalances( + USD(13000), XRP(2600), IOUAmount{5813776741499453, -9})); + env.close(); + + auto aliceXrpBalance = env.balance(alice, XRP); + auto bobXrpBalance = env.balance(bob, XRP); + + // gw clawback all alice's USD in amm. (1000 USD / 200 XRP) + env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), + ter(tesSUCCESS)); + env.close(); + BEAST_EXPECT(amm.expectBalances( + USD(12000), XRP(2400), IOUAmount{5366563145999495, -9})); + BEAST_EXPECT( + expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(200))); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0))); + + // gw clawback all bob's USD in amm. (2000 USD / 400 XRP) + env(amm::ammClawback(gw, bob, USD, XRP, std::nullopt), + ter(tesSUCCESS)); + env.close(); + BEAST_EXPECT(amm.expectBalances( + USD(10000), XRP(2000), IOUAmount{4472135954999580, -9})); + BEAST_EXPECT( + expectLedgerEntryRoot(env, bob, bobXrpBalance + XRP(400))); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0))); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(0))); + } + } + + void + testAMMClawbackSameIssuerAssets(FeatureBitset features) + { + testcase( + "test AMMClawback from AMM pool with assets having the same " + "issuer"); + using namespace jtx; + + // Test AMMClawback for USD/EUR pool. The assets are issued by different + // issuer. Claw back all the USD for different users. + Env env(*this, features); + Account gw{"gateway"}; + Account alice{"alice"}; + Account bob{"bob"}; + Account carol{"carol"}; + env.fund(XRP(1000000), gw, alice, bob, carol); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + auto const USD = gw["USD"]; + env.trust(USD(100000), alice); + env(pay(gw, alice, USD(10000))); + env.trust(USD(100000), bob); + env(pay(gw, bob, USD(9000))); + env.trust(USD(100000), carol); + env(pay(gw, carol, USD(8000))); + env.close(); + + auto const EUR = gw["EUR"]; + env.trust(EUR(100000), alice); + env(pay(gw, alice, EUR(10000))); + env.trust(EUR(100000), bob); + env(pay(gw, bob, EUR(9000))); + env.trust(EUR(100000), carol); + env(pay(gw, carol, EUR(8000))); + env.close(); + + AMM amm(env, alice, EUR(2000), USD(8000), ter(tesSUCCESS)); + env.close(); + + BEAST_EXPECT(amm.expectBalances(USD(8000), EUR(2000), IOUAmount(4000))); + amm.deposit(bob, USD(4000), EUR(1000)); + BEAST_EXPECT( + amm.expectBalances(USD(12000), EUR(3000), IOUAmount(6000))); + amm.deposit(carol, USD(2000), EUR(500)); + BEAST_EXPECT( + amm.expectBalances(USD(14000), EUR(3500), IOUAmount(7000))); + + // gw clawback 1000 USD from carol. + env(amm::ammClawback(gw, carol, USD, EUR, USD(1000)), ter(tesSUCCESS)); + env.close(); + BEAST_EXPECT( + amm.expectBalances(USD(13000), EUR(3250), IOUAmount(6500))); + + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(4000))); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(2000))); + BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount(500))); + BEAST_EXPECT(env.balance(alice, USD) == USD(2000)); + BEAST_EXPECT(env.balance(alice, EUR) == EUR(8000)); + BEAST_EXPECT(env.balance(bob, USD) == USD(5000)); + BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000)); + BEAST_EXPECT(env.balance(carol, USD) == USD(6000)); + // 250 EUR goes back to carol. + BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750)); + + // gw clawback 1000 USD from bob with tfClawTwoAssets flag. + // then the corresponding EUR will also be clawed back + // by gw. + env(amm::ammClawback(gw, bob, USD, EUR, USD(1000)), + txflags(tfClawTwoAssets), + ter(tesSUCCESS)); + env.close(); + BEAST_EXPECT( + amm.expectBalances(USD(12000), EUR(3000), IOUAmount(6000))); + + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(4000))); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(1500))); + BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount(500))); + BEAST_EXPECT(env.balance(alice, USD) == USD(2000)); + BEAST_EXPECT(env.balance(alice, EUR) == EUR(8000)); + BEAST_EXPECT(env.balance(bob, USD) == USD(5000)); + // 250 EUR did not go back to bob because tfClawTwoAssets is set. + BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000)); + BEAST_EXPECT(env.balance(carol, USD) == USD(6000)); + BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750)); + + // gw clawback all USD from alice and set tfClawTwoAssets. + env(amm::ammClawback(gw, alice, USD, EUR, std::nullopt), + txflags(tfClawTwoAssets), + ter(tesSUCCESS)); + env.close(); + BEAST_EXPECT(amm.expectBalances(USD(4000), EUR(1000), IOUAmount(2000))); + + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0))); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(1500))); + BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount(500))); + BEAST_EXPECT(env.balance(alice, USD) == USD(2000)); + BEAST_EXPECT(env.balance(alice, EUR) == EUR(8000)); + BEAST_EXPECT(env.balance(bob, USD) == USD(5000)); + BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000)); + BEAST_EXPECT(env.balance(carol, USD) == USD(6000)); + BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750)); + } + + void + testAMMClawbackSameCurrency(FeatureBitset features) + { + testcase( + "test AMMClawback from AMM pool with assets having the same " + "currency, but from different issuer"); + using namespace jtx; + + // Test AMMClawback for USD/EUR pool. The assets are issued by different + // issuer. Claw back all the USD for different users. + Env env(*this, features); + Account gw{"gateway"}; + Account gw2{"gateway2"}; + Account alice{"alice"}; + Account bob{"bob"}; + env.fund(XRP(1000000), gw, gw2, alice, bob); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw2 sets asfAllowTrustLineClawback. + env(fset(gw2, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw2, asfAllowTrustLineClawback)); + + env.trust(gw["USD"](100000), alice); + env(pay(gw, alice, gw["USD"](8000))); + env.trust(gw["USD"](100000), bob); + env(pay(gw, bob, gw["USD"](7000))); + + env.trust(gw2["USD"](100000), alice); + env(pay(gw2, alice, gw2["USD"](6000))); + env.trust(gw2["USD"](100000), bob); + env(pay(gw2, bob, gw2["USD"](5000))); + env.close(); + + AMM amm(env, alice, gw["USD"](1000), gw2["USD"](1500), ter(tesSUCCESS)); + env.close(); + + BEAST_EXPECT(amm.expectBalances( + gw["USD"](1000), + gw2["USD"](1500), + IOUAmount{1224744871391589, -12})); + amm.deposit(bob, gw["USD"](2000), gw2["USD"](3000)); + BEAST_EXPECT(amm.expectBalances( + gw["USD"](3000), + gw2["USD"](4500), + IOUAmount{3674234614174767, -12})); + + // Issuer does not match with asset. + env(amm::ammClawback( + gw, + alice, + gw2["USD"], + gw["USD"], + STAmount{Issue{gw2["USD"].currency, gw2.id()}, 500}), + ter(temMALFORMED)); + + // gw2 clawback 500 gw2[USD] from alice. + env(amm::ammClawback( + gw2, + alice, + gw2["USD"], + gw["USD"], + STAmount{Issue{gw2["USD"].currency, gw2.id()}, 500}), + ter(tesSUCCESS)); + env.close(); + BEAST_EXPECT(amm.expectBalances( + STAmount{gw["USD"], UINT64_C(2666666666666667), -12}, + gw2["USD"](4000), + IOUAmount{3265986323710904, -12})); + + BEAST_EXPECT( + amm.expectLPTokens(alice, IOUAmount{8164965809277260, -13})); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount{2449489742783178, -12})); + BEAST_EXPECT( + env.balance(alice, gw["USD"]) == + STAmount(gw["USD"], UINT64_C(7333333333333333), -12)); + BEAST_EXPECT(env.balance(alice, gw2["USD"]) == gw2["USD"](4500)); + BEAST_EXPECT(env.balance(bob, gw["USD"]) == gw["USD"](5000)); + BEAST_EXPECT(env.balance(bob, gw2["USD"]) == gw2["USD"](2000)); + + // gw clawback all gw["USD"] from bob. + env(amm::ammClawback(gw, bob, gw["USD"], gw2["USD"], std::nullopt), + ter(tesSUCCESS)); + env.close(); + BEAST_EXPECT(amm.expectBalances( + STAmount{gw["USD"], UINT64_C(6666666666666670), -13}, + gw2["USD"](1000), + IOUAmount{8164965809277260, -13})); + + BEAST_EXPECT( + amm.expectLPTokens(alice, IOUAmount{8164965809277260, -13})); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(0))); + BEAST_EXPECT( + env.balance(alice, gw["USD"]) == + STAmount(gw["USD"], UINT64_C(7333333333333333), -12)); + BEAST_EXPECT(env.balance(alice, gw2["USD"]) == gw2["USD"](4500)); + BEAST_EXPECT(env.balance(bob, gw["USD"]) == gw["USD"](5000)); + // Bob gets 3000 gw2["USD"] back and now his balance is 5000. + BEAST_EXPECT(env.balance(bob, gw2["USD"]) == gw2["USD"](5000)); + } + + void + testAMMClawbackIssuesEachOther(FeatureBitset features) + { + testcase("test AMMClawback when issuing token for each other"); + using namespace jtx; + + // gw and gw2 issues token for each other. Test AMMClawback from + // each other. + Env env(*this, features); + Account gw{"gateway"}; + Account gw2{"gateway2"}; + Account alice{"alice"}; + env.fund(XRP(1000000), gw, gw2, alice); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw2 sets asfAllowTrustLineClawback. + env(fset(gw2, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw2, asfAllowTrustLineClawback)); + + auto const USD = gw["USD"]; + env.trust(USD(100000), gw2); + env(pay(gw, gw2, USD(5000))); + env.trust(USD(100000), alice); + env(pay(gw, alice, USD(5000))); + + auto const EUR = gw2["EUR"]; + env.trust(EUR(100000), gw); + env(pay(gw2, gw, EUR(6000))); + env.trust(EUR(100000), alice); + env(pay(gw2, alice, EUR(6000))); + env.close(); + + AMM amm(env, gw, USD(1000), EUR(2000), ter(tesSUCCESS)); + env.close(); + BEAST_EXPECT(amm.expectBalances( + USD(1000), EUR(2000), IOUAmount{1414213562373095, -12})); + + amm.deposit(gw2, USD(2000), EUR(4000)); + BEAST_EXPECT(amm.expectBalances( + USD(3000), EUR(6000), IOUAmount{4242640687119285, -12})); + + amm.deposit(alice, USD(3000), EUR(6000)); + BEAST_EXPECT(amm.expectBalances( + USD(6000), EUR(12000), IOUAmount{8485281374238570, -12})); + + BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{1414213562373095, -12})); + BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{2828427124746190, -12})); + BEAST_EXPECT( + amm.expectLPTokens(alice, IOUAmount{4242640687119285, -12})); + + // gw claws back 1000 USD from gw2. + env(amm::ammClawback(gw, gw2, USD, EUR, USD(1000)), ter(tesSUCCESS)); + env.close(); + BEAST_EXPECT(amm.expectBalances( + USD(5000), EUR(10000), IOUAmount{7071067811865475, -12})); + + BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{1414213562373095, -12})); + BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12})); + BEAST_EXPECT( + amm.expectLPTokens(alice, IOUAmount{4242640687119285, -12})); + + BEAST_EXPECT(env.balance(alice, USD) == USD(2000)); + BEAST_EXPECT(env.balance(alice, EUR) == EUR(0)); + BEAST_EXPECT(env.balance(gw, EUR) == EUR(4000)); + BEAST_EXPECT(env.balance(gw2, USD) == USD(3000)); + + // gw2 claws back 1000 EUR from gw. + env(amm::ammClawback(gw2, gw, EUR, USD, EUR(1000)), ter(tesSUCCESS)); + env.close(); + BEAST_EXPECT(amm.expectBalances( + USD(4500), + STAmount(EUR, UINT64_C(9000000000000001), -12), + IOUAmount{6363961030678928, -12})); + + BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13})); + BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12})); + BEAST_EXPECT( + amm.expectLPTokens(alice, IOUAmount{4242640687119285, -12})); + + BEAST_EXPECT(env.balance(alice, USD) == USD(2000)); + BEAST_EXPECT(env.balance(alice, EUR) == EUR(0)); + BEAST_EXPECT(env.balance(gw, EUR) == EUR(4000)); + BEAST_EXPECT(env.balance(gw2, USD) == USD(3000)); + + // gw2 claws back 4000 EUR from alice. + env(amm::ammClawback(gw2, alice, EUR, USD, EUR(4000)), ter(tesSUCCESS)); + env.close(); + BEAST_EXPECT(amm.expectBalances( + USD(2500), + STAmount(EUR, UINT64_C(5000000000000001), -12), + IOUAmount{3535533905932738, -12})); + + BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13})); + BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12})); + BEAST_EXPECT( + amm.expectLPTokens(alice, IOUAmount{1414213562373095, -12})); + + BEAST_EXPECT(env.balance(alice, USD) == USD(4000)); + BEAST_EXPECT(env.balance(alice, EUR) == EUR(0)); + BEAST_EXPECT(env.balance(gw, EUR) == EUR(4000)); + BEAST_EXPECT(env.balance(gw2, USD) == USD(3000)); + } + + void + testNotHoldingLptoken(FeatureBitset features) + { + testcase( + "test AMMClawback from account which does not own any lptoken in " + "the pool"); + using namespace jtx; + + Env env(*this, features); + Account gw{"gateway"}; + Account alice{"alice"}; + env.fund(XRP(1000000), gw, alice); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + auto const USD = gw["USD"]; + env.trust(USD(100000), alice); + env(pay(gw, alice, USD(5000))); + + AMM amm(env, gw, USD(1000), XRP(2000), ter(tesSUCCESS)); + env.close(); + + // Alice did not deposit in the amm pool. So AMMClawback from Alice + // will fail. + env(amm::ammClawback(gw, alice, USD, XRP, USD(1000)), + ter(tecAMM_BALANCE)); + } + + void + testAssetFrozen(FeatureBitset features) + { + testcase("test assets frozen"); + using namespace jtx; + + // test individually frozen trustline. + { + Env env(*this, features); + Account gw{"gateway"}; + Account gw2{"gateway2"}; + Account alice{"alice"}; + env.fund(XRP(1000000), gw, gw2, alice); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw issues 3000 USD to Alice. + auto const USD = gw["USD"]; + env.trust(USD(100000), alice); + env(pay(gw, alice, USD(3000))); + env.close(); + env.require(balance(alice, gw["USD"](3000))); + + // gw2 issues 3000 EUR to Alice. + auto const EUR = gw2["EUR"]; + env.trust(EUR(100000), alice); + env(pay(gw2, alice, EUR(3000))); + env.close(); + env.require(balance(alice, gw2["EUR"](3000))); + + // Alice creates AMM pool of EUR/USD. + AMM amm(env, alice, EUR(1000), USD(2000), ter(tesSUCCESS)); + env.close(); + + BEAST_EXPECT(amm.expectBalances( + USD(2000), EUR(1000), IOUAmount{1414213562373095, -12})); + + // freeze trustline + env(trust(gw, alice["USD"](0), tfSetFreeze)); + env.close(); + + // gw clawback 1000 USD from the AMM pool. + env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), + ter(tesSUCCESS)); + env.close(); + + env.require(balance(alice, gw["USD"](1000))); + env.require(balance(alice, gw2["EUR"](2500))); + BEAST_EXPECT(amm.expectBalances( + USD(1000), EUR(500), IOUAmount{7071067811865475, -13})); + + // Alice has half of its initial lptokens Left. + BEAST_EXPECT( + amm.expectLPTokens(alice, IOUAmount{7071067811865475, -13})); + + // gw clawback another 1000 USD from the AMM pool. The AMM pool will + // be empty and get deleted. + env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), + ter(tesSUCCESS)); + env.close(); + + // Alice should still has 1000 USD because gw clawed back from the + // AMM pool. + env.require(balance(alice, gw["USD"](1000))); + env.require(balance(alice, gw2["EUR"](3000))); + + // amm is automatically deleted. + BEAST_EXPECT(!amm.ammExists()); + } + + // test individually frozen trustline of both USD and EUR currency. + { + Env env(*this, features); + Account gw{"gateway"}; + Account gw2{"gateway2"}; + Account alice{"alice"}; + env.fund(XRP(1000000), gw, gw2, alice); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw issues 3000 USD to Alice. + auto const USD = gw["USD"]; + env.trust(USD(100000), alice); + env(pay(gw, alice, USD(3000))); + env.close(); + env.require(balance(alice, gw["USD"](3000))); + + // gw2 issues 3000 EUR to Alice. + auto const EUR = gw2["EUR"]; + env.trust(EUR(100000), alice); + env(pay(gw2, alice, EUR(3000))); + env.close(); + env.require(balance(alice, gw2["EUR"](3000))); + + // Alice creates AMM pool of EUR/USD. + AMM amm(env, alice, EUR(1000), USD(2000), ter(tesSUCCESS)); + env.close(); + + BEAST_EXPECT(amm.expectBalances( + USD(2000), EUR(1000), IOUAmount{1414213562373095, -12})); + + // freeze trustlines + env(trust(gw, alice["USD"](0), tfSetFreeze)); + env(trust(gw2, alice["EUR"](0), tfSetFreeze)); + env.close(); + + // gw clawback 1000 USD from the AMM pool. + env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), + ter(tesSUCCESS)); + env.close(); + + env.require(balance(alice, gw["USD"](1000))); + env.require(balance(alice, gw2["EUR"](2500))); + BEAST_EXPECT(amm.expectBalances( + USD(1000), EUR(500), IOUAmount{7071067811865475, -13})); + BEAST_EXPECT( + amm.expectLPTokens(alice, IOUAmount{7071067811865475, -13})); + } + + // test gw global freeze. + { + Env env(*this, features); + Account gw{"gateway"}; + Account gw2{"gateway2"}; + Account alice{"alice"}; + env.fund(XRP(1000000), gw, gw2, alice); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw issues 3000 USD to Alice. + auto const USD = gw["USD"]; + env.trust(USD(100000), alice); + env(pay(gw, alice, USD(3000))); + env.close(); + env.require(balance(alice, gw["USD"](3000))); + + // gw2 issues 3000 EUR to Alice. + auto const EUR = gw2["EUR"]; + env.trust(EUR(100000), alice); + env(pay(gw2, alice, EUR(3000))); + env.close(); + env.require(balance(alice, gw2["EUR"](3000))); + + // Alice creates AMM pool of EUR/USD. + AMM amm(env, alice, EUR(1000), USD(2000), ter(tesSUCCESS)); + env.close(); + + BEAST_EXPECT(amm.expectBalances( + USD(2000), EUR(1000), IOUAmount{1414213562373095, -12})); + + // global freeze + env(fset(gw, asfGlobalFreeze)); + env.close(); + + // gw clawback 1000 USD from the AMM pool. + env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)), + ter(tesSUCCESS)); + env.close(); + + env.require(balance(alice, gw["USD"](1000))); + env.require(balance(alice, gw2["EUR"](2500))); + BEAST_EXPECT(amm.expectBalances( + USD(1000), EUR(500), IOUAmount{7071067811865475, -13})); + BEAST_EXPECT( + amm.expectLPTokens(alice, IOUAmount{7071067811865475, -13})); + } + + // Test both assets are issued by the same issuer. And issuer sets + // global freeze. + { + Env env(*this, features); + Account gw{"gateway"}; + Account alice{"alice"}; + Account bob{"bob"}; + Account carol{"carol"}; + env.fund(XRP(1000000), gw, alice, bob, carol); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + auto const USD = gw["USD"]; + env.trust(USD(100000), alice); + env(pay(gw, alice, USD(10000))); + env.trust(USD(100000), bob); + env(pay(gw, bob, USD(9000))); + env.trust(USD(100000), carol); + env(pay(gw, carol, USD(8000))); + env.close(); + + auto const EUR = gw["EUR"]; + env.trust(EUR(100000), alice); + env(pay(gw, alice, EUR(10000))); + env.trust(EUR(100000), bob); + env(pay(gw, bob, EUR(9000))); + env.trust(EUR(100000), carol); + env(pay(gw, carol, EUR(8000))); + env.close(); + + AMM amm(env, alice, EUR(2000), USD(8000), ter(tesSUCCESS)); + env.close(); + + BEAST_EXPECT( + amm.expectBalances(USD(8000), EUR(2000), IOUAmount(4000))); + amm.deposit(bob, USD(4000), EUR(1000)); + BEAST_EXPECT( + amm.expectBalances(USD(12000), EUR(3000), IOUAmount(6000))); + amm.deposit(carol, USD(2000), EUR(500)); + BEAST_EXPECT( + amm.expectBalances(USD(14000), EUR(3500), IOUAmount(7000))); + + // global freeze + env(fset(gw, asfGlobalFreeze)); + env.close(); + + // gw clawback 1000 USD from carol. + env(amm::ammClawback(gw, carol, USD, EUR, USD(1000)), + ter(tesSUCCESS)); + env.close(); + BEAST_EXPECT( + amm.expectBalances(USD(13000), EUR(3250), IOUAmount(6500))); + + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(4000))); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(2000))); + BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount(500))); + BEAST_EXPECT(env.balance(alice, USD) == USD(2000)); + BEAST_EXPECT(env.balance(alice, EUR) == EUR(8000)); + BEAST_EXPECT(env.balance(bob, USD) == USD(5000)); + BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000)); + BEAST_EXPECT(env.balance(carol, USD) == USD(6000)); + // 250 EUR goes back to carol. + BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750)); + + // gw clawback 1000 USD from bob with tfClawTwoAssets flag. + // then the corresponding EUR will also be clawed back + // by gw. + env(amm::ammClawback(gw, bob, USD, EUR, USD(1000)), + txflags(tfClawTwoAssets), + ter(tesSUCCESS)); + env.close(); + BEAST_EXPECT( + amm.expectBalances(USD(12000), EUR(3000), IOUAmount(6000))); + + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(4000))); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(1500))); + BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount(500))); + BEAST_EXPECT(env.balance(alice, USD) == USD(2000)); + BEAST_EXPECT(env.balance(alice, EUR) == EUR(8000)); + BEAST_EXPECT(env.balance(bob, USD) == USD(5000)); + // 250 EUR did not go back to bob because tfClawTwoAssets is set. + BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000)); + BEAST_EXPECT(env.balance(carol, USD) == USD(6000)); + BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750)); + + // gw clawback all USD from alice and set tfClawTwoAssets. + env(amm::ammClawback(gw, alice, USD, EUR, std::nullopt), + txflags(tfClawTwoAssets), + ter(tesSUCCESS)); + env.close(); + BEAST_EXPECT( + amm.expectBalances(USD(4000), EUR(1000), IOUAmount(2000))); + + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0))); + BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(1500))); + BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount(500))); + BEAST_EXPECT(env.balance(alice, USD) == USD(2000)); + BEAST_EXPECT(env.balance(alice, EUR) == EUR(8000)); + BEAST_EXPECT(env.balance(bob, USD) == USD(5000)); + BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000)); + BEAST_EXPECT(env.balance(carol, USD) == USD(6000)); + BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750)); + } + } + + void + testSingleDepositAndClawback(FeatureBitset features) + { + testcase("test single depoit and clawback"); + using namespace jtx; + + // Test AMMClawback for USD/XRP pool. Claw back USD, and XRP goes back + // to the holder. + Env env(*this, features); + Account gw{"gateway"}; + Account alice{"alice"}; + env.fund(XRP(1000000000), gw, alice); + env.close(); + + // gw sets asfAllowTrustLineClawback. + env(fset(gw, asfAllowTrustLineClawback)); + env.close(); + env.require(flags(gw, asfAllowTrustLineClawback)); + + // gw issues 1000 USD to Alice. + auto const USD = gw["USD"]; + env.trust(USD(100000), alice); + env(pay(gw, alice, USD(1000))); + env.close(); + env.require(balance(alice, gw["USD"](1000))); + + // gw creates AMM pool of XRP/USD. + AMM amm(env, gw, XRP(100), USD(400), ter(tesSUCCESS)); + env.close(); + + BEAST_EXPECT(amm.expectBalances(USD(400), XRP(100), IOUAmount(200000))); + + amm.deposit(alice, USD(400)); + env.close(); + + BEAST_EXPECT(amm.expectBalances( + USD(800), XRP(100), IOUAmount{2828427124746190, -10})); + + auto aliceXrpBalance = env.balance(alice, XRP); + + env(amm::ammClawback(gw, alice, USD, XRP, USD(400)), ter(tesSUCCESS)); + env.close(); + + BEAST_EXPECT(amm.expectBalances( + STAmount(USD, UINT64_C(5656854249492380), -13), + XRP(70.710678), + IOUAmount(200000))); + BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0))); + BEAST_EXPECT(expectLedgerEntryRoot( + env, alice, aliceXrpBalance + XRP(29.289322))); + } + + void + run() override + { + FeatureBitset const all{jtx::supported_amendments()}; + testInvalidRequest(all); + testFeatureDisabled(all - featureAMMClawback); + testAMMClawbackSpecificAmount(all); + testAMMClawbackExceedBalance(all); + testAMMClawbackAll(all); + testAMMClawbackSameIssuerAssets(all); + testAMMClawbackSameCurrency(all); + testAMMClawbackIssuesEachOther(all); + testNotHoldingLptoken(all); + testAssetFrozen(all); + testSingleDepositAndClawback(all); + } +}; +BEAST_DEFINE_TESTSUITE(AMMClawback, app, ripple); +} // namespace test +} // namespace ripple diff --git a/src/test/app/AMM_test.cpp b/src/test/app/AMM_test.cpp index ceddc019504..8e764390e9a 100644 --- a/src/test/app/AMM_test.cpp +++ b/src/test/app/AMM_test.cpp @@ -416,25 +416,10 @@ struct AMM_test : public jtx::AMMTest AMM ammAlice1( env, alice, USD(10'000), USD1(10'000), ter(terNO_RIPPLE)); } - - // Issuer has clawback enabled - { - Env env(*this); - env.fund(XRP(1'000), gw); - env(fset(gw, asfAllowTrustLineClawback)); - fund(env, gw, {alice}, XRP(1'000), {USD(1'000)}, Fund::Acct); - env.close(); - AMM amm(env, gw, XRP(100), USD(100), ter(tecNO_PERMISSION)); - AMM amm1(env, alice, USD(100), XRP(100), ter(tecNO_PERMISSION)); - env(fclear(gw, asfAllowTrustLineClawback)); - env.close(); - // Can't be cleared - AMM amm2(env, gw, XRP(100), USD(100), ter(tecNO_PERMISSION)); - } } void - testInvalidDeposit() + testInvalidDeposit(FeatureBitset features) { testcase("Invalid Deposit"); @@ -869,62 +854,112 @@ struct AMM_test : public jtx::AMMTest }); // Globally frozen asset - testAMM([&](AMM& ammAlice, Env& env) { - env(fset(gw, asfGlobalFreeze)); - // Can deposit non-frozen token - ammAlice.deposit(carol, XRP(100)); - ammAlice.deposit( - carol, - USD(100), - std::nullopt, - std::nullopt, - std::nullopt, - ter(tecFROZEN)); - ammAlice.deposit( - carol, 1'000'000, std::nullopt, std::nullopt, ter(tecFROZEN)); - ammAlice.deposit( - carol, - XRP(100), - USD(100), - std::nullopt, - std::nullopt, - ter(tecFROZEN)); - }); + testAMM( + [&](AMM& ammAlice, Env& env) { + env(fset(gw, asfGlobalFreeze)); + if (!features[featureAMMClawback]) + // If the issuer set global freeze, the holder still can + // deposit the other non-frozen token when AMMClawback is + // not enabled. + ammAlice.deposit(carol, XRP(100)); + else + // If the issuer set global freeze, the holder cannot + // deposit the other non-frozen token when AMMClawback is + // enabled. + ammAlice.deposit( + carol, + XRP(100), + std::nullopt, + std::nullopt, + std::nullopt, + ter(tecFROZEN)); + ammAlice.deposit( + carol, + USD(100), + std::nullopt, + std::nullopt, + std::nullopt, + ter(tecFROZEN)); + ammAlice.deposit( + carol, + 1'000'000, + std::nullopt, + std::nullopt, + ter(tecFROZEN)); + ammAlice.deposit( + carol, + XRP(100), + USD(100), + std::nullopt, + std::nullopt, + ter(tecFROZEN)); + }, + std::nullopt, + 0, + std::nullopt, + {features}); // Individually frozen (AMM) account - testAMM([&](AMM& ammAlice, Env& env) { - env(trust(gw, carol["USD"](0), tfSetFreeze)); - env.close(); - // Can deposit non-frozen token - ammAlice.deposit(carol, XRP(100)); - ammAlice.deposit( - carol, 1'000'000, std::nullopt, std::nullopt, ter(tecFROZEN)); - ammAlice.deposit( - carol, - USD(100), - std::nullopt, - std::nullopt, - std::nullopt, - ter(tecFROZEN)); - env(trust(gw, carol["USD"](0), tfClearFreeze)); - // Individually frozen AMM - env(trust( - gw, - STAmount{Issue{gw["USD"].currency, ammAlice.ammAccount()}, 0}, - tfSetFreeze)); - env.close(); - // Can deposit non-frozen token - ammAlice.deposit(carol, XRP(100)); - ammAlice.deposit( - carol, 1'000'000, std::nullopt, std::nullopt, ter(tecFROZEN)); - ammAlice.deposit( - carol, - USD(100), - std::nullopt, - std::nullopt, - std::nullopt, - ter(tecFROZEN)); - }); + testAMM( + [&](AMM& ammAlice, Env& env) { + env(trust(gw, carol["USD"](0), tfSetFreeze)); + env.close(); + if (!features[featureAMMClawback]) + // Can deposit non-frozen token if AMMClawback is not + // enabled + ammAlice.deposit(carol, XRP(100)); + else + // Cannot deposit non-frozen token if the other token is + // frozen when AMMClawback is enabled + ammAlice.deposit( + carol, + XRP(100), + std::nullopt, + std::nullopt, + std::nullopt, + ter(tecFROZEN)); + + ammAlice.deposit( + carol, + 1'000'000, + std::nullopt, + std::nullopt, + ter(tecFROZEN)); + ammAlice.deposit( + carol, + USD(100), + std::nullopt, + std::nullopt, + std::nullopt, + ter(tecFROZEN)); + env(trust(gw, carol["USD"](0), tfClearFreeze)); + // Individually frozen AMM + env(trust( + gw, + STAmount{ + Issue{gw["USD"].currency, ammAlice.ammAccount()}, 0}, + tfSetFreeze)); + env.close(); + // Can deposit non-frozen token + ammAlice.deposit(carol, XRP(100)); + ammAlice.deposit( + carol, + 1'000'000, + std::nullopt, + std::nullopt, + ter(tecFROZEN)); + ammAlice.deposit( + carol, + USD(100), + std::nullopt, + std::nullopt, + std::nullopt, + ter(tecFROZEN)); + }, + std::nullopt, + 0, + std::nullopt, + {features}); // Individually frozen (AMM) account with IOU/IOU AMM testAMM( @@ -970,6 +1005,44 @@ struct AMM_test : public jtx::AMMTest }, {{USD(20'000), BTC(0.5)}}); + // Deposit unauthorized token. + { + Env env(*this, features); + env.fund(XRP(1000), gw, alice, bob); + env(fset(gw, asfRequireAuth)); + env.close(); + env(trust(gw, alice["USD"](100)), txflags(tfSetfAuth)); + env(trust(alice, gw["USD"](20))); + env.close(); + env(pay(gw, alice, gw["USD"](10))); + env.close(); + env(trust(gw, bob["USD"](100))); + env.close(); + + AMM amm(env, alice, XRP(10), gw["USD"](10), ter(tesSUCCESS)); + env.close(); + + if (features[featureAMMClawback]) + // if featureAMMClawback is enabled, bob can not deposit XRP + // because he's not authorized to hold the paired token + // gw["USD"]. + amm.deposit( + bob, + XRP(10), + std::nullopt, + std::nullopt, + std::nullopt, + ter(tecNO_AUTH)); + else + amm.deposit( + bob, + XRP(10), + std::nullopt, + std::nullopt, + std::nullopt, + ter(tesSUCCESS)); + } + // Insufficient XRP balance testAMM([&](AMM& ammAlice, Env& env) { env.fund(XRP(1'000), bob); @@ -6862,13 +6935,143 @@ struct AMM_test : public jtx::AMMTest } } + void + testAMMClawback(FeatureBitset features) + { + testcase("test clawback from AMM account"); + using namespace jtx; + + // Issuer has clawback enabled + Env env(*this, features); + env.fund(XRP(1'000), gw); + env(fset(gw, asfAllowTrustLineClawback)); + fund(env, gw, {alice}, XRP(1'000), {USD(1'000)}, Fund::Acct); + env.close(); + + // If featureAMMClawback is not enabled, AMMCreate is not allowed for + // clawback-enabled issuer + if (!features[featureAMMClawback]) + { + AMM amm(env, gw, XRP(100), USD(100), ter(tecNO_PERMISSION)); + AMM amm1(env, alice, USD(100), XRP(100), ter(tecNO_PERMISSION)); + env(fclear(gw, asfAllowTrustLineClawback)); + env.close(); + // Can't be cleared + AMM amm2(env, gw, XRP(100), USD(100), ter(tecNO_PERMISSION)); + } + // If featureAMMClawback is enabled, AMMCreate is allowed for + // clawback-enabled issuer. Clawback from the AMM Account is not + // allowed, which will return tecAMM_ACCOUNT. We can only use + // AMMClawback transaction to claw back from AMM Account. + else + { + AMM amm(env, gw, XRP(100), USD(100), ter(tesSUCCESS)); + AMM amm1(env, alice, USD(100), XRP(200), ter(tecDUPLICATE)); + + // Construct the amount being clawed back using AMM account. + // By doing this, we make the clawback transaction's Amount field's + // subfield `issuer` to be the AMM account, which means + // we are clawing back from an AMM account. This should return an + // tecAMM_ACCOUNT error because regular Clawback transaction is not + // allowed for clawing back from an AMM account. Please notice the + // `issuer` subfield represents the account being clawed back, which + // is confusing. + Issue usd(USD.issue().currency, amm.ammAccount()); + auto amount = amountFromString(usd, "10"); + env(claw(gw, amount), ter(tecAMM_ACCOUNT)); + } + } + + void + testAMMDepositWithFrozenAssets(FeatureBitset features) + { + testcase("test AMMDeposit with frozen assets"); + using namespace jtx; + + // This lambda function is used to create trustlines + // between gw and alice, and create an AMM account. + // And also test the callback function. + auto testAMMDeposit = [&](Env& env, std::function cb) { + env.fund(XRP(1'000), gw); + fund(env, gw, {alice}, XRP(1'000), {USD(1'000)}, Fund::Acct); + env.close(); + AMM amm(env, alice, XRP(100), USD(100), ter(tesSUCCESS)); + env(trust(gw, alice["USD"](0), tfSetFreeze)); + cb(amm); + }; + + // Deposit two assets, one of which is frozen, + // then we should get tecFROZEN error. + { + Env env(*this, features); + testAMMDeposit(env, [&](AMM& amm) { + amm.deposit( + alice, + USD(100), + XRP(100), + std::nullopt, + tfTwoAsset, + ter(tecFROZEN)); + }); + } + + // Deposit one asset, which is the frozen token, + // then we should get tecFROZEN error. + { + Env env(*this, features); + testAMMDeposit(env, [&](AMM& amm) { + amm.deposit( + alice, + USD(100), + std::nullopt, + std::nullopt, + tfSingleAsset, + ter(tecFROZEN)); + }); + } + + if (features[featureAMMClawback]) + { + // Deposit one asset which is not the frozen token, + // but the other asset is frozen. We should get tecFROZEN error + // when feature AMMClawback is enabled. + Env env(*this, features); + testAMMDeposit(env, [&](AMM& amm) { + amm.deposit( + alice, + XRP(100), + std::nullopt, + std::nullopt, + tfSingleAsset, + ter(tecFROZEN)); + }); + } + else + { + // Deposit one asset which is not the frozen token, + // but the other asset is frozen. We will get tecSUCCESS + // when feature AMMClawback is not enabled. + Env env(*this, features); + testAMMDeposit(env, [&](AMM& amm) { + amm.deposit( + alice, + XRP(100), + std::nullopt, + std::nullopt, + tfSingleAsset, + ter(tesSUCCESS)); + }); + } + } + void run() override { FeatureBitset const all{jtx::supported_amendments()}; testInvalidInstance(); testInstanceCreate(); - testInvalidDeposit(); + testInvalidDeposit(all); + testInvalidDeposit(all - featureAMMClawback); testDeposit(); testInvalidWithdraw(); testWithdraw(); @@ -6908,6 +7111,12 @@ struct AMM_test : public jtx::AMMTest testFixAMMOfferBlockedByLOB(all - fixAMMv1_1); testLPTokenBalance(all); testLPTokenBalance(all - fixAMMv1_1); + testAMMClawback(all); + testAMMClawback(all - featureAMMClawback); + testAMMClawback(all - fixAMMv1_1 - featureAMMClawback); + testAMMDepositWithFrozenAssets(all); + testAMMDepositWithFrozenAssets(all - featureAMMClawback); + testAMMDepositWithFrozenAssets(all - fixAMMv1_1 - featureAMMClawback); } }; diff --git a/src/test/app/MPToken_test.cpp b/src/test/app/MPToken_test.cpp index fa888faea17..9fdad6a0743 100644 --- a/src/test/app/MPToken_test.cpp +++ b/src/test/app/MPToken_test.cpp @@ -1443,6 +1443,17 @@ class MPToken_test : public beast::unit_test::suite }; ammBid(sfBidMin); ammBid(sfBidMax); + // AMMClawback + { + Json::Value jv; + jv[jss::TransactionType] = jss::AMMClawback; + jv[jss::Account] = alice.human(); + jv[jss::Holder] = carol.human(); + jv[jss::Asset] = to_json(xrpIssue()); + jv[jss::Asset2] = to_json(USD.issue()); + jv[jss::Amount] = mpt.getJson(JsonOptions::none); + test(jv, jss::Amount.c_str()); + } // CheckCash auto checkCash = [&](SField const& field) { Json::Value jv; diff --git a/src/test/jtx/AMM.h b/src/test/jtx/AMM.h index 77b9c8c9ec6..52039f74aea 100644 --- a/src/test/jtx/AMM.h +++ b/src/test/jtx/AMM.h @@ -438,6 +438,14 @@ trust( std::uint32_t flags = 0); Json::Value pay(Account const& account, AccountID const& to, STAmount const& amount); + +Json::Value +ammClawback( + Account const& issuer, + Account const& holder, + Issue const& asset, + Issue const& asset2, + std::optional const& amount); } // namespace amm } // namespace jtx diff --git a/src/test/jtx/impl/AMM.cpp b/src/test/jtx/impl/AMM.cpp index 4ef4fef7c1e..089d3508d70 100644 --- a/src/test/jtx/impl/AMM.cpp +++ b/src/test/jtx/impl/AMM.cpp @@ -823,6 +823,26 @@ pay(Account const& account, AccountID const& to, STAmount const& amount) jv[jss::Flags] = tfUniversal; return jv; } + +Json::Value +ammClawback( + Account const& issuer, + Account const& holder, + Issue const& asset, + Issue const& asset2, + std::optional const& amount) +{ + Json::Value jv; + jv[jss::TransactionType] = jss::AMMClawback; + jv[jss::Account] = issuer.human(); + jv[jss::Holder] = holder.human(); + jv[jss::Asset] = to_json(asset); + jv[jss::Asset2] = to_json(asset2); + if (amount) + jv[jss::Amount] = amount->getJson(JsonOptions::none); + + return jv; +} } // namespace amm } // namespace jtx } // namespace test diff --git a/src/test/rpc/Status_test.cpp b/src/test/rpc/Status_test.cpp index 1ae8b23c66c..c68131e8131 100644 --- a/src/test/rpc/Status_test.cpp +++ b/src/test/rpc/Status_test.cpp @@ -76,7 +76,7 @@ class codeString_test : public beast::unit_test::suite { auto s = codeString(temBAD_AMOUNT); - expect(s == "temBAD_AMOUNT: Can only send positive amounts.", s); + expect(s == "temBAD_AMOUNT: Malformed: Bad amount.", s); } { @@ -176,7 +176,7 @@ class fillJson_test : public beast::unit_test::suite "temBAD_AMOUNT", temBAD_AMOUNT, {}, - "temBAD_AMOUNT: Can only send positive amounts."); + "temBAD_AMOUNT: Malformed: Bad amount."); expectFill( "rpcBAD_SYNTAX", diff --git a/src/xrpld/app/tx/detail/AMMClawback.cpp b/src/xrpld/app/tx/detail/AMMClawback.cpp new file mode 100644 index 00000000000..468a5a4c6a2 --- /dev/null +++ b/src/xrpld/app/tx/detail/AMMClawback.cpp @@ -0,0 +1,290 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ripple { + +NotTEC +AMMClawback::preflight(PreflightContext const& ctx) +{ + if (!ctx.rules.enabled(featureAMMClawback)) + return temDISABLED; + + if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) + return ret; // LCOV_EXCL_LINE + + if (ctx.tx.getFlags() & tfAMMClawbackMask) + return temINVALID_FLAG; + + AccountID const issuer = ctx.tx[sfAccount]; + AccountID const holder = ctx.tx[sfHolder]; + + if (issuer == holder) + { + JLOG(ctx.j.trace()) + << "AMMClawback: holder cannot be the same as issuer."; + return temMALFORMED; + } + + std::optional const clawAmount = ctx.tx[~sfAmount]; + auto const asset = ctx.tx[sfAsset]; + + if (isXRP(asset)) + return temMALFORMED; + + if (asset.account != issuer) + { + JLOG(ctx.j.trace()) << "AMMClawback: Asset's account does not " + "match Account field."; + return temMALFORMED; + } + + if (clawAmount && clawAmount->issue() != asset) + { + JLOG(ctx.j.trace()) << "AMMClawback: Amount's issuer/currency subfield " + "does not match Asset field"; + return temBAD_AMOUNT; + } + + if (clawAmount && *clawAmount <= beast::zero) + return temBAD_AMOUNT; + + return preflight2(ctx); +} + +TER +AMMClawback::preclaim(PreclaimContext const& ctx) +{ + auto const asset = ctx.tx[sfAsset]; + auto const asset2 = ctx.tx[sfAsset2]; + auto const sleIssuer = ctx.view.read(keylet::account(ctx.tx[sfAccount])); + if (!sleIssuer) + return terNO_ACCOUNT; // LCOV_EXCL_LINE + + if (!ctx.view.read(keylet::account(ctx.tx[sfHolder]))) + return terNO_ACCOUNT; + + auto const ammSle = ctx.view.read(keylet::amm(asset, asset2)); + if (!ammSle) + { + JLOG(ctx.j.debug()) << "AMM Clawback: Invalid asset pair."; + return terNO_AMM; + } + + std::uint32_t const issuerFlagsIn = sleIssuer->getFieldU32(sfFlags); + + // If AllowTrustLineClawback is not set or NoFreeze is set, return no + // permission + if (!(issuerFlagsIn & lsfAllowTrustLineClawback) || + (issuerFlagsIn & lsfNoFreeze)) + return tecNO_PERMISSION; + + auto const flags = ctx.tx.getFlags(); + if (flags & tfClawTwoAssets && asset.account != asset2.account) + { + JLOG(ctx.j.trace()) + << "AMMClawback: tfClawTwoAssets can only be enabled when two " + "assets in the AMM pool are both issued by the issuer"; + return tecNO_PERMISSION; + } + + return tesSUCCESS; +} + +TER +AMMClawback::doApply() +{ + Sandbox sb(&ctx_.view()); + + auto const ter = applyGuts(sb); + if (ter == tesSUCCESS) + sb.apply(ctx_.rawView()); + + return ter; +} + +TER +AMMClawback::applyGuts(Sandbox& sb) +{ + std::optional const clawAmount = ctx_.tx[~sfAmount]; + AccountID const issuer = ctx_.tx[sfAccount]; + AccountID const holder = ctx_.tx[sfHolder]; + Issue const asset = ctx_.tx[sfAsset]; + Issue const asset2 = ctx_.tx[sfAsset2]; + + auto ammSle = sb.peek(keylet::amm(asset, asset2)); + if (!ammSle) + return tecINTERNAL; // LCOV_EXCL_LINE + + auto const ammAccount = (*ammSle)[sfAccount]; + auto const accountSle = sb.read(keylet::account(ammAccount)); + if (!accountSle) + return tecINTERNAL; // LCOV_EXCL_LINE + + auto const expected = ammHolds( + sb, + *ammSle, + asset, + asset2, + FreezeHandling::fhIGNORE_FREEZE, + ctx_.journal); + + if (!expected) + return expected.error(); // LCOV_EXCL_LINE + auto const [amountBalance, amount2Balance, lptAMMBalance] = *expected; + + TER result; + STAmount newLPTokenBalance; + STAmount amountWithdraw; + std::optional amount2Withdraw; + + auto const holdLPtokens = ammLPHolds(sb, *ammSle, holder, j_); + if (holdLPtokens == beast::zero) + return tecAMM_BALANCE; + + if (!clawAmount) + // Because we are doing a two-asset withdrawal, + // tfee is actually not used, so pass tfee as 0. + std::tie(result, newLPTokenBalance, amountWithdraw, amount2Withdraw) = + AMMWithdraw::equalWithdrawTokens( + sb, + *ammSle, + holder, + ammAccount, + amountBalance, + amount2Balance, + lptAMMBalance, + holdLPtokens, + holdLPtokens, + 0, + FreezeHandling::fhIGNORE_FREEZE, + WithdrawAll::Yes, + ctx_.journal); + else + std::tie(result, newLPTokenBalance, amountWithdraw, amount2Withdraw) = + equalWithdrawMatchingOneAmount( + sb, + *ammSle, + holder, + ammAccount, + amountBalance, + amount2Balance, + lptAMMBalance, + holdLPtokens, + *clawAmount); + + if (result != tesSUCCESS) + return result; // LCOV_EXCL_LINE + + auto const res = AMMWithdraw::deleteAMMAccountIfEmpty( + sb, ammSle, newLPTokenBalance, asset, asset2, j_); + if (!res.second) + return res.first; // LCOV_EXCL_LINE + + JLOG(ctx_.journal.trace()) + << "AMM Withdraw during AMMClawback: lptoken new balance: " + << to_string(newLPTokenBalance.iou()) + << " old balance: " << to_string(lptAMMBalance.iou()); + + auto const ter = rippleCredit(sb, holder, issuer, amountWithdraw, true, j_); + if (ter != tesSUCCESS) + return ter; // LCOV_EXCL_LINE + + // if the issuer issues both assets and sets flag tfClawTwoAssets, we + // will claw the paired asset as well. We already checked if + // tfClawTwoAssets is enabled, the two assets have to be issued by the + // same issuer. + if (!amount2Withdraw) + return tecINTERNAL; // LCOV_EXCL_LINE + + auto const flags = ctx_.tx.getFlags(); + if (flags & tfClawTwoAssets) + return rippleCredit(sb, holder, issuer, *amount2Withdraw, true, j_); + + return tesSUCCESS; +} + +std::tuple> +AMMClawback::equalWithdrawMatchingOneAmount( + Sandbox& sb, + SLE const& ammSle, + AccountID const& holder, + AccountID const& ammAccount, + STAmount const& amountBalance, + STAmount const& amount2Balance, + STAmount const& lptAMMBalance, + STAmount const& holdLPtokens, + STAmount const& amount) +{ + auto frac = Number{amount} / amountBalance; + auto const amount2Withdraw = amount2Balance * frac; + + auto const lpTokensWithdraw = + toSTAmount(lptAMMBalance.issue(), lptAMMBalance * frac); + if (lpTokensWithdraw > holdLPtokens) + // if lptoken balance less than what the issuer intended to clawback, + // clawback all the tokens. Because we are doing a two-asset withdrawal, + // tfee is actually not used, so pass tfee as 0. + return AMMWithdraw::equalWithdrawTokens( + sb, + ammSle, + holder, + ammAccount, + amountBalance, + amount2Balance, + lptAMMBalance, + holdLPtokens, + holdLPtokens, + 0, + FreezeHandling::fhIGNORE_FREEZE, + WithdrawAll::Yes, + ctx_.journal); + + // Because we are doing a two-asset withdrawal, + // tfee is actually not used, so pass tfee as 0. + return AMMWithdraw::withdraw( + sb, + ammSle, + ammAccount, + holder, + amountBalance, + amount, + toSTAmount(amount2Balance.issue(), amount2Withdraw), + lptAMMBalance, + toSTAmount(lptAMMBalance.issue(), lptAMMBalance * frac), + 0, + FreezeHandling::fhIGNORE_FREEZE, + WithdrawAll::No, + ctx_.journal); +} + +} // namespace ripple diff --git a/src/xrpld/app/tx/detail/AMMClawback.h b/src/xrpld/app/tx/detail/AMMClawback.h new file mode 100644 index 00000000000..fdcfc53e2ca --- /dev/null +++ b/src/xrpld/app/tx/detail/AMMClawback.h @@ -0,0 +1,75 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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_TX_AMMCLAWBACK_H_INCLUDED +#define RIPPLE_TX_AMMCLAWBACK_H_INCLUDED + +#include + +namespace ripple { +class Sandbox; +class AMMClawback : public Transactor +{ +public: + static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; + + explicit AMMClawback(ApplyContext& ctx) : Transactor(ctx) + { + } + + static NotTEC + preflight(PreflightContext const& ctx); + + static TER + preclaim(PreclaimContext const& ctx); + + TER + doApply() override; + +private: + TER + applyGuts(Sandbox& view); + + /** Withdraw both assets by providing maximum amount of asset1, + * asset2's amount will be calculated according to the current proportion. + * Since it is two-asset withdrawal, tfee is omitted. + * @param view + * @param ammAccount current AMM account + * @param amountBalance current AMM asset1 balance + * @param amount2Balance current AMM asset2 balance + * @param lptAMMBalance current AMM LPT balance + * @param amount asset1 withdraw amount + * @return + */ + std::tuple> + equalWithdrawMatchingOneAmount( + Sandbox& view, + SLE const& ammSle, + AccountID const& holder, + AccountID const& ammAccount, + STAmount const& amountBalance, + STAmount const& amount2Balance, + STAmount const& lptAMMBalance, + STAmount const& holdLPtokens, + STAmount const& amount); +}; + +} // namespace ripple + +#endif diff --git a/src/xrpld/app/tx/detail/AMMCreate.cpp b/src/xrpld/app/tx/detail/AMMCreate.cpp index 237e1afa240..31773166d4a 100644 --- a/src/xrpld/app/tx/detail/AMMCreate.cpp +++ b/src/xrpld/app/tx/detail/AMMCreate.cpp @@ -184,7 +184,13 @@ AMMCreate::preclaim(PreclaimContext const& ctx) return tecAMM_INVALID_TOKENS; } - // Disallow AMM if the issuer has clawback enabled + // If featureAMMClawback is enabled, allow AMMCreate without checking + // if the issuer has clawback enabled + if (ctx.view.rules().enabled(featureAMMClawback)) + return tesSUCCESS; + + // Disallow AMM if the issuer has clawback enabled when featureAMMClawback + // is not enabled auto clawbackDisabled = [&](Issue const& issue) -> TER { if (isXRP(issue)) return tesSUCCESS; diff --git a/src/xrpld/app/tx/detail/AMMDeposit.cpp b/src/xrpld/app/tx/detail/AMMDeposit.cpp index 9bbf5b4a60a..3448401eb79 100644 --- a/src/xrpld/app/tx/detail/AMMDeposit.cpp +++ b/src/xrpld/app/tx/detail/AMMDeposit.cpp @@ -244,6 +244,37 @@ AMMDeposit::preclaim(PreclaimContext const& ctx) : tecUNFUNDED_AMM; }; + if (ctx.view.rules().enabled(featureAMMClawback)) + { + // Check if either of the assets is frozen, AMMDeposit is not allowed + // if either asset is frozen + auto checkAsset = [&](Issue const& asset) -> TER { + if (auto const ter = requireAuth(ctx.view, asset, accountID)) + { + JLOG(ctx.j.debug()) + << "AMM Deposit: account is not authorized, " << asset; + return ter; + } + + if (isFrozen(ctx.view, accountID, asset)) + { + JLOG(ctx.j.debug()) + << "AMM Deposit: account or currency is frozen, " + << to_string(accountID) << " " << to_string(asset.currency); + + return tecFROZEN; + } + + return tesSUCCESS; + }; + + if (auto const ter = checkAsset(ctx.tx[sfAsset])) + return ter; + + if (auto const ter = checkAsset(ctx.tx[sfAsset2])) + return ter; + } + auto const amount = ctx.tx[~sfAmount]; auto const amount2 = ctx.tx[~sfAmount2]; auto const ammAccountID = ammSle->getAccountID(sfAccount); diff --git a/src/xrpld/app/tx/detail/AMMWithdraw.cpp b/src/xrpld/app/tx/detail/AMMWithdraw.cpp index 51b512aba0a..0a6f3291b78 100644 --- a/src/xrpld/app/tx/detail/AMMWithdraw.cpp +++ b/src/xrpld/app/tx/detail/AMMWithdraw.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -358,6 +357,7 @@ AMMWithdraw::applyGuts(Sandbox& sb) if (subTxType & tfTwoAsset) return equalWithdrawLimit( sb, + *ammSle, ammAccountID, amountBalance, amount2Balance, @@ -368,6 +368,7 @@ AMMWithdraw::applyGuts(Sandbox& sb) if (subTxType & tfOneAssetLPToken || subTxType & tfOneAssetWithdrawAll) return singleWithdrawTokens( sb, + *ammSle, ammAccountID, amountBalance, lptAMMBalance, @@ -377,6 +378,7 @@ AMMWithdraw::applyGuts(Sandbox& sb) if (subTxType & tfLimitLPToken) return singleWithdrawEPrice( sb, + *ammSle, ammAccountID, amountBalance, lptAMMBalance, @@ -385,10 +387,18 @@ AMMWithdraw::applyGuts(Sandbox& sb) tfee); if (subTxType & tfSingleAsset) return singleWithdraw( - sb, ammAccountID, amountBalance, lptAMMBalance, *amount, tfee); + sb, + *ammSle, + ammAccountID, + amountBalance, + lptAMMBalance, + *amount, + tfee); if (subTxType & tfLPToken || subTxType & tfWithdrawAll) + { return equalWithdrawTokens( sb, + *ammSle, ammAccountID, amountBalance, amount2Balance, @@ -396,6 +406,7 @@ AMMWithdraw::applyGuts(Sandbox& sb) lpTokens, *lpTokensWithdraw, tfee); + } // should not happen. // LCOV_EXCL_START JLOG(j_.error()) << "AMM Withdraw: invalid options."; @@ -406,22 +417,12 @@ AMMWithdraw::applyGuts(Sandbox& sb) if (result != tesSUCCESS) return {result, false}; - bool updateBalance = true; - if (newLPTokenBalance == beast::zero) - { - if (auto const ter = - deleteAMMAccount(sb, ctx_.tx[sfAsset], ctx_.tx[sfAsset2], j_); - ter != tesSUCCESS && ter != tecINCOMPLETE) - return {ter, false}; - else - updateBalance = (ter == tecINCOMPLETE); - } - - if (updateBalance) - { - ammSle->setFieldAmount(sfLPTokenBalance, newLPTokenBalance); - sb.update(ammSle); - } + auto const res = deleteAMMAccountIfEmpty( + sb, ammSle, newLPTokenBalance, ctx_.tx[sfAsset], ctx_.tx[sfAsset2], j_); + // LCOV_EXCL_START + if (!res.second) + return {res.first, false}; + // LCOV_EXCL_STOP JLOG(ctx_.journal.trace()) << "AMM Withdraw: tokens " << to_string(newLPTokenBalance.iou()) << " " @@ -447,6 +448,7 @@ AMMWithdraw::doApply() std::pair AMMWithdraw::withdraw( Sandbox& view, + SLE const& ammSle, AccountID const& ammAccount, STAmount const& amountBalance, STAmount const& amountWithdraw, @@ -455,27 +457,60 @@ AMMWithdraw::withdraw( STAmount const& lpTokensWithdraw, std::uint16_t tfee) { - auto const ammSle = - ctx_.view().read(keylet::amm(ctx_.tx[sfAsset], ctx_.tx[sfAsset2])); - if (!ammSle) - return {tecINTERNAL, STAmount{}}; // LCOV_EXCL_LINE - auto const lpTokens = ammLPHolds(view, *ammSle, account_, ctx_.journal); + TER ter; + STAmount newLPTokenBalance; + std::tie(ter, newLPTokenBalance, std::ignore, std::ignore) = withdraw( + view, + ammSle, + ammAccount, + account_, + amountBalance, + amountWithdraw, + amount2Withdraw, + lpTokensAMMBalance, + lpTokensWithdraw, + tfee, + FreezeHandling::fhZERO_IF_FROZEN, + isWithdrawAll(ctx_.tx), + j_); + return {ter, newLPTokenBalance}; +} + +std::tuple> +AMMWithdraw::withdraw( + Sandbox& view, + SLE const& ammSle, + AccountID const& ammAccount, + AccountID const& account, + STAmount const& amountBalance, + STAmount const& amountWithdraw, + std::optional const& amount2Withdraw, + STAmount const& lpTokensAMMBalance, + STAmount const& lpTokensWithdraw, + std::uint16_t tfee, + FreezeHandling freezeHandling, + WithdrawAll withdrawAll, + beast::Journal const& journal) +{ + auto const lpTokens = ammLPHolds(view, ammSle, account, journal); auto const expected = ammHolds( view, - *ammSle, + ammSle, amountWithdraw.issue(), std::nullopt, - FreezeHandling::fhZERO_IF_FROZEN, - j_); + freezeHandling, + journal); + // LCOV_EXCL_START if (!expected) - return {expected.error(), STAmount{}}; + return {expected.error(), STAmount{}, STAmount{}, STAmount{}}; + // LCOV_EXCL_STOP auto const [curBalance, curBalance2, _] = *expected; (void)_; auto const [amountWithdrawActual, amount2WithdrawActual, lpTokensWithdrawActual] = [&]() -> std::tuple, STAmount> { - if (!(ctx_.tx[sfFlags] & (tfWithdrawAll | tfOneAssetWithdrawAll))) + if (withdrawAll == WithdrawAll::No) return adjustAmountsByLPTokens( amountBalance, amountWithdraw, @@ -491,11 +526,11 @@ AMMWithdraw::withdraw( if (lpTokensWithdrawActual <= beast::zero || lpTokensWithdrawActual > lpTokens) { - JLOG(ctx_.journal.debug()) + JLOG(journal.debug()) << "AMM Withdraw: failed to withdraw, invalid LP tokens: " << lpTokensWithdrawActual << " " << lpTokens << " " << lpTokensAMMBalance; - return {tecAMM_INVALID_TOKENS, STAmount{}}; + return {tecAMM_INVALID_TOKENS, STAmount{}, STAmount{}, STAmount{}}; } // Should not happen since the only LP on last withdraw @@ -503,11 +538,13 @@ AMMWithdraw::withdraw( if (view.rules().enabled(fixAMMv1_1) && lpTokensWithdrawActual > lpTokensAMMBalance) { - JLOG(ctx_.journal.debug()) + // LCOV_EXCL_START + JLOG(journal.debug()) << "AMM Withdraw: failed to withdraw, unexpected LP tokens: " << lpTokensWithdrawActual << " " << lpTokens << " " << lpTokensAMMBalance; - return {tecINTERNAL, STAmount{}}; + return {tecINTERNAL, STAmount{}, STAmount{}, STAmount{}}; + // LCOV_EXCL_STOP } // Withdrawing one side of the pool @@ -516,12 +553,12 @@ AMMWithdraw::withdraw( (amount2WithdrawActual == curBalance2 && amountWithdrawActual != curBalance)) { - JLOG(ctx_.journal.debug()) + JLOG(journal.debug()) << "AMM Withdraw: failed to withdraw one side of the pool " << " curBalance: " << curBalance << " " << amountWithdrawActual << " lpTokensBalance: " << lpTokensWithdraw << " lptBalance " << lpTokensAMMBalance; - return {tecAMM_BALANCE, STAmount{}}; + return {tecAMM_BALANCE, STAmount{}, STAmount{}, STAmount{}}; } // May happen if withdrawing an amount close to one side of the pool @@ -529,42 +566,44 @@ AMMWithdraw::withdraw( (amountWithdrawActual != curBalance || amount2WithdrawActual != curBalance2)) { - JLOG(ctx_.journal.debug()) + JLOG(journal.debug()) << "AMM Withdraw: failed to withdraw all tokens " << " curBalance: " << curBalance << " " << amountWithdrawActual << " curBalance2: " << amount2WithdrawActual.value_or(STAmount{0}) << " lpTokensBalance: " << lpTokensWithdraw << " lptBalance " << lpTokensAMMBalance; - return {tecAMM_BALANCE, STAmount{}}; + return {tecAMM_BALANCE, STAmount{}, STAmount{}, STAmount{}}; } // Withdrawing more than the pool's balance if (amountWithdrawActual > curBalance || amount2WithdrawActual > curBalance2) { - JLOG(ctx_.journal.debug()) + JLOG(journal.debug()) << "AMM Withdraw: withdrawing more than the pool's balance " << " curBalance: " << curBalance << " " << amountWithdrawActual << " curBalance2: " << curBalance2 << " " << (amount2WithdrawActual ? *amount2WithdrawActual : STAmount{}) << " lpTokensBalance: " << lpTokensWithdraw << " lptBalance " << lpTokensAMMBalance; - return {tecAMM_BALANCE, STAmount{}}; + return {tecAMM_BALANCE, STAmount{}, STAmount{}, STAmount{}}; } // Withdraw amountWithdraw auto res = accountSend( view, ammAccount, - account_, + account, amountWithdrawActual, - ctx_.journal, + journal, WaiveTransferFee::Yes); if (res != tesSUCCESS) { - JLOG(ctx_.journal.debug()) + // LCOV_EXCL_START + JLOG(journal.debug()) << "AMM Withdraw: failed to withdraw " << amountWithdrawActual; - return {res, STAmount{}}; + return {res, STAmount{}, STAmount{}, STAmount{}}; + // LCOV_EXCL_STOP } // Withdraw amount2Withdraw @@ -573,40 +612,46 @@ AMMWithdraw::withdraw( res = accountSend( view, ammAccount, - account_, + account, *amount2WithdrawActual, - ctx_.journal, + journal, WaiveTransferFee::Yes); if (res != tesSUCCESS) { - JLOG(ctx_.journal.debug()) << "AMM Withdraw: failed to withdraw " - << *amount2WithdrawActual; - return {res, STAmount{}}; + // LCOV_EXCL_START + JLOG(journal.debug()) << "AMM Withdraw: failed to withdraw " + << *amount2WithdrawActual; + return {res, STAmount{}, STAmount{}, STAmount{}}; + // LCOV_EXCL_STOP } } // Withdraw LP tokens res = redeemIOU( view, - account_, + account, lpTokensWithdrawActual, lpTokensWithdrawActual.issue(), - ctx_.journal); + journal); if (res != tesSUCCESS) { - JLOG(ctx_.journal.debug()) - << "AMM Withdraw: failed to withdraw LPTokens"; - return {res, STAmount{}}; + // LCOV_EXCL_START + JLOG(journal.debug()) << "AMM Withdraw: failed to withdraw LPTokens"; + return {res, STAmount{}, STAmount{}, STAmount{}}; + // LCOV_EXCL_STOP } - return {tesSUCCESS, lpTokensAMMBalance - lpTokensWithdrawActual}; + return std::make_tuple( + tesSUCCESS, + lpTokensAMMBalance - lpTokensWithdrawActual, + amountWithdrawActual, + amount2WithdrawActual); } -/** Proportional withdrawal of pool assets for the amount of LPTokens. - */ std::pair AMMWithdraw::equalWithdrawTokens( Sandbox& view, + SLE const& ammSle, AccountID const& ammAccount, STAmount const& amountBalance, STAmount const& amount2Balance, @@ -614,20 +659,94 @@ AMMWithdraw::equalWithdrawTokens( STAmount const& lpTokens, STAmount const& lpTokensWithdraw, std::uint16_t tfee) +{ + TER ter; + STAmount newLPTokenBalance; + std::tie(ter, newLPTokenBalance, std::ignore, std::ignore) = + equalWithdrawTokens( + view, + ammSle, + account_, + ammAccount, + amountBalance, + amount2Balance, + lptAMMBalance, + lpTokens, + lpTokensWithdraw, + tfee, + FreezeHandling::fhZERO_IF_FROZEN, + isWithdrawAll(ctx_.tx), + ctx_.journal); + return {ter, newLPTokenBalance}; +} + +std::pair +AMMWithdraw::deleteAMMAccountIfEmpty( + Sandbox& sb, + std::shared_ptr const ammSle, + STAmount const& lpTokenBalance, + Issue const& issue1, + Issue const& issue2, + beast::Journal const& journal) +{ + TER ter; + bool updateBalance = true; + if (lpTokenBalance == beast::zero) + { + ter = deleteAMMAccount(sb, issue1, issue2, journal); + if (ter != tesSUCCESS && ter != tecINCOMPLETE) + return {ter, false}; // LCOV_EXCL_LINE + else + updateBalance = (ter == tecINCOMPLETE); + } + + if (updateBalance) + { + ammSle->setFieldAmount(sfLPTokenBalance, lpTokenBalance); + sb.update(ammSle); + } + + return {ter, true}; +} + +/** Proportional withdrawal of pool assets for the amount of LPTokens. + */ +std::tuple> +AMMWithdraw::equalWithdrawTokens( + Sandbox& view, + SLE const& ammSle, + AccountID const account, + AccountID const& ammAccount, + STAmount const& amountBalance, + STAmount const& amount2Balance, + STAmount const& lptAMMBalance, + STAmount const& lpTokens, + STAmount const& lpTokensWithdraw, + std::uint16_t tfee, + FreezeHandling freezeHanding, + WithdrawAll withdrawAll, + beast::Journal const& journal) { try { // Withdrawing all tokens in the pool if (lpTokensWithdraw == lptAMMBalance) + { return withdraw( view, + ammSle, ammAccount, + account, amountBalance, amountBalance, amount2Balance, lptAMMBalance, lpTokensWithdraw, - tfee); + tfee, + freezeHanding, + WithdrawAll::Yes, + journal); + } auto const frac = divide(lpTokensWithdraw, lptAMMBalance, noIssue()); auto const withdrawAmount = @@ -639,25 +758,30 @@ AMMWithdraw::equalWithdrawTokens( // withdrawal due to round off. Fail so the user withdraws // more tokens. if (withdrawAmount == beast::zero || withdraw2Amount == beast::zero) - return {tecAMM_FAILED, STAmount{}}; + return {tecAMM_FAILED, STAmount{}, STAmount{}, STAmount{}}; return withdraw( view, + ammSle, ammAccount, + account, amountBalance, withdrawAmount, withdraw2Amount, lptAMMBalance, lpTokensWithdraw, - tfee); + tfee, + freezeHanding, + withdrawAll, + journal); } // LCOV_EXCL_START catch (std::exception const& e) { - JLOG(j_.error()) << "AMMWithdraw::equalWithdrawTokens exception " - << e.what(); + JLOG(journal.error()) + << "AMMWithdraw::equalWithdrawTokens exception " << e.what(); } - return {tecINTERNAL, STAmount{}}; + return {tecINTERNAL, STAmount{}, STAmount{}, STAmount{}}; // LCOV_EXCL_STOP } @@ -689,6 +813,7 @@ AMMWithdraw::equalWithdrawTokens( std::pair AMMWithdraw::equalWithdrawLimit( Sandbox& view, + SLE const& ammSle, AccountID const& ammAccount, STAmount const& amountBalance, STAmount const& amount2Balance, @@ -700,8 +825,10 @@ AMMWithdraw::equalWithdrawLimit( auto frac = Number{amount} / amountBalance; auto const amount2Withdraw = amount2Balance * frac; if (amount2Withdraw <= amount2) + { return withdraw( view, + ammSle, ammAccount, amountBalance, amount, @@ -709,11 +836,14 @@ AMMWithdraw::equalWithdrawLimit( lptAMMBalance, toSTAmount(lptAMMBalance.issue(), lptAMMBalance * frac), tfee); + } + frac = Number{amount2} / amount2Balance; auto const amountWithdraw = amountBalance * frac; assert(amountWithdraw <= amount); return withdraw( view, + ammSle, ammAccount, amountBalance, toSTAmount(amount.issue(), amountWithdraw), @@ -731,6 +861,7 @@ AMMWithdraw::equalWithdrawLimit( std::pair AMMWithdraw::singleWithdraw( Sandbox& view, + SLE const& ammSle, AccountID const& ammAccount, STAmount const& amountBalance, STAmount const& lptAMMBalance, @@ -740,8 +871,10 @@ AMMWithdraw::singleWithdraw( auto const tokens = lpTokensOut(amountBalance, amount, lptAMMBalance, tfee); if (tokens == beast::zero) return {tecAMM_FAILED, STAmount{}}; + return withdraw( view, + ammSle, ammAccount, amountBalance, amount, @@ -764,6 +897,7 @@ AMMWithdraw::singleWithdraw( std::pair AMMWithdraw::singleWithdrawTokens( Sandbox& view, + SLE const& ammSle, AccountID const& ammAccount, STAmount const& amountBalance, STAmount const& lptAMMBalance, @@ -774,8 +908,10 @@ AMMWithdraw::singleWithdrawTokens( auto const amountWithdraw = withdrawByTokens(amountBalance, lptAMMBalance, lpTokensWithdraw, tfee); if (amount == beast::zero || amountWithdraw >= amount) + { return withdraw( view, + ammSle, ammAccount, amountBalance, amountWithdraw, @@ -783,6 +919,8 @@ AMMWithdraw::singleWithdrawTokens( lptAMMBalance, lpTokensWithdraw, tfee); + } + return {tecAMM_FAILED, STAmount{}}; } @@ -808,6 +946,7 @@ AMMWithdraw::singleWithdrawTokens( std::pair AMMWithdraw::singleWithdrawEPrice( Sandbox& view, + SLE const& ammSle, AccountID const& ammAccount, STAmount const& amountBalance, STAmount const& lptAMMBalance, @@ -833,8 +972,10 @@ AMMWithdraw::singleWithdrawEPrice( return {tecAMM_FAILED, STAmount{}}; auto const amountWithdraw = toSTAmount(amount.issue(), tokens / ePrice); if (amount == beast::zero || amountWithdraw >= amount) + { return withdraw( view, + ammSle, ammAccount, amountBalance, amountWithdraw, @@ -842,8 +983,16 @@ AMMWithdraw::singleWithdrawEPrice( lptAMMBalance, toSTAmount(lptAMMBalance.issue(), tokens), tfee); + } return {tecAMM_FAILED, STAmount{}}; } +WithdrawAll +AMMWithdraw::isWithdrawAll(STTx const& tx) +{ + if (tx[sfFlags] & (tfWithdrawAll | tfOneAssetWithdrawAll)) + return WithdrawAll::Yes; + return WithdrawAll::No; +} } // namespace ripple diff --git a/src/xrpld/app/tx/detail/AMMWithdraw.h b/src/xrpld/app/tx/detail/AMMWithdraw.h index 9e9920aa5f6..f5b6b52e5ba 100644 --- a/src/xrpld/app/tx/detail/AMMWithdraw.h +++ b/src/xrpld/app/tx/detail/AMMWithdraw.h @@ -21,6 +21,7 @@ #define RIPPLE_TX_AMMWITHDRAW_H_INCLUDED #include +#include namespace ripple { @@ -62,6 +63,9 @@ class Sandbox; * @see [XLS30d:AMMWithdraw * transaction](https://github.com/XRPLF/XRPL-Standards/discussions/78) */ + +enum class WithdrawAll : bool { No = false, Yes }; + class AMMWithdraw : public Transactor { public: @@ -80,6 +84,76 @@ class AMMWithdraw : public Transactor TER doApply() override; + /** Equal-asset withdrawal (LPTokens) of some AMM instance pools + * shares represented by the number of LPTokens . + * The trading fee is not charged. + * @param view + * @param ammAccount + * @param amountBalance current LP asset1 balance + * @param amount2Balance current LP asset2 balance + * @param lptAMMBalance current AMM LPT balance + * @param lpTokens current LPT balance + * @param lpTokensWithdraw amount of tokens to withdraw + * @param tfee trading fee in basis points + * @param withdrawAll if withdrawing all lptokens + * @return + */ + static std::tuple> + equalWithdrawTokens( + Sandbox& view, + SLE const& ammSle, + AccountID const account, + AccountID const& ammAccount, + STAmount const& amountBalance, + STAmount const& amount2Balance, + STAmount const& lptAMMBalance, + STAmount const& lpTokens, + STAmount const& lpTokensWithdraw, + std::uint16_t tfee, + FreezeHandling freezeHanding, + WithdrawAll withdrawAll, + beast::Journal const& journal); + + /** Withdraw requested assets and token from AMM into LP account. + * Return new total LPToken balance and the withdrawn amounts for both + * assets. + * @param view + * @param ammSle AMM ledger entry + * @param ammAccount AMM account + * @param amountBalance current LP asset1 balance + * @param amountWithdraw asset1 withdraw amount + * @param amount2Withdraw asset2 withdraw amount + * @param lpTokensAMMBalance current AMM LPT balance + * @param lpTokensWithdraw amount of lptokens to withdraw + * @param tfee trading fee in basis points + * @param withdrawAll if withdraw all lptokens + * @return + */ + static std::tuple> + withdraw( + Sandbox& view, + SLE const& ammSle, + AccountID const& ammAccount, + AccountID const& account, + STAmount const& amountBalance, + STAmount const& amountWithdraw, + std::optional const& amount2Withdraw, + STAmount const& lpTokensAMMBalance, + STAmount const& lpTokensWithdraw, + std::uint16_t tfee, + FreezeHandling freezeHandling, + WithdrawAll withdrawAll, + beast::Journal const& journal); + + static std::pair + deleteAMMAccountIfEmpty( + Sandbox& sb, + std::shared_ptr const ammSle, + STAmount const& lpTokenBalance, + Issue const& issue1, + Issue const& issue2, + beast::Journal const& journal); + private: std::pair applyGuts(Sandbox& view); @@ -87,21 +161,22 @@ class AMMWithdraw : public Transactor /** Withdraw requested assets and token from AMM into LP account. * Return new total LPToken balance. * @param view - * @param ammAccount - * @param amountBalance - * @param amountWithdraw - * @param amount2Withdraw + * @param ammSle AMM ledger entry + * @param ammAccount AMM account + * @param amountBalance current LP asset1 balance + * @param amountWithdraw asset1 withdraw amount + * @param amount2Withdraw asset2 withdraw amount * @param lpTokensAMMBalance current AMM LPT balance - * @param lpTokensWithdraw - * @param tfee + * @param lpTokensWithdraw amount of lptokens to withdraw * @return */ std::pair withdraw( Sandbox& view, + SLE const& ammSle, AccountID const& ammAccount, - STAmount const& amountWithdraw, STAmount const& amountBalance, + STAmount const& amountWithdraw, std::optional const& amount2Withdraw, STAmount const& lpTokensAMMBalance, STAmount const& lpTokensWithdraw, @@ -123,6 +198,7 @@ class AMMWithdraw : public Transactor std::pair equalWithdrawTokens( Sandbox& view, + SLE const& ammSle, AccountID const& ammAccount, STAmount const& amountBalance, STAmount const& amount2Balance, @@ -147,6 +223,7 @@ class AMMWithdraw : public Transactor std::pair equalWithdrawLimit( Sandbox& view, + SLE const& ammSle, AccountID const& ammAccount, STAmount const& amountBalance, STAmount const& amount2Balance, @@ -168,6 +245,7 @@ class AMMWithdraw : public Transactor std::pair singleWithdraw( Sandbox& view, + SLE const& ammSle, AccountID const& ammAccount, STAmount const& amountBalance, STAmount const& lptAMMBalance, @@ -188,6 +266,7 @@ class AMMWithdraw : public Transactor std::pair singleWithdrawTokens( Sandbox& view, + SLE const& ammSle, AccountID const& ammAccount, STAmount const& amountBalance, STAmount const& lptAMMBalance, @@ -209,12 +288,17 @@ class AMMWithdraw : public Transactor std::pair singleWithdrawEPrice( Sandbox& view, + SLE const& ammSle, AccountID const& ammAccount, STAmount const& amountBalance, STAmount const& lptAMMBalance, STAmount const& amount, STAmount const& ePrice, std::uint16_t tfee); + + /** Check from the flags if it's withdraw all */ + WithdrawAll + isWithdrawAll(STTx const& tx); }; } // namespace ripple diff --git a/src/xrpld/app/tx/detail/InvariantCheck.cpp b/src/xrpld/app/tx/detail/InvariantCheck.cpp index e8bbd0283b5..d1eaf86844d 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.cpp +++ b/src/xrpld/app/tx/detail/InvariantCheck.cpp @@ -342,11 +342,12 @@ AccountRootsNotDeleted::finalize( return false; } - // A successful AMMWithdraw MAY delete one account root + // A successful AMMWithdraw/AMMClawback MAY delete one account root // when the total AMM LP Tokens balance goes to 0. Not every AMM withdraw // deletes the AMM account, accountsDeleted_ is set if it is deleted. - if (tx.getTxnType() == ttAMM_WITHDRAW && result == tesSUCCESS && - accountsDeleted_ == 1) + if ((tx.getTxnType() == ttAMM_WITHDRAW || + tx.getTxnType() == ttAMM_CLAWBACK) && + result == tesSUCCESS && accountsDeleted_ == 1) return true; if (accountsDeleted_ == 0) diff --git a/src/xrpld/app/tx/detail/applySteps.cpp b/src/xrpld/app/tx/detail/applySteps.cpp index f59cd73378b..44c25cb22ef 100644 --- a/src/xrpld/app/tx/detail/applySteps.cpp +++ b/src/xrpld/app/tx/detail/applySteps.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include From d57cced17b40304c48f74259509d121e0a6afa76 Mon Sep 17 00:00:00 2001 From: Gregory Tsipenyuk Date: Tue, 5 Nov 2024 10:48:02 -0500 Subject: [PATCH 69/82] Fix unity build (#5179) --- src/test/app/MPToken_test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/app/MPToken_test.cpp b/src/test/app/MPToken_test.cpp index 9fdad6a0743..0f92212288d 100644 --- a/src/test/app/MPToken_test.cpp +++ b/src/test/app/MPToken_test.cpp @@ -24,6 +24,7 @@ #include namespace ripple { +namespace test { class MPToken_test : public beast::unit_test::suite { @@ -1989,4 +1990,5 @@ class MPToken_test : public beast::unit_test::suite BEAST_DEFINE_TESTSUITE_PRIO(MPToken, tx, ripple, 2); +} // namespace test } // namespace ripple From ec61f5e9d32114eac1a2020c3b26abc7299e49e8 Mon Sep 17 00:00:00 2001 From: Gregory Tsipenyuk Date: Tue, 5 Nov 2024 15:06:16 -0500 Subject: [PATCH 70/82] Add fixAMMv1_2 amendment (#5176) * Add reserve check on AMM Withdraw * Try AMM max offer if changeSpotPriceQuality() fails --- include/xrpl/protocol/Feature.h | 2 +- include/xrpl/protocol/detail/features.macro | 1 + src/test/app/AMM_test.cpp | 51 +++++++++++++++++++++ src/xrpld/app/paths/detail/AMMLiquidity.cpp | 7 +++ src/xrpld/app/tx/detail/AMMClawback.cpp | 3 ++ src/xrpld/app/tx/detail/AMMWithdraw.cpp | 37 +++++++++++++++ src/xrpld/app/tx/detail/AMMWithdraw.h | 4 ++ 7 files changed, 104 insertions(+), 1 deletion(-) diff --git a/include/xrpl/protocol/Feature.h b/include/xrpl/protocol/Feature.h index a2510c63000..d8353f50a44 100644 --- a/include/xrpl/protocol/Feature.h +++ b/include/xrpl/protocol/Feature.h @@ -80,7 +80,7 @@ namespace detail { // Feature.cpp. Because it's only used to reserve storage, and determine how // large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than // the actual number of amendments. A LogicError on startup will verify this. -static constexpr std::size_t numFeatures = 81; +static constexpr std::size_t numFeatures = 82; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated diff --git a/include/xrpl/protocol/detail/features.macro b/include/xrpl/protocol/detail/features.macro index e5351be11c0..c0d2706cc1a 100644 --- a/include/xrpl/protocol/detail/features.macro +++ b/include/xrpl/protocol/detail/features.macro @@ -29,6 +29,7 @@ // If you add an amendment here, then do not forget to increment `numFeatures` // in include/xrpl/protocol/Feature.h. +XRPL_FIX (AMMv1_2, Supported::yes, VoteBehavior::DefaultNo) // InvariantsV1_1 will be changes to Supported::yes when all the // invariants expected to be included under it are complete. XRPL_FEATURE(MPTokensV1, Supported::yes, VoteBehavior::DefaultNo) diff --git a/src/test/app/AMM_test.cpp b/src/test/app/AMM_test.cpp index 8e764390e9a..f1e81132c5e 100644 --- a/src/test/app/AMM_test.cpp +++ b/src/test/app/AMM_test.cpp @@ -7064,6 +7064,55 @@ struct AMM_test : public jtx::AMMTest } } + void + testFixReserveCheckOnWithdrawal(FeatureBitset features) + { + testcase("Fix Reserve Check On Withdrawal"); + using namespace jtx; + + auto const err = features[fixAMMv1_2] ? ter(tecINSUFFICIENT_RESERVE) + : ter(tesSUCCESS); + + auto test = [&](auto&& cb) { + Env env(*this, features); + auto const starting_xrp = + reserve(env, 2) + env.current()->fees().base * 5; + env.fund(starting_xrp, gw); + env.fund(starting_xrp, alice); + env.trust(USD(2'000), alice); + env.close(); + env(pay(gw, alice, USD(2'000))); + env.close(); + AMM amm(env, gw, EUR(1'000), USD(1'000)); + amm.deposit(alice, USD(1)); + cb(amm); + }; + + // Equal withdraw + test([&](AMM& amm) { amm.withdrawAll(alice, std::nullopt, err); }); + + // Equal withdraw with a limit + test([&](AMM& amm) { + amm.withdraw(WithdrawArg{ + .account = alice, + .asset1Out = EUR(0.1), + .asset2Out = USD(0.1), + .err = err}); + amm.withdraw(WithdrawArg{ + .account = alice, + .asset1Out = USD(0.1), + .asset2Out = EUR(0.1), + .err = err}); + }); + + // Single withdraw + test([&](AMM& amm) { + amm.withdraw(WithdrawArg{ + .account = alice, .asset1Out = EUR(0.1), .err = err}); + amm.withdraw(WithdrawArg{.account = alice, .asset1Out = USD(0.1)}); + }); + } + void run() override { @@ -7117,6 +7166,8 @@ struct AMM_test : public jtx::AMMTest testAMMDepositWithFrozenAssets(all); testAMMDepositWithFrozenAssets(all - featureAMMClawback); testAMMDepositWithFrozenAssets(all - fixAMMv1_1 - featureAMMClawback); + testFixReserveCheckOnWithdrawal(all); + testFixReserveCheckOnWithdrawal(all - fixAMMv1_2); } }; diff --git a/src/xrpld/app/paths/detail/AMMLiquidity.cpp b/src/xrpld/app/paths/detail/AMMLiquidity.cpp index 8215cdee593..7b1649c649e 100644 --- a/src/xrpld/app/paths/detail/AMMLiquidity.cpp +++ b/src/xrpld/app/paths/detail/AMMLiquidity.cpp @@ -211,6 +211,13 @@ AMMLiquidity::getOffer( return AMMOffer( *this, *amounts, balances, Quality{*amounts}); } + else if (view.rules().enabled(fixAMMv1_2)) + { + if (auto const maxAMMOffer = maxOffer(balances, view.rules()); + maxAMMOffer && + Quality{maxAMMOffer->amount()} > *clobQuality) + return maxAMMOffer; + } } catch (std::overflow_error const& e) { diff --git a/src/xrpld/app/tx/detail/AMMClawback.cpp b/src/xrpld/app/tx/detail/AMMClawback.cpp index 468a5a4c6a2..64150ded6da 100644 --- a/src/xrpld/app/tx/detail/AMMClawback.cpp +++ b/src/xrpld/app/tx/detail/AMMClawback.cpp @@ -188,6 +188,7 @@ AMMClawback::applyGuts(Sandbox& sb) 0, FreezeHandling::fhIGNORE_FREEZE, WithdrawAll::Yes, + mPriorBalance, ctx_.journal); else std::tie(result, newLPTokenBalance, amountWithdraw, amount2Withdraw) = @@ -267,6 +268,7 @@ AMMClawback::equalWithdrawMatchingOneAmount( 0, FreezeHandling::fhIGNORE_FREEZE, WithdrawAll::Yes, + mPriorBalance, ctx_.journal); // Because we are doing a two-asset withdrawal, @@ -284,6 +286,7 @@ AMMClawback::equalWithdrawMatchingOneAmount( 0, FreezeHandling::fhIGNORE_FREEZE, WithdrawAll::No, + mPriorBalance, ctx_.journal); } diff --git a/src/xrpld/app/tx/detail/AMMWithdraw.cpp b/src/xrpld/app/tx/detail/AMMWithdraw.cpp index 0a6f3291b78..118262905c1 100644 --- a/src/xrpld/app/tx/detail/AMMWithdraw.cpp +++ b/src/xrpld/app/tx/detail/AMMWithdraw.cpp @@ -472,6 +472,7 @@ AMMWithdraw::withdraw( tfee, FreezeHandling::fhZERO_IF_FROZEN, isWithdrawAll(ctx_.tx), + mPriorBalance, j_); return {ter, newLPTokenBalance}; } @@ -490,6 +491,7 @@ AMMWithdraw::withdraw( std::uint16_t tfee, FreezeHandling freezeHandling, WithdrawAll withdrawAll, + XRPAmount const& priorBalance, beast::Journal const& journal) { auto const lpTokens = ammLPHolds(view, ammSle, account, journal); @@ -589,6 +591,33 @@ AMMWithdraw::withdraw( return {tecAMM_BALANCE, STAmount{}, STAmount{}, STAmount{}}; } + // Check the reserve in case a trustline has to be created + bool const enabledFixAMMv1_2 = view.rules().enabled(fixAMMv1_2); + auto sufficientReserve = [&](Issue const& issue) -> TER { + if (!enabledFixAMMv1_2 || isXRP(issue)) + return tesSUCCESS; + if (!view.exists(keylet::line(account, issue))) + { + auto const sleAccount = view.read(keylet::account(account)); + if (!sleAccount) + return tecINTERNAL; // LCOV_EXCL_LINE + auto const balance = (*sleAccount)[sfBalance].xrp(); + std::uint32_t const ownerCount = sleAccount->at(sfOwnerCount); + + // See also SetTrust::doApply() + XRPAmount const reserve( + (ownerCount < 2) ? XRPAmount(beast::zero) + : view.fees().accountReserve(ownerCount + 1)); + + if (std::max(priorBalance, balance) < reserve) + return tecINSUFFICIENT_RESERVE; + } + return tesSUCCESS; + }; + + if (auto const err = sufficientReserve(amountWithdrawActual.issue())) + return {err, STAmount{}, STAmount{}, STAmount{}}; + // Withdraw amountWithdraw auto res = accountSend( view, @@ -609,6 +638,10 @@ AMMWithdraw::withdraw( // Withdraw amount2Withdraw if (amount2WithdrawActual) { + if (auto const err = sufficientReserve(amount2WithdrawActual->issue()); + err != tesSUCCESS) + return {err, STAmount{}, STAmount{}, STAmount{}}; + res = accountSend( view, ammAccount, @@ -676,6 +709,7 @@ AMMWithdraw::equalWithdrawTokens( tfee, FreezeHandling::fhZERO_IF_FROZEN, isWithdrawAll(ctx_.tx), + mPriorBalance, ctx_.journal); return {ter, newLPTokenBalance}; } @@ -725,6 +759,7 @@ AMMWithdraw::equalWithdrawTokens( std::uint16_t tfee, FreezeHandling freezeHanding, WithdrawAll withdrawAll, + XRPAmount const& priorBalance, beast::Journal const& journal) { try @@ -745,6 +780,7 @@ AMMWithdraw::equalWithdrawTokens( tfee, freezeHanding, WithdrawAll::Yes, + priorBalance, journal); } @@ -773,6 +809,7 @@ AMMWithdraw::equalWithdrawTokens( tfee, freezeHanding, withdrawAll, + priorBalance, journal); } // LCOV_EXCL_START diff --git a/src/xrpld/app/tx/detail/AMMWithdraw.h b/src/xrpld/app/tx/detail/AMMWithdraw.h index f5b6b52e5ba..ae9328cb05e 100644 --- a/src/xrpld/app/tx/detail/AMMWithdraw.h +++ b/src/xrpld/app/tx/detail/AMMWithdraw.h @@ -96,6 +96,7 @@ class AMMWithdraw : public Transactor * @param lpTokensWithdraw amount of tokens to withdraw * @param tfee trading fee in basis points * @param withdrawAll if withdrawing all lptokens + * @param priorBalance balance before fees * @return */ static std::tuple> @@ -112,6 +113,7 @@ class AMMWithdraw : public Transactor std::uint16_t tfee, FreezeHandling freezeHanding, WithdrawAll withdrawAll, + XRPAmount const& priorBalance, beast::Journal const& journal); /** Withdraw requested assets and token from AMM into LP account. @@ -127,6 +129,7 @@ class AMMWithdraw : public Transactor * @param lpTokensWithdraw amount of lptokens to withdraw * @param tfee trading fee in basis points * @param withdrawAll if withdraw all lptokens + * @param priorBalance balance before fees * @return */ static std::tuple> @@ -143,6 +146,7 @@ class AMMWithdraw : public Transactor std::uint16_t tfee, FreezeHandling freezeHandling, WithdrawAll withdrawAll, + XRPAmount const& priorBalance, beast::Journal const& journal); static std::pair From c5c0e70e23d8f0ae06147e8cad9050f5bacc207c Mon Sep 17 00:00:00 2001 From: Gregory Tsipenyuk Date: Wed, 6 Nov 2024 11:20:30 -0500 Subject: [PATCH 71/82] Fix token comparison in Payment (#5172) * Checks only Currency or MPT Issuance ID part of the Asset object. * Resolves temREDUNDANT regression detected in testing. --- include/xrpl/protocol/Asset.h | 29 ++++++ src/libxrpl/protocol/Asset.cpp | 7 ++ src/test/app/MPToken_test.cpp | 132 ++++++++++++++++++++++++++++ src/xrpld/app/tx/detail/Payment.cpp | 2 +- 4 files changed, 169 insertions(+), 1 deletion(-) diff --git a/include/xrpl/protocol/Asset.h b/include/xrpl/protocol/Asset.h index bfb72ab61fc..2cccc28bd41 100644 --- a/include/xrpl/protocol/Asset.h +++ b/include/xrpl/protocol/Asset.h @@ -97,6 +97,12 @@ class Asset friend constexpr bool operator==(Currency const& lhs, Asset const& rhs); + + /** Return true if both assets refer to the same currency (regardless of + * issuer) or MPT issuance. Otherwise return false. + */ + friend constexpr bool + equalTokens(Asset const& lhs, Asset const& rhs); }; template @@ -157,6 +163,26 @@ operator==(Currency const& lhs, Asset const& rhs) return rhs.holds() && rhs.get().currency == lhs; } +constexpr bool +equalTokens(Asset const& lhs, Asset const& rhs) +{ + return std::visit( + [&]( + TLhs const& issLhs, TRhs const& issRhs) { + if constexpr ( + std::is_same_v && std::is_same_v) + return issLhs.currency == issRhs.currency; + else if constexpr ( + std::is_same_v && + std::is_same_v) + return issLhs.getMptID() == issRhs.getMptID(); + else + return false; + }, + lhs.issue_, + rhs.issue_); +} + inline bool isXRP(Asset const& asset) { @@ -172,6 +198,9 @@ validJSONAsset(Json::Value const& jv); Asset assetFromJson(Json::Value const& jv); +Json::Value +to_json(Asset const& asset); + } // namespace ripple #endif // RIPPLE_PROTOCOL_ASSET_H_INCLUDED diff --git a/src/libxrpl/protocol/Asset.cpp b/src/libxrpl/protocol/Asset.cpp index 67323f8614b..5a496352840 100644 --- a/src/libxrpl/protocol/Asset.cpp +++ b/src/libxrpl/protocol/Asset.cpp @@ -70,4 +70,11 @@ assetFromJson(Json::Value const& v) return mptIssueFromJson(v); } +Json::Value +to_json(Asset const& asset) +{ + return std::visit( + [&](auto const& issue) { return to_json(issue); }, asset.value()); +} + } // namespace ripple diff --git a/src/test/app/MPToken_test.cpp b/src/test/app/MPToken_test.cpp index 0f92212288d..69c5d90111c 100644 --- a/src/test/app/MPToken_test.cpp +++ b/src/test/app/MPToken_test.cpp @@ -1950,6 +1950,132 @@ class MPToken_test : public beast::unit_test::suite } } + void + testTokensEquality() + { + using namespace test::jtx; + testcase("Tokens Equality"); + Currency const cur1{to_currency("CU1")}; + Currency const cur2{to_currency("CU2")}; + Account const gw1{"gw1"}; + Account const gw2{"gw2"}; + MPTID const mpt1 = makeMptID(1, gw1); + MPTID const mpt1a = makeMptID(1, gw1); + MPTID const mpt2 = makeMptID(1, gw2); + MPTID const mpt3 = makeMptID(2, gw2); + Asset const assetCur1Gw1{Issue{cur1, gw1}}; + Asset const assetCur1Gw1a{Issue{cur1, gw1}}; + Asset const assetCur2Gw1{Issue{cur2, gw1}}; + Asset const assetCur2Gw2{Issue{cur2, gw2}}; + Asset const assetMpt1Gw1{mpt1}; + Asset const assetMpt1Gw1a{mpt1a}; + Asset const assetMpt1Gw2{mpt2}; + Asset const assetMpt2Gw2{mpt3}; + + // Assets holding Issue + // Currencies are equal regardless of the issuer + BEAST_EXPECT(equalTokens(assetCur1Gw1, assetCur1Gw1a)); + BEAST_EXPECT(equalTokens(assetCur2Gw1, assetCur2Gw2)); + // Currencies are different regardless of whether the issuers + // are the same or not + BEAST_EXPECT(!equalTokens(assetCur1Gw1, assetCur2Gw1)); + BEAST_EXPECT(!equalTokens(assetCur1Gw1, assetCur2Gw2)); + + // Assets holding MPTIssue + // MPTIDs are the same if the sequence and the issuer are the same + BEAST_EXPECT(equalTokens(assetMpt1Gw1, assetMpt1Gw1a)); + // MPTIDs are different if sequence and the issuer don't match + BEAST_EXPECT(!equalTokens(assetMpt1Gw1, assetMpt1Gw2)); + BEAST_EXPECT(!equalTokens(assetMpt1Gw2, assetMpt2Gw2)); + + // Assets holding Issue and MPTIssue + BEAST_EXPECT(!equalTokens(assetCur1Gw1, assetMpt1Gw1)); + BEAST_EXPECT(!equalTokens(assetMpt2Gw2, assetCur2Gw2)); + } + + void + testHelperFunctions() + { + using namespace test::jtx; + Account const gw{"gw"}; + Asset const asset1{makeMptID(1, gw)}; + Asset const asset2{makeMptID(2, gw)}; + Asset const asset3{makeMptID(3, gw)}; + STAmount const amt1{asset1, 100}; + STAmount const amt2{asset2, 100}; + STAmount const amt3{asset3, 10'000}; + + { + testcase("Test STAmount MPT arithmetics"); + using namespace std::string_literals; + STAmount res = multiply(amt1, amt2, asset3); + BEAST_EXPECT(res == amt3); + + res = mulRound(amt1, amt2, asset3, true); + BEAST_EXPECT(res == amt3); + + res = mulRoundStrict(amt1, amt2, asset3, true); + BEAST_EXPECT(res == amt3); + + // overflow, any value > 3037000499ull + STAmount mptOverflow{asset2, UINT64_C(3037000500)}; + try + { + res = multiply(mptOverflow, mptOverflow, asset3); + fail("should throw runtime exception 1"); + } + catch (std::runtime_error const& e) + { + BEAST_EXPECTS(e.what() == "MPT value overflow"s, e.what()); + } + // overflow, (v1 >> 32) * v2 > 2147483648ull + mptOverflow = STAmount{asset2, UINT64_C(2147483648)}; + uint64_t const mantissa = (2ull << 32) + 2; + try + { + res = multiply(STAmount{asset1, mantissa}, mptOverflow, asset3); + fail("should throw runtime exception 2"); + } + catch (std::runtime_error const& e) + { + BEAST_EXPECTS(e.what() == "MPT value overflow"s, e.what()); + } + } + + { + testcase("Test MPTAmount arithmetics"); + MPTAmount mptAmt1{100}; + MPTAmount const mptAmt2{100}; + BEAST_EXPECT((mptAmt1 += mptAmt2) == MPTAmount{200}); + BEAST_EXPECT(mptAmt1 == 200); + BEAST_EXPECT((mptAmt1 -= mptAmt2) == mptAmt1); + BEAST_EXPECT(mptAmt1 == mptAmt2); + BEAST_EXPECT(mptAmt1 == 100); + BEAST_EXPECT(MPTAmount::minPositiveAmount() == MPTAmount{1}); + } + + { + testcase("Test MPTIssue from/to Json"); + MPTIssue const issue1{asset1.get()}; + Json::Value const jv = to_json(issue1); + BEAST_EXPECT( + jv[jss::mpt_issuance_id] == to_string(asset1.get())); + BEAST_EXPECT(issue1 == mptIssueFromJson(jv)); + } + + { + testcase("Test Asset from/to Json"); + Json::Value const jv = to_json(asset1); + BEAST_EXPECT( + jv[jss::mpt_issuance_id] == to_string(asset1.get())); + BEAST_EXPECT( + to_string(jv) == + "{\"mpt_issuance_id\":" + "\"00000001A407AF5856CCF3C42619DAA925813FC955C72983\"}"); + BEAST_EXPECT(asset1 == assetFromJson(jv)); + } + } + public: void run() override @@ -1985,6 +2111,12 @@ class MPToken_test : public beast::unit_test::suite // Test parsed MPTokenIssuanceID in API response metadata testTxJsonMetaFields(all); + + // Test tokens equality + testTokensEquality(); + + // Test helpers + testHelperFunctions(); } }; diff --git a/src/xrpld/app/tx/detail/Payment.cpp b/src/xrpld/app/tx/detail/Payment.cpp index 25ec119d6ae..77c8d015d1e 100644 --- a/src/xrpld/app/tx/detail/Payment.cpp +++ b/src/xrpld/app/tx/detail/Payment.cpp @@ -145,7 +145,7 @@ Payment::preflight(PreflightContext const& ctx) JLOG(j.trace()) << "Malformed transaction: " << "Bad currency."; return temBAD_CURRENCY; } - if (account == dstAccountID && srcAsset == dstAsset && !hasPaths) + if (account == dstAccountID && equalTokens(srcAsset, dstAsset) && !hasPaths) { // You're signing yourself a payment. // If hasPaths is true, you might be trying some arbitrage. From 8e827e32ace41a410a738ccb8ee19c064469b337 Mon Sep 17 00:00:00 2001 From: Olek <115580134+oleks-rip@users.noreply.github.com> Date: Wed, 6 Nov 2024 17:05:03 -0500 Subject: [PATCH 72/82] Introduce Credentials support (XLS-70d): (#5103) Amendment: - Credentials New Transactions: - CredentialCreate - CredentialAccept - CredentialDelete Modified Transactions: - DepositPreauth - Payment - EscrowFinish - PaymentChannelClaim - AccountDelete New Object: - Credential Modified Object: - DepositPreauth API updates: - ledger_entry - account_objects - ledger_data - deposit_authorized Read full spec: https://github.com/XRPLF/XRPL-Standards/tree/master/XLS-0070d-credentials --- include/xrpl/protocol/ErrorCodes.h | 5 +- include/xrpl/protocol/Feature.h | 2 +- include/xrpl/protocol/HashPrefix.h | 3 + include/xrpl/protocol/Indexes.h | 18 + include/xrpl/protocol/LedgerFormats.h | 3 + include/xrpl/protocol/Protocol.h | 9 + include/xrpl/protocol/TER.h | 1 + include/xrpl/protocol/UintTypes.h | 6 + include/xrpl/protocol/detail/features.macro | 4 +- .../xrpl/protocol/detail/ledger_entries.macro | 18 +- include/xrpl/protocol/detail/sfields.macro | 8 + .../xrpl/protocol/detail/transactions.macro | 29 + include/xrpl/protocol/jss.h | 8 + src/libxrpl/protocol/ErrorCodes.cpp | 3 +- src/libxrpl/protocol/Indexes.cpp | 30 + src/libxrpl/protocol/InnerObjectFormats.cpp | 7 + src/libxrpl/protocol/TER.cpp | 1 + src/test/app/AccountDelete_test.cpp | 362 ++++++ src/test/app/Check_test.cpp | 10 - src/test/app/Clawback_test.cpp | 10 - src/test/app/Credentials_test.cpp | 1079 +++++++++++++++++ src/test/app/DID_test.cpp | 10 - src/test/app/DepositAuth_test.cpp | 829 +++++++++++++ src/test/app/Escrow_test.cpp | 149 +++ src/test/app/FixNFTokenPageLinks_test.cpp | 10 - src/test/app/MPToken_test.cpp | 152 +++ src/test/app/NFTokenBurn_test.cpp | 10 - src/test/app/NFToken_test.cpp | 12 +- src/test/app/Oracle_test.cpp | 10 - src/test/app/PayChan_test.cpp | 185 +++ src/test/jtx.h | 1 + src/test/jtx/TestHelpers.h | 4 + src/test/jtx/credentials.h | 104 ++ src/test/jtx/deposit.h | 35 + src/test/jtx/impl/TestHelpers.cpp | 11 +- src/test/jtx/impl/credentials.cpp | 110 ++ src/test/jtx/impl/deposit.cpp | 40 + src/test/jtx/impl/mpt.cpp | 13 +- src/test/jtx/mpt.h | 3 +- src/test/rpc/DepositAuthorized_test.cpp | 351 +++++- src/test/rpc/LedgerRPC_test.cpp | 496 ++++++++ src/test/rpc/RPCCall_test.cpp | 23 +- src/xrpld/app/main/Main.cpp | 2 +- src/xrpld/app/misc/CredentialHelpers.cpp | 262 ++++ src/xrpld/app/misc/CredentialHelpers.h | 77 ++ src/xrpld/app/tx/detail/Credentials.cpp | 382 ++++++ src/xrpld/app/tx/detail/Credentials.h | 87 ++ src/xrpld/app/tx/detail/DeleteAccount.cpp | 60 +- src/xrpld/app/tx/detail/DepositPreauth.cpp | 218 +++- src/xrpld/app/tx/detail/DepositPreauth.h | 1 - src/xrpld/app/tx/detail/Escrow.cpp | 37 +- src/xrpld/app/tx/detail/Escrow.h | 3 + src/xrpld/app/tx/detail/InvariantCheck.cpp | 1 + src/xrpld/app/tx/detail/PayChan.cpp | 36 +- src/xrpld/app/tx/detail/PayChan.h | 3 + src/xrpld/app/tx/detail/Payment.cpp | 57 +- src/xrpld/app/tx/detail/Transactor.cpp | 42 +- src/xrpld/app/tx/detail/applySteps.cpp | 1 + src/xrpld/net/detail/RPCCall.cpp | 15 +- src/xrpld/rpc/detail/RPCHelpers.cpp | 5 +- src/xrpld/rpc/handlers/DepositAuthorized.cpp | 110 +- src/xrpld/rpc/handlers/LedgerEntry.cpp | 135 ++- 62 files changed, 5491 insertions(+), 217 deletions(-) create mode 100644 src/test/app/Credentials_test.cpp create mode 100644 src/test/jtx/credentials.h create mode 100644 src/test/jtx/impl/credentials.cpp create mode 100644 src/xrpld/app/misc/CredentialHelpers.cpp create mode 100644 src/xrpld/app/misc/CredentialHelpers.h create mode 100644 src/xrpld/app/tx/detail/Credentials.cpp create mode 100644 src/xrpld/app/tx/detail/Credentials.h diff --git a/include/xrpl/protocol/ErrorCodes.h b/include/xrpl/protocol/ErrorCodes.h index d8ec3052b7b..39cfa9369cd 100644 --- a/include/xrpl/protocol/ErrorCodes.h +++ b/include/xrpl/protocol/ErrorCodes.h @@ -148,7 +148,10 @@ enum error_code_i { // Oracle rpcORACLE_MALFORMED = 94, - rpcLAST = rpcORACLE_MALFORMED // rpcLAST should always equal the last code. + // deposit_authorized + credentials + rpcBAD_CREDENTIALS = 95, + + rpcLAST = rpcBAD_CREDENTIALS // rpcLAST should always equal the last code. }; /** Codes returned in the `warnings` array of certain RPC commands. diff --git a/include/xrpl/protocol/Feature.h b/include/xrpl/protocol/Feature.h index d8353f50a44..90a81c55ef4 100644 --- a/include/xrpl/protocol/Feature.h +++ b/include/xrpl/protocol/Feature.h @@ -80,7 +80,7 @@ namespace detail { // Feature.cpp. Because it's only used to reserve storage, and determine how // large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than // the actual number of amendments. A LogicError on startup will verify this. -static constexpr std::size_t numFeatures = 82; +static constexpr std::size_t numFeatures = 83; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated diff --git a/include/xrpl/protocol/HashPrefix.h b/include/xrpl/protocol/HashPrefix.h index bc9c23d1910..0b6ddda4921 100644 --- a/include/xrpl/protocol/HashPrefix.h +++ b/include/xrpl/protocol/HashPrefix.h @@ -84,6 +84,9 @@ enum class HashPrefix : std::uint32_t { /** Payment Channel Claim */ paymentChannelClaim = detail::make_hash_prefix('C', 'L', 'M'), + + /** Credentials signature */ + credential = detail::make_hash_prefix('C', 'R', 'D'), }; template diff --git a/include/xrpl/protocol/Indexes.h b/include/xrpl/protocol/Indexes.h index 8249eabb43a..72cf0b527b1 100644 --- a/include/xrpl/protocol/Indexes.h +++ b/include/xrpl/protocol/Indexes.h @@ -30,6 +30,7 @@ #include #include #include + #include namespace ripple { @@ -189,6 +190,11 @@ check(uint256 const& key) noexcept Keylet depositPreauth(AccountID const& owner, AccountID const& preauthorized) noexcept; +Keylet +depositPreauth( + AccountID const& owner, + std::set> const& authCreds) noexcept; + inline Keylet depositPreauth(uint256 const& key) noexcept { @@ -287,6 +293,18 @@ did(AccountID const& account) noexcept; Keylet oracle(AccountID const& account, std::uint32_t const& documentID) noexcept; +Keylet +credential( + AccountID const& subject, + AccountID const& issuer, + Slice const& credType) noexcept; + +inline Keylet +credential(uint256 const& key) noexcept +{ + return {ltCREDENTIAL, key}; +} + Keylet mptIssuance(std::uint32_t seq, AccountID const& issuer) noexcept; diff --git a/include/xrpl/protocol/LedgerFormats.h b/include/xrpl/protocol/LedgerFormats.h index b0374db1c29..4f3eef4919d 100644 --- a/include/xrpl/protocol/LedgerFormats.h +++ b/include/xrpl/protocol/LedgerFormats.h @@ -186,6 +186,9 @@ enum LedgerSpecificFlags { // ltMPTOKEN lsfMPTAuthorized = 0x00000002, + + // ltCREDENTIAL + lsfAccepted = 0x00010000, }; //------------------------------------------------------------------------------ diff --git a/include/xrpl/protocol/Protocol.h b/include/xrpl/protocol/Protocol.h index f706b6a3bbb..a9bd10a6fd1 100644 --- a/include/xrpl/protocol/Protocol.h +++ b/include/xrpl/protocol/Protocol.h @@ -95,6 +95,15 @@ std::size_t constexpr maxDIDAttestationLength = 256; /** The maximum length of a domain */ std::size_t constexpr maxDomainLength = 256; +/** The maximum length of a URI inside a Credential */ +std::size_t constexpr maxCredentialURILength = 256; + +/** The maximum length of a CredentialType inside a Credential */ +std::size_t constexpr maxCredentialTypeLength = 64; + +/** The maximum number of credentials can be passed in array */ +std::size_t constexpr maxCredentialsArraySize = 8; + /** The maximum length of MPTokenMetadata */ std::size_t constexpr maxMPTokenMetadataLength = 1024; diff --git a/include/xrpl/protocol/TER.h b/include/xrpl/protocol/TER.h index cf297b0c37b..317e9c2c978 100644 --- a/include/xrpl/protocol/TER.h +++ b/include/xrpl/protocol/TER.h @@ -343,6 +343,7 @@ enum TECcodes : TERUnderlyingType { tecARRAY_EMPTY = 190, tecARRAY_TOO_LARGE = 191, tecLOCKED = 192, + tecBAD_CREDENTIALS = 193, }; //------------------------------------------------------------------------------ diff --git a/include/xrpl/protocol/UintTypes.h b/include/xrpl/protocol/UintTypes.h index cf676189bad..9a7284158e7 100644 --- a/include/xrpl/protocol/UintTypes.h +++ b/include/xrpl/protocol/UintTypes.h @@ -134,6 +134,12 @@ struct hash : ripple::Directory::hasher explicit hash() = default; }; +template <> +struct hash : ripple::uint256::hasher +{ + explicit hash() = default; +}; + } // namespace std #endif diff --git a/include/xrpl/protocol/detail/features.macro b/include/xrpl/protocol/detail/features.macro index c0d2706cc1a..24c6e72ae34 100644 --- a/include/xrpl/protocol/detail/features.macro +++ b/include/xrpl/protocol/detail/features.macro @@ -29,6 +29,8 @@ // If you add an amendment here, then do not forget to increment `numFeatures` // in include/xrpl/protocol/Feature.h. +XRPL_FEATURE(Credentials, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(AMMClawback, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (AMMv1_2, Supported::yes, VoteBehavior::DefaultNo) // InvariantsV1_1 will be changes to Supported::yes when all the // invariants expected to be included under it are complete. @@ -96,7 +98,7 @@ XRPL_FIX (1513, Supported::yes, VoteBehavior::DefaultYe XRPL_FEATURE(FlowCross, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(Flow, Supported::yes, VoteBehavior::DefaultYes) XRPL_FEATURE(OwnerPaysFee, Supported::no, VoteBehavior::DefaultNo) -XRPL_FEATURE(AMMClawback, Supported::yes, VoteBehavior::DefaultYes) + // The following amendments are obsolete, but must remain supported // because they could potentially get enabled. diff --git a/include/xrpl/protocol/detail/ledger_entries.macro b/include/xrpl/protocol/detail/ledger_entries.macro index 3c23539593d..0cb1ec3416a 100644 --- a/include/xrpl/protocol/detail/ledger_entries.macro +++ b/include/xrpl/protocol/detail/ledger_entries.macro @@ -245,10 +245,11 @@ LEDGER_ENTRY(ltOFFER, 0x006f, Offer, ({ */ LEDGER_ENTRY(ltDEPOSIT_PREAUTH, 0x0070, DepositPreauth, ({ {sfAccount, soeREQUIRED}, - {sfAuthorize, soeREQUIRED}, + {sfAuthorize, soeOPTIONAL}, {sfOwnerNode, soeREQUIRED}, {sfPreviousTxnID, soeREQUIRED}, {sfPreviousTxnLgrSeq, soeREQUIRED}, + {sfAuthorizeCredentials, soeOPTIONAL}, })) /** A claim id for a cross chain transaction. @@ -420,3 +421,18 @@ LEDGER_ENTRY(ltMPTOKEN, 0x007f, MPToken, ({ {sfPreviousTxnID, soeREQUIRED}, {sfPreviousTxnLgrSeq, soeREQUIRED}, })) + +/** A ledger object which tracks Credential + \sa keylet::credential + */ +LEDGER_ENTRY(ltCREDENTIAL, 0x0081, Credential, ({ + {sfSubject, soeREQUIRED}, + {sfIssuer, soeREQUIRED}, + {sfCredentialType, soeREQUIRED}, + {sfExpiration, soeOPTIONAL}, + {sfURI, soeOPTIONAL}, + {sfIssuerNode, soeREQUIRED}, + {sfSubjectNode, soeREQUIRED}, + {sfPreviousTxnID, soeREQUIRED}, + {sfPreviousTxnLgrSeq, soeREQUIRED}, +})) diff --git a/include/xrpl/protocol/detail/sfields.macro b/include/xrpl/protocol/detail/sfields.macro index e3a93fc7f46..ccf6350cbfc 100644 --- a/include/xrpl/protocol/detail/sfields.macro +++ b/include/xrpl/protocol/detail/sfields.macro @@ -140,6 +140,8 @@ TYPED_SFIELD(sfAssetPrice, UINT64, 23) TYPED_SFIELD(sfMaximumAmount, UINT64, 24, SField::sMD_BaseTen|SField::sMD_Default) TYPED_SFIELD(sfOutstandingAmount, UINT64, 25, SField::sMD_BaseTen|SField::sMD_Default) TYPED_SFIELD(sfMPTAmount, UINT64, 26, SField::sMD_BaseTen|SField::sMD_Default) +TYPED_SFIELD(sfIssuerNode, UINT64, 27) +TYPED_SFIELD(sfSubjectNode, UINT64, 28) // 128-bit TYPED_SFIELD(sfEmailHash, UINT128, 1) @@ -258,6 +260,7 @@ TYPED_SFIELD(sfData, VL, 27) TYPED_SFIELD(sfAssetClass, VL, 28) TYPED_SFIELD(sfProvider, VL, 29) TYPED_SFIELD(sfMPTokenMetadata, VL, 30) +TYPED_SFIELD(sfCredentialType, VL, 31) // account (common) TYPED_SFIELD(sfAccount, ACCOUNT, 1) @@ -280,12 +283,14 @@ TYPED_SFIELD(sfAttestationSignerAccount, ACCOUNT, 20) TYPED_SFIELD(sfAttestationRewardAccount, ACCOUNT, 21) TYPED_SFIELD(sfLockingChainDoor, ACCOUNT, 22) TYPED_SFIELD(sfIssuingChainDoor, ACCOUNT, 23) +TYPED_SFIELD(sfSubject, ACCOUNT, 24) // vector of 256-bit TYPED_SFIELD(sfIndexes, VECTOR256, 1, SField::sMD_Never) TYPED_SFIELD(sfHashes, VECTOR256, 2) TYPED_SFIELD(sfAmendments, VECTOR256, 3) TYPED_SFIELD(sfNFTokenOffers, VECTOR256, 4) +TYPED_SFIELD(sfCredentialIDs, VECTOR256, 5) // path set UNTYPED_SFIELD(sfPaths, PATHSET, 1) @@ -337,6 +342,7 @@ UNTYPED_SFIELD(sfXChainCreateAccountProofSig, OBJECT, 29) UNTYPED_SFIELD(sfXChainClaimAttestationCollectionElement, OBJECT, 30) UNTYPED_SFIELD(sfXChainCreateAccountAttestationCollectionElement, OBJECT, 31) UNTYPED_SFIELD(sfPriceData, OBJECT, 32) +UNTYPED_SFIELD(sfCredential, OBJECT, 33) // array of objects (common) // ARRAY/1 is reserved for end of array @@ -364,3 +370,5 @@ UNTYPED_SFIELD(sfXChainCreateAccountAttestations, ARRAY, 22) // 23 unused UNTYPED_SFIELD(sfPriceDataSeries, ARRAY, 24) UNTYPED_SFIELD(sfAuthAccounts, ARRAY, 25) +UNTYPED_SFIELD(sfAuthorizeCredentials, ARRAY, 26) +UNTYPED_SFIELD(sfUnauthorizeCredentials, ARRAY, 27) diff --git a/include/xrpl/protocol/detail/transactions.macro b/include/xrpl/protocol/detail/transactions.macro index a064abbc12b..4f4c8f12595 100644 --- a/include/xrpl/protocol/detail/transactions.macro +++ b/include/xrpl/protocol/detail/transactions.macro @@ -37,6 +37,7 @@ TRANSACTION(ttPAYMENT, 0, Payment, ({ {sfInvoiceID, soeOPTIONAL}, {sfDestinationTag, soeOPTIONAL}, {sfDeliverMin, soeOPTIONAL, soeMPTSupported}, + {sfCredentialIDs, soeOPTIONAL}, })) /** This transaction type creates an escrow object. */ @@ -55,6 +56,7 @@ TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish, ({ {sfOfferSequence, soeREQUIRED}, {sfFulfillment, soeOPTIONAL}, {sfCondition, soeOPTIONAL}, + {sfCredentialIDs, soeOPTIONAL}, })) @@ -139,6 +141,7 @@ TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim, ({ {sfBalance, soeOPTIONAL}, {sfSignature, soeOPTIONAL}, {sfPublicKey, soeOPTIONAL}, + {sfCredentialIDs, soeOPTIONAL}, })) /** This transaction type creates a new check. */ @@ -166,6 +169,8 @@ TRANSACTION(ttCHECK_CANCEL, 18, CheckCancel, ({ TRANSACTION(ttDEPOSIT_PREAUTH, 19, DepositPreauth, ({ {sfAuthorize, soeOPTIONAL}, {sfUnauthorize, soeOPTIONAL}, + {sfAuthorizeCredentials, soeOPTIONAL}, + {sfUnauthorizeCredentials, soeOPTIONAL}, })) /** This transaction type modifies a trustline between two accounts. */ @@ -179,6 +184,7 @@ TRANSACTION(ttTRUST_SET, 20, TrustSet, ({ TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete, ({ {sfDestination, soeREQUIRED}, {sfDestinationTag, soeOPTIONAL}, + {sfCredentialIDs, soeOPTIONAL}, })) // 22 reserved @@ -420,6 +426,28 @@ TRANSACTION(ttMPTOKEN_AUTHORIZE, 57, MPTokenAuthorize, ({ {sfHolder, soeOPTIONAL}, })) +/** This transaction type create an Credential instance */ +TRANSACTION(ttCREDENTIAL_CREATE, 58, CredentialCreate, ({ + {sfSubject, soeREQUIRED}, + {sfCredentialType, soeREQUIRED}, + {sfExpiration, soeOPTIONAL}, + {sfURI, soeOPTIONAL}, +})) + +/** This transaction type accept an Credential object */ +TRANSACTION(ttCREDENTIAL_ACCEPT, 59, CredentialAccept, ({ + {sfIssuer, soeREQUIRED}, + {sfCredentialType, soeREQUIRED}, +})) + +/** This transaction type delete an Credential object */ +TRANSACTION(ttCREDENTIAL_DELETE, 60, CredentialDelete, ({ + {sfSubject, soeOPTIONAL}, + {sfIssuer, soeOPTIONAL}, + {sfCredentialType, soeREQUIRED}, +})) + + /** This system-generated transaction type is used to update the status of the various amendments. For details, see: https://xrpl.org/amendments.html @@ -455,3 +483,4 @@ TRANSACTION(ttUNL_MODIFY, 102, UNLModify, ({ {sfLedgerSequence, soeREQUIRED}, {sfUNLModifyValidator, soeREQUIRED}, })) + diff --git a/include/xrpl/protocol/jss.h b/include/xrpl/protocol/jss.h index 90e5b1c6e47..f9e0db24949 100644 --- a/include/xrpl/protocol/jss.h +++ b/include/xrpl/protocol/jss.h @@ -63,6 +63,7 @@ JSS(BidMin); // in: AMM Bid JSS(Bridge); // ledger type. JSS(Check); // ledger type. JSS(ClearFlag); // field. +JSS(Credential); // ledger type. JSS(DID); // ledger type. JSS(DeliverMax); // out: alias to Amount JSS(DeliverMin); // in: TransactionSign @@ -75,6 +76,7 @@ JSS(FeeSettings); // ledger type. JSS(Flags); // in/out: TransactionSign; field. JSS(Holder); // field. JSS(Invalid); // +JSS(Issuer); // in: Credential transactions JSS(LastLedgerSequence); // in: TransactionSign; field JSS(LastUpdateTime); // field. JSS(LedgerHashes); // ledger type. @@ -107,6 +109,7 @@ JSS(Sequence); // in/out: TransactionSign; field. JSS(SetFlag); // field. JSS(SignerList); // ledger type. JSS(SigningPubKey); // field. +JSS(Subject); // in: Credential transactions JSS(TakerGets); // field. JSS(TakerPays); // field. JSS(Ticket); // ledger type. @@ -165,6 +168,7 @@ JSS(attestations); JSS(attestation_reward_account); JSS(auction_slot); // out: amm_info JSS(authorized); // out: AccountLines +JSS(authorized_credentials); // in: ledger_entry DepositPreauth JSS(auth_accounts); // out: amm_info JSS(auth_change); // out: AccountInfo JSS(auth_change_queued); // out: AccountInfo @@ -228,6 +232,9 @@ JSS(converge_time_s); // out: NetworkOPs JSS(cookie); // out: NetworkOPs JSS(count); // in: AccountTx*, ValidatorList JSS(counters); // in/out: retrieve counters +JSS(credential); // in: LedgerEntry Credential +JSS(credentials); // in: deposit_authorized +JSS(credential_type); // in: LedgerEntry DepositPreauth JSS(ctid); // in/out: Tx RPC JSS(currency_a); // out: BookChanges JSS(currency_b); // out: BookChanges @@ -614,6 +621,7 @@ JSS(streams); // in: Subscribe, Unsubscribe JSS(strict); // in: AccountCurrencies, AccountInfo JSS(sub_index); // in: LedgerEntry JSS(subcommand); // in: PathFind +JSS(subject); // in: LedgerEntry Credential JSS(success); // rpc JSS(supported); // out: AmendmentTableImpl JSS(sync_mode); // in: Submit diff --git a/src/libxrpl/protocol/ErrorCodes.cpp b/src/libxrpl/protocol/ErrorCodes.cpp index 4c934f4fd53..c157d9b296c 100644 --- a/src/libxrpl/protocol/ErrorCodes.cpp +++ b/src/libxrpl/protocol/ErrorCodes.cpp @@ -108,7 +108,8 @@ constexpr static ErrorInfo unorderedErrorInfos[]{ {rpcTOO_BUSY, "tooBusy", "The server is too busy to help you now.", 503}, {rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found.", 404}, {rpcUNKNOWN_COMMAND, "unknownCmd", "Unknown method.", 405}, - {rpcORACLE_MALFORMED, "oracleMalformed", "Oracle request is malformed.", 400}}; + {rpcORACLE_MALFORMED, "oracleMalformed", "Oracle request is malformed.", 400}, + {rpcBAD_CREDENTIALS, "badCredentials", "Credentials do not exist, are not accepted, or have expired.", 400}}; // clang-format on // Sort and validate unorderedErrorInfos at compile time. Should be diff --git a/src/libxrpl/protocol/Indexes.cpp b/src/libxrpl/protocol/Indexes.cpp index 9a537eaaf2b..12142879ad5 100644 --- a/src/libxrpl/protocol/Indexes.cpp +++ b/src/libxrpl/protocol/Indexes.cpp @@ -63,6 +63,7 @@ enum class LedgerNameSpace : std::uint16_t { XRP_PAYMENT_CHANNEL = 'x', CHECK = 'C', DEPOSIT_PREAUTH = 'p', + DEPOSIT_PREAUTH_CREDENTIALS = 'P', NEGATIVE_UNL = 'N', NFTOKEN_OFFER = 'q', NFTOKEN_BUY_OFFERS = 'h', @@ -75,6 +76,7 @@ enum class LedgerNameSpace : std::uint16_t { ORACLE = 'R', MPTOKEN_ISSUANCE = '~', MPTOKEN = 't', + CREDENTIAL = 'D', // No longer used or supported. Left here to reserve the space // to avoid accidental reuse. @@ -313,6 +315,22 @@ depositPreauth(AccountID const& owner, AccountID const& preauthorized) noexcept indexHash(LedgerNameSpace::DEPOSIT_PREAUTH, owner, preauthorized)}; } +// Credentials should be sorted here, use credentials::makeSorted +Keylet +depositPreauth( + AccountID const& owner, + std::set> const& authCreds) noexcept +{ + std::vector hashes; + hashes.reserve(authCreds.size()); + for (auto const& o : authCreds) + hashes.emplace_back(sha512Half(o.first, o.second)); + + return { + ltDEPOSIT_PREAUTH, + indexHash(LedgerNameSpace::DEPOSIT_PREAUTH_CREDENTIALS, owner, hashes)}; +} + //------------------------------------------------------------------------------ Keylet @@ -489,6 +507,18 @@ mptoken(uint256 const& issuanceKey, AccountID const& holder) noexcept return { ltMPTOKEN, indexHash(LedgerNameSpace::MPTOKEN, issuanceKey, holder)}; } + +Keylet +credential( + AccountID const& subject, + AccountID const& issuer, + Slice const& credType) noexcept +{ + return { + ltCREDENTIAL, + indexHash(LedgerNameSpace::CREDENTIAL, subject, issuer, credType)}; +} + } // namespace keylet } // namespace ripple diff --git a/src/libxrpl/protocol/InnerObjectFormats.cpp b/src/libxrpl/protocol/InnerObjectFormats.cpp index 6d7b855d199..87c42a8085f 100644 --- a/src/libxrpl/protocol/InnerObjectFormats.cpp +++ b/src/libxrpl/protocol/InnerObjectFormats.cpp @@ -147,6 +147,13 @@ InnerObjectFormats::InnerObjectFormats() {sfAssetPrice, soeOPTIONAL}, {sfScale, soeDEFAULT}, }); + + add(sfCredential.jsonName.c_str(), + sfCredential.getCode(), + { + {sfIssuer, soeREQUIRED}, + {sfCredentialType, soeREQUIRED}, + }); } InnerObjectFormats const& diff --git a/src/libxrpl/protocol/TER.cpp b/src/libxrpl/protocol/TER.cpp index 90809b29981..815b27c0018 100644 --- a/src/libxrpl/protocol/TER.cpp +++ b/src/libxrpl/protocol/TER.cpp @@ -116,6 +116,7 @@ transResults() MAKE_ERROR(tecARRAY_EMPTY, "Array is empty."), MAKE_ERROR(tecARRAY_TOO_LARGE, "Array is too large."), MAKE_ERROR(tecLOCKED, "Fund is locked."), + MAKE_ERROR(tecBAD_CREDENTIALS, "Bad credentials."), MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."), MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."), diff --git a/src/test/app/AccountDelete_test.cpp b/src/test/app/AccountDelete_test.cpp index 5fbb0ba38b1..f8d3cf4692a 100644 --- a/src/test/app/AccountDelete_test.cpp +++ b/src/test/app/AccountDelete_test.cpp @@ -912,6 +912,366 @@ class AccountDelete_test : public beast::unit_test::suite env.close(); } + void + testDestinationDepositAuthCredentials() + { + { + testcase( + "Destination Constraints with DepositPreauth and Credentials"); + + using namespace test::jtx; + + Account const alice{"alice"}; + Account const becky{"becky"}; + Account const carol{"carol"}; + Account const daria{"daria"}; + + const char credType[] = "abcd"; + + Env env{*this}; + env.fund(XRP(100000), alice, becky, carol, daria); + env.close(); + + // carol issue credentials for becky + env(credentials::create(becky, carol, credType)); + env.close(); + + // get credentials index + auto const jv = + credentials::ledgerEntry(env, becky, carol, credType); + std::string const credIdx = jv[jss::result][jss::index].asString(); + + // Close enough ledgers to be able to delete becky's account. + incLgrSeqForAccDel(env, becky); + + auto const acctDelFee{drops(env.current()->fees().increment)}; + + // becky use credentials but they aren't accepted + env(acctdelete(becky, alice), + credentials::ids({credIdx}), + fee(acctDelFee), + ter(tecBAD_CREDENTIALS)); + env.close(); + + { + // alice sets the lsfDepositAuth flag on her account. This + // should prevent becky from deleting her account while using + // alice as the destination. + env(fset(alice, asfDepositAuth)); + env.close(); + } + + // Fail, credentials still not accepted + env(acctdelete(becky, alice), + credentials::ids({credIdx}), + fee(acctDelFee), + ter(tecBAD_CREDENTIALS)); + env.close(); + + // becky accept the credentials + env(credentials::accept(becky, carol, credType)); + env.close(); + + // Fail, credentials doesn’t belong to carol + env(acctdelete(carol, alice), + credentials::ids({credIdx}), + fee(acctDelFee), + ter(tecBAD_CREDENTIALS)); + + // Fail, no depositPreauth for provided credentials + env(acctdelete(becky, alice), + credentials::ids({credIdx}), + fee(acctDelFee), + ter(tecNO_PERMISSION)); + env.close(); + + // alice create DepositPreauth Object + env(deposit::authCredentials(alice, {{carol, credType}})); + env.close(); + + // becky attempts to delete her account, but alice won't take her + // XRP, so the delete is blocked. + env(acctdelete(becky, alice), + fee(acctDelFee), + ter(tecNO_PERMISSION)); + + // becky use empty credentials and can't delete account + env(acctdelete(becky, alice), + fee(acctDelFee), + credentials::ids({}), + ter(temMALFORMED)); + + // becky use bad credentials and can't delete account + env(acctdelete(becky, alice), + credentials::ids( + {"48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6E" + "A288BE4"}), + fee(acctDelFee), + ter(tecBAD_CREDENTIALS)); + env.close(); + + // becky use credentials and can delete account + env(acctdelete(becky, alice), + credentials::ids({credIdx}), + fee(acctDelFee)); + env.close(); + + { + // check that credential object deleted too + auto const jNoCred = + credentials::ledgerEntry(env, becky, carol, credType); + BEAST_EXPECT( + jNoCred.isObject() && jNoCred.isMember(jss::result) && + jNoCred[jss::result].isMember(jss::error) && + jNoCred[jss::result][jss::error] == "entryNotFound"); + } + + testcase("Credentials that aren't required"); + { // carol issue credentials for daria + env(credentials::create(daria, carol, credType)); + env.close(); + env(credentials::accept(daria, carol, credType)); + env.close(); + std::string const credDaria = + credentials::ledgerEntry( + env, daria, carol, credType)[jss::result][jss::index] + .asString(); + + // daria use valid credentials, which aren't required and can + // delete her account + env(acctdelete(daria, carol), + credentials::ids({credDaria}), + fee(acctDelFee)); + env.close(); + + // check that credential object deleted too + auto const jNoCred = + credentials::ledgerEntry(env, daria, carol, credType); + + BEAST_EXPECT( + jNoCred.isObject() && jNoCred.isMember(jss::result) && + jNoCred[jss::result].isMember(jss::error) && + jNoCred[jss::result][jss::error] == "entryNotFound"); + } + + { + Account const eaton{"eaton"}; + Account const fred{"fred"}; + + env.fund(XRP(5000), eaton, fred); + + // carol issue credentials for eaton + env(credentials::create(eaton, carol, credType)); + env.close(); + env(credentials::accept(eaton, carol, credType)); + env.close(); + std::string const credEaton = + credentials::ledgerEntry( + env, eaton, carol, credType)[jss::result][jss::index] + .asString(); + + // fred make preauthorization through authorized account + env(fset(fred, asfDepositAuth)); + env.close(); + env(deposit::auth(fred, eaton)); + env.close(); + + // Close enough ledgers to be able to delete becky's account. + incLgrSeqForAccDel(env, eaton); + auto const acctDelFee{drops(env.current()->fees().increment)}; + + // eaton use valid credentials, but he already authorized + // through "Authorized" field. + env(acctdelete(eaton, fred), + credentials::ids({credEaton}), + fee(acctDelFee)); + env.close(); + + // check that credential object deleted too + auto const jNoCred = + credentials::ledgerEntry(env, eaton, carol, credType); + + BEAST_EXPECT( + jNoCred.isObject() && jNoCred.isMember(jss::result) && + jNoCred[jss::result].isMember(jss::error) && + jNoCred[jss::result][jss::error] == "entryNotFound"); + } + + testcase("Expired credentials"); + { + Account const john{"john"}; + + env.fund(XRP(10000), john); + env.close(); + + auto jv = credentials::create(john, carol, credType); + uint32_t const t = env.current() + ->info() + .parentCloseTime.time_since_epoch() + .count() + + 20; + jv[sfExpiration.jsonName] = t; + env(jv); + env.close(); + env(credentials::accept(john, carol, credType)); + env.close(); + jv = credentials::ledgerEntry(env, john, carol, credType); + std::string const credIdx = + jv[jss::result][jss::index].asString(); + + incLgrSeqForAccDel(env, john); + + // credentials are expired + // john use credentials but can't delete account + env(acctdelete(john, alice), + credentials::ids({credIdx}), + fee(acctDelFee), + ter(tecEXPIRED)); + env.close(); + + { + // check that expired credential object deleted + auto jv = + credentials::ledgerEntry(env, john, carol, credType); + BEAST_EXPECT( + jv.isObject() && jv.isMember(jss::result) && + jv[jss::result].isMember(jss::error) && + jv[jss::result][jss::error] == "entryNotFound"); + } + } + } + + { + testcase("Credentials feature disabled"); + using namespace test::jtx; + + Account const alice{"alice"}; + Account const becky{"becky"}; + Account const carol{"carol"}; + + Env env{*this, supported_amendments() - featureCredentials}; + env.fund(XRP(100000), alice, becky, carol); + env.close(); + + // alice sets the lsfDepositAuth flag on her account. This should + // prevent becky from deleting her account while using alice as the + // destination. + env(fset(alice, asfDepositAuth)); + env.close(); + + // Close enough ledgers to be able to delete becky's account. + incLgrSeqForAccDel(env, becky); + + auto const acctDelFee{drops(env.current()->fees().increment)}; + + std::string const credIdx = + "098B7F1B146470A1C5084DC7832C04A72939E3EBC58E68AB8B579BA072B0CE" + "CB"; + + // and can't delete even with old DepositPreauth + env(deposit::auth(alice, becky)); + env.close(); + + env(acctdelete(becky, alice), + credentials::ids({credIdx}), + fee(acctDelFee), + ter(temDISABLED)); + env.close(); + } + } + + void + testDeleteCredentialsOwner() + { + { + testcase("Deleting Issuer deletes issued credentials"); + + using namespace test::jtx; + + Account const alice{"alice"}; + Account const becky{"becky"}; + Account const carol{"carol"}; + + const char credType[] = "abcd"; + + Env env{*this}; + env.fund(XRP(100000), alice, becky, carol); + env.close(); + + // carol issue credentials for becky + env(credentials::create(becky, carol, credType)); + env.close(); + env(credentials::accept(becky, carol, credType)); + env.close(); + + // get credentials index + auto const jv = + credentials::ledgerEntry(env, becky, carol, credType); + std::string const credIdx = jv[jss::result][jss::index].asString(); + + // Close enough ledgers to be able to delete carol's account. + incLgrSeqForAccDel(env, carol); + + auto const acctDelFee{drops(env.current()->fees().increment)}; + env(acctdelete(carol, alice), fee(acctDelFee)); + env.close(); + + { // check that credential object deleted too + BEAST_EXPECT(!env.le(credIdx)); + auto const jv = + credentials::ledgerEntry(env, becky, carol, credType); + BEAST_EXPECT( + jv.isObject() && jv.isMember(jss::result) && + jv[jss::result].isMember(jss::error) && + jv[jss::result][jss::error] == "entryNotFound"); + } + } + + { + testcase("Deleting Subject deletes issued credentials"); + + using namespace test::jtx; + + Account const alice{"alice"}; + Account const becky{"becky"}; + Account const carol{"carol"}; + + const char credType[] = "abcd"; + + Env env{*this}; + env.fund(XRP(100000), alice, becky, carol); + env.close(); + + // carol issue credentials for becky + env(credentials::create(becky, carol, credType)); + env.close(); + env(credentials::accept(becky, carol, credType)); + env.close(); + + // get credentials index + auto const jv = + credentials::ledgerEntry(env, becky, carol, credType); + std::string const credIdx = jv[jss::result][jss::index].asString(); + + // Close enough ledgers to be able to delete carol's account. + incLgrSeqForAccDel(env, becky); + + auto const acctDelFee{drops(env.current()->fees().increment)}; + env(acctdelete(becky, alice), fee(acctDelFee)); + env.close(); + + { // check that credential object deleted too + BEAST_EXPECT(!env.le(credIdx)); + auto const jv = + credentials::ledgerEntry(env, becky, carol, credType); + BEAST_EXPECT( + jv.isObject() && jv.isMember(jss::result) && + jv[jss::result].isMember(jss::error) && + jv[jss::result][jss::error] == "entryNotFound"); + } + } + } + void run() override { @@ -925,6 +1285,8 @@ class AccountDelete_test : public beast::unit_test::suite testBalanceTooSmallForFee(); testWithTickets(); testDest(); + testDestinationDepositAuthCredentials(); + testDeleteCredentialsOwner(); } }; diff --git a/src/test/app/Check_test.cpp b/src/test/app/Check_test.cpp index 31b45abf43a..2c4f44ce79f 100644 --- a/src/test/app/Check_test.cpp +++ b/src/test/app/Check_test.cpp @@ -108,16 +108,6 @@ class Check_test : public beast::unit_test::suite return result; } - // Helper function that returns the owner count on an account. - static std::uint32_t - ownerCount(test::jtx::Env const& env, test::jtx::Account const& account) - { - std::uint32_t ret{0}; - if (auto const sleAccount = env.le(account)) - ret = sleAccount->getFieldU32(sfOwnerCount); - return ret; - } - // Helper function that verifies the expected DeliveredAmount is present. // // NOTE: the function _infers_ the transaction to operate on by calling diff --git a/src/test/app/Clawback_test.cpp b/src/test/app/Clawback_test.cpp index 8a42d4c38ef..c000433d2af 100644 --- a/src/test/app/Clawback_test.cpp +++ b/src/test/app/Clawback_test.cpp @@ -37,16 +37,6 @@ class Clawback_test : public beast::unit_test::suite return boost::lexical_cast(t); } - // Helper function that returns the owner count of an account root. - static std::uint32_t - ownerCount(test::jtx::Env const& env, test::jtx::Account const& acct) - { - std::uint32_t ret{0}; - if (auto const sleAcct = env.le(acct)) - ret = sleAcct->at(sfOwnerCount); - return ret; - } - // Helper function that returns the number of tickets held by an account. static std::uint32_t ticketCount(test::jtx::Env const& env, test::jtx::Account const& acct) diff --git a/src/test/app/Credentials_test.cpp b/src/test/app/Credentials_test.cpp new file mode 100644 index 00000000000..e5d90d9766c --- /dev/null +++ b/src/test/app/Credentials_test.cpp @@ -0,0 +1,1079 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace ripple { +namespace test { + +static inline bool +checkVL( + std::shared_ptr const& sle, + SField const& field, + std::string const& expected) +{ + return strHex(expected) == strHex(sle->getFieldVL(field)); +} + +static inline Keylet +credentialKeylet( + test::jtx::Account const& subject, + test::jtx::Account const& issuer, + std::string_view credType) +{ + return keylet::credential( + subject.id(), issuer.id(), Slice(credType.data(), credType.size())); +} + +struct Credentials_test : public beast::unit_test::suite +{ + void + testSuccessful(FeatureBitset features) + { + using namespace test::jtx; + + const char credType[] = "abcde"; + const char uri[] = "uri"; + + Account const issuer{"issuer"}; + Account const subject{"subject"}; + Account const other{"other"}; + + Env env{*this, features}; + + { + testcase("Create for subject."); + + auto const credKey = credentialKeylet(subject, issuer, credType); + + env.fund(XRP(5000), subject, issuer, other); + env.close(); + + // Test Create credentials + env(credentials::create(subject, issuer, credType), + credentials::uri(uri)); + env.close(); + { + auto const sleCred = env.le(credKey); + BEAST_EXPECT(static_cast(sleCred)); + if (!sleCred) + return; + + BEAST_EXPECT(sleCred->getAccountID(sfSubject) == subject.id()); + BEAST_EXPECT(sleCred->getAccountID(sfIssuer) == issuer.id()); + BEAST_EXPECT(!sleCred->getFieldU32(sfFlags)); + BEAST_EXPECT(ownerCount(env, issuer) == 1); + BEAST_EXPECT(!ownerCount(env, subject)); + BEAST_EXPECT(checkVL(sleCred, sfCredentialType, credType)); + BEAST_EXPECT(checkVL(sleCred, sfURI, uri)); + auto const jle = + credentials::ledgerEntry(env, subject, issuer, credType); + BEAST_EXPECT( + jle.isObject() && jle.isMember(jss::result) && + !jle[jss::result].isMember(jss::error) && + jle[jss::result].isMember(jss::node) && + jle[jss::result][jss::node].isMember("LedgerEntryType") && + jle[jss::result][jss::node]["LedgerEntryType"] == + jss::Credential && + jle[jss::result][jss::node][jss::Issuer] == + issuer.human() && + jle[jss::result][jss::node][jss::Subject] == + subject.human() && + jle[jss::result][jss::node]["CredentialType"] == + strHex(std::string_view(credType))); + } + + env(credentials::accept(subject, issuer, credType)); + env.close(); + { + // check switching owner of the credentials from issuer to + // subject + auto const sleCred = env.le(credKey); + BEAST_EXPECT(static_cast(sleCred)); + if (!sleCred) + return; + + BEAST_EXPECT(sleCred->getAccountID(sfSubject) == subject.id()); + BEAST_EXPECT(sleCred->getAccountID(sfIssuer) == issuer.id()); + BEAST_EXPECT(!ownerCount(env, issuer)); + BEAST_EXPECT(ownerCount(env, subject) == 1); + BEAST_EXPECT(checkVL(sleCred, sfCredentialType, credType)); + BEAST_EXPECT(checkVL(sleCred, sfURI, uri)); + BEAST_EXPECT(sleCred->getFieldU32(sfFlags) == lsfAccepted); + } + + env(credentials::deleteCred(subject, subject, issuer, credType)); + env.close(); + { + BEAST_EXPECT(!env.le(credKey)); + BEAST_EXPECT(!ownerCount(env, issuer)); + BEAST_EXPECT(!ownerCount(env, subject)); + + // check no credential exists anymore + auto const jle = + credentials::ledgerEntry(env, subject, issuer, credType); + BEAST_EXPECT( + jle.isObject() && jle.isMember(jss::result) && + jle[jss::result].isMember(jss::error) && + jle[jss::result][jss::error] == "entryNotFound"); + } + } + + { + testcase("Create for themself."); + + auto const credKey = credentialKeylet(issuer, issuer, credType); + + env(credentials::create(issuer, issuer, credType), + credentials::uri(uri)); + env.close(); + { + auto const sleCred = env.le(credKey); + BEAST_EXPECT(static_cast(sleCred)); + if (!sleCred) + return; + + BEAST_EXPECT(sleCred->getAccountID(sfSubject) == issuer.id()); + BEAST_EXPECT(sleCred->getAccountID(sfIssuer) == issuer.id()); + BEAST_EXPECT((sleCred->getFieldU32(sfFlags) & lsfAccepted)); + BEAST_EXPECT( + sleCred->getFieldU64(sfIssuerNode) == + sleCred->getFieldU64(sfSubjectNode)); + BEAST_EXPECT(ownerCount(env, issuer) == 1); + BEAST_EXPECT(checkVL(sleCred, sfCredentialType, credType)); + BEAST_EXPECT(checkVL(sleCred, sfURI, uri)); + auto const jle = + credentials::ledgerEntry(env, issuer, issuer, credType); + BEAST_EXPECT( + jle.isObject() && jle.isMember(jss::result) && + !jle[jss::result].isMember(jss::error) && + jle[jss::result].isMember(jss::node) && + jle[jss::result][jss::node].isMember("LedgerEntryType") && + jle[jss::result][jss::node]["LedgerEntryType"] == + jss::Credential && + jle[jss::result][jss::node][jss::Issuer] == + issuer.human() && + jle[jss::result][jss::node][jss::Subject] == + issuer.human() && + jle[jss::result][jss::node]["CredentialType"] == + strHex(std::string_view(credType))); + } + + env(credentials::deleteCred(issuer, issuer, issuer, credType)); + env.close(); + { + BEAST_EXPECT(!env.le(credKey)); + BEAST_EXPECT(!ownerCount(env, issuer)); + + // check no credential exists anymore + auto const jle = + credentials::ledgerEntry(env, issuer, issuer, credType); + BEAST_EXPECT( + jle.isObject() && jle.isMember(jss::result) && + jle[jss::result].isMember(jss::error) && + jle[jss::result][jss::error] == "entryNotFound"); + } + } + } + + void + testCredentialsDelete(FeatureBitset features) + { + using namespace test::jtx; + + const char credType[] = "abcde"; + + Account const issuer{"issuer"}; + Account const subject{"subject"}; + Account const other{"other"}; + + Env env{*this, features}; + + // fund subject and issuer + env.fund(XRP(5000), issuer, subject, other); + env.close(); + + { + testcase("Delete issuer before accept"); + + auto const credKey = credentialKeylet(subject, issuer, credType); + env(credentials::create(subject, issuer, credType)); + env.close(); + + // delete issuer + { + int const delta = env.seq(issuer) + 255; + for (int i = 0; i < delta; ++i) + env.close(); + auto const acctDelFee{drops(env.current()->fees().increment)}; + env(acctdelete(issuer, other), fee(acctDelFee)); + env.close(); + } + + // check credentials deleted too + { + BEAST_EXPECT(!env.le(credKey)); + BEAST_EXPECT(!ownerCount(env, subject)); + + // check no credential exists anymore + auto const jle = + credentials::ledgerEntry(env, subject, issuer, credType); + BEAST_EXPECT( + jle.isObject() && jle.isMember(jss::result) && + jle[jss::result].isMember(jss::error) && + jle[jss::result][jss::error] == "entryNotFound"); + } + + // resurrection + env.fund(XRP(5000), issuer); + env.close(); + } + + { + testcase("Delete issuer after accept"); + + auto const credKey = credentialKeylet(subject, issuer, credType); + env(credentials::create(subject, issuer, credType)); + env.close(); + env(credentials::accept(subject, issuer, credType)); + env.close(); + + // delete issuer + { + int const delta = env.seq(issuer) + 255; + for (int i = 0; i < delta; ++i) + env.close(); + auto const acctDelFee{drops(env.current()->fees().increment)}; + env(acctdelete(issuer, other), fee(acctDelFee)); + env.close(); + } + + // check credentials deleted too + { + BEAST_EXPECT(!env.le(credKey)); + BEAST_EXPECT(!ownerCount(env, subject)); + + // check no credential exists anymore + auto const jle = + credentials::ledgerEntry(env, subject, issuer, credType); + BEAST_EXPECT( + jle.isObject() && jle.isMember(jss::result) && + jle[jss::result].isMember(jss::error) && + jle[jss::result][jss::error] == "entryNotFound"); + } + + // resurrection + env.fund(XRP(5000), issuer); + env.close(); + } + + { + testcase("Delete subject before accept"); + + auto const credKey = credentialKeylet(subject, issuer, credType); + env(credentials::create(subject, issuer, credType)); + env.close(); + + // delete subject + { + int const delta = env.seq(subject) + 255; + for (int i = 0; i < delta; ++i) + env.close(); + auto const acctDelFee{drops(env.current()->fees().increment)}; + env(acctdelete(subject, other), fee(acctDelFee)); + env.close(); + } + + // check credentials deleted too + { + BEAST_EXPECT(!env.le(credKey)); + BEAST_EXPECT(!ownerCount(env, issuer)); + + // check no credential exists anymore + auto const jle = + credentials::ledgerEntry(env, subject, issuer, credType); + BEAST_EXPECT( + jle.isObject() && jle.isMember(jss::result) && + jle[jss::result].isMember(jss::error) && + jle[jss::result][jss::error] == "entryNotFound"); + } + + // resurrection + env.fund(XRP(5000), subject); + env.close(); + } + + { + testcase("Delete subject after accept"); + + auto const credKey = credentialKeylet(subject, issuer, credType); + env(credentials::create(subject, issuer, credType)); + env.close(); + env(credentials::accept(subject, issuer, credType)); + env.close(); + + // delete subject + { + int const delta = env.seq(subject) + 255; + for (int i = 0; i < delta; ++i) + env.close(); + auto const acctDelFee{drops(env.current()->fees().increment)}; + env(acctdelete(subject, other), fee(acctDelFee)); + env.close(); + } + + // check credentials deleted too + { + BEAST_EXPECT(!env.le(credKey)); + BEAST_EXPECT(!ownerCount(env, issuer)); + + // check no credential exists anymore + auto const jle = + credentials::ledgerEntry(env, subject, issuer, credType); + BEAST_EXPECT( + jle.isObject() && jle.isMember(jss::result) && + jle[jss::result].isMember(jss::error) && + jle[jss::result][jss::error] == "entryNotFound"); + } + + // resurrection + env.fund(XRP(5000), subject); + env.close(); + } + + { + testcase("Delete by other"); + + auto const credKey = credentialKeylet(subject, issuer, credType); + auto jv = credentials::create(subject, issuer, credType); + uint32_t const t = env.current() + ->info() + .parentCloseTime.time_since_epoch() + .count(); + jv[sfExpiration.jsonName] = t + 20; + env(jv); + + // time advance + env.close(); + env.close(); + env.close(); + + // Other account delete credentials + env(credentials::deleteCred(other, subject, issuer, credType)); + env.close(); + + // check credentials object + { + BEAST_EXPECT(!env.le(credKey)); + BEAST_EXPECT(!ownerCount(env, issuer)); + BEAST_EXPECT(!ownerCount(env, subject)); + + // check no credential exists anymore + auto const jle = + credentials::ledgerEntry(env, subject, issuer, credType); + BEAST_EXPECT( + jle.isObject() && jle.isMember(jss::result) && + jle[jss::result].isMember(jss::error) && + jle[jss::result][jss::error] == "entryNotFound"); + } + } + + { + testcase("Delete by subject"); + + env(credentials::create(subject, issuer, credType)); + env.close(); + + // Subject can delete + env(credentials::deleteCred(subject, subject, issuer, credType)); + env.close(); + { + auto const credKey = + credentialKeylet(subject, issuer, credType); + BEAST_EXPECT(!env.le(credKey)); + BEAST_EXPECT(!ownerCount(env, subject)); + BEAST_EXPECT(!ownerCount(env, issuer)); + auto const jle = + credentials::ledgerEntry(env, subject, issuer, credType); + BEAST_EXPECT( + jle.isObject() && jle.isMember(jss::result) && + jle[jss::result].isMember(jss::error) && + jle[jss::result][jss::error] == "entryNotFound"); + } + } + + { + testcase("Delete by issuer"); + env(credentials::create(subject, issuer, credType)); + env.close(); + + env(credentials::deleteCred(issuer, subject, issuer, credType)); + env.close(); + { + auto const credKey = + credentialKeylet(subject, issuer, credType); + BEAST_EXPECT(!env.le(credKey)); + BEAST_EXPECT(!ownerCount(env, subject)); + BEAST_EXPECT(!ownerCount(env, issuer)); + auto const jle = + credentials::ledgerEntry(env, subject, issuer, credType); + BEAST_EXPECT( + jle.isObject() && jle.isMember(jss::result) && + jle[jss::result].isMember(jss::error) && + jle[jss::result][jss::error] == "entryNotFound"); + } + } + } + + void + testCreateFailed(FeatureBitset features) + { + using namespace test::jtx; + + const char credType[] = "abcde"; + + Account const issuer{"issuer"}; + Account const subject{"subject"}; + + { + using namespace jtx; + Env env{*this, features}; + + env.fund(XRP(5000), subject, issuer); + env.close(); + + { + testcase("Credentials fail, no subject param."); + auto jv = credentials::create(subject, issuer, credType); + jv.removeMember(jss::Subject); + env(jv, ter(temMALFORMED)); + } + + { + auto jv = credentials::create(subject, issuer, credType); + jv[jss::Subject] = to_string(xrpAccount()); + env(jv, ter(temMALFORMED)); + } + + { + testcase("Credentials fail, no credentialType param."); + auto jv = credentials::create(subject, issuer, credType); + jv.removeMember(sfCredentialType.jsonName); + env(jv, ter(temMALFORMED)); + } + + { + testcase("Credentials fail, empty credentialType param."); + auto jv = credentials::create(subject, issuer, ""); + env(jv, ter(temMALFORMED)); + } + + { + testcase( + "Credentials fail, credentialType length > " + "maxCredentialTypeLength."); + constexpr std::string_view longCredType = + "abcdefghijklmnopqrstuvwxyz01234567890qwertyuiop[]" + "asdfghjkl;'zxcvbnm8237tr28weufwldebvfv8734t07p"; + static_assert(longCredType.size() > maxCredentialTypeLength); + auto jv = credentials::create(subject, issuer, longCredType); + env(jv, ter(temMALFORMED)); + } + + { + testcase("Credentials fail, URI length > 256."); + constexpr std::string_view longURI = + "abcdefghijklmnopqrstuvwxyz01234567890qwertyuiop[]" + "asdfghjkl;'zxcvbnm8237tr28weufwldebvfv8734t07p " + "9hfup;wDJFBVSD8f72 " + "pfhiusdovnbs;" + "djvbldafghwpEFHdjfaidfgio84763tfysgdvhjasbd " + "vujhgWQIE7F6WEUYFGWUKEYFVQW87FGWOEFWEFUYWVEF8723GFWEFB" + "WULE" + "fv28o37gfwEFB3872TFO8GSDSDVD"; + static_assert(longURI.size() > maxCredentialURILength); + env(credentials::create(subject, issuer, credType), + credentials::uri(longURI), + ter(temMALFORMED)); + } + + { + testcase("Credentials fail, URI empty."); + env(credentials::create(subject, issuer, credType), + credentials::uri(""), + ter(temMALFORMED)); + } + + { + testcase("Credentials fail, expiration in the past."); + auto jv = credentials::create(subject, issuer, credType); + // current time in ripple epoch - 1s + uint32_t const t = env.current() + ->info() + .parentCloseTime.time_since_epoch() + .count() - + 1; + jv[sfExpiration.jsonName] = t; + env(jv, ter(tecEXPIRED)); + } + + { + testcase("Credentials fail, invalid fee."); + + auto jv = credentials::create(subject, issuer, credType); + jv[jss::Fee] = -1; + env(jv, ter(temBAD_FEE)); + } + + { + testcase("Credentials fail, duplicate."); + auto const jv = credentials::create(subject, issuer, credType); + env(jv); + env.close(); + env(jv, ter(tecDUPLICATE)); + env.close(); + + // check credential still present + auto const jle = + credentials::ledgerEntry(env, subject, issuer, credType); + BEAST_EXPECT( + jle.isObject() && jle.isMember(jss::result) && + !jle[jss::result].isMember(jss::error) && + jle[jss::result].isMember(jss::node) && + jle[jss::result][jss::node].isMember("LedgerEntryType") && + jle[jss::result][jss::node]["LedgerEntryType"] == + jss::Credential && + jle[jss::result][jss::node][jss::Issuer] == + issuer.human() && + jle[jss::result][jss::node][jss::Subject] == + subject.human() && + jle[jss::result][jss::node]["CredentialType"] == + strHex(std::string_view(credType))); + } + } + + { + using namespace jtx; + Env env{*this, features}; + + env.fund(XRP(5000), issuer); + env.close(); + + { + testcase("Credentials fail, subject doesn't exist."); + auto const jv = credentials::create(subject, issuer, credType); + env(jv, ter(tecNO_TARGET)); + } + } + + { + using namespace jtx; + Env env{*this, features}; + + auto const reserve = drops(env.current()->fees().accountReserve(0)); + env.fund(reserve, subject, issuer); + env.close(); + + testcase("Credentials fail, not enough reserve."); + { + auto const jv = credentials::create(subject, issuer, credType); + env(jv, ter(tecINSUFFICIENT_RESERVE)); + env.close(); + } + } + } + + void + testAcceptFailed(FeatureBitset features) + { + using namespace jtx; + + const char credType[] = "abcde"; + Account const issuer{"issuer"}; + Account const subject{"subject"}; + Account const other{"other"}; + + { + Env env{*this, features}; + + env.fund(XRP(5000), subject, issuer); + + { + testcase("CredentialsAccept fail, Credential doesn't exist."); + env(credentials::accept(subject, issuer, credType), + ter(tecNO_ENTRY)); + env.close(); + } + + { + testcase("CredentialsAccept fail, invalid Issuer account."); + auto jv = credentials::accept(subject, issuer, credType); + jv[jss::Issuer] = to_string(xrpAccount()); + env(jv, ter(temINVALID_ACCOUNT_ID)); + env.close(); + } + + { + testcase( + "CredentialsAccept fail, invalid credentialType param."); + auto jv = credentials::accept(subject, issuer, ""); + env(jv, ter(temMALFORMED)); + } + } + + { + Env env{*this, features}; + + env.fund(drops(env.current()->fees().accountReserve(1)), issuer); + env.fund(drops(env.current()->fees().accountReserve(0)), subject); + env.close(); + + { + testcase("CredentialsAccept fail, not enough reserve."); + env(credentials::create(subject, issuer, credType)); + env.close(); + + env(credentials::accept(subject, issuer, credType), + ter(tecINSUFFICIENT_RESERVE)); + env.close(); + + // check credential still present + auto const jle = + credentials::ledgerEntry(env, subject, issuer, credType); + BEAST_EXPECT( + jle.isObject() && jle.isMember(jss::result) && + !jle[jss::result].isMember(jss::error) && + jle[jss::result].isMember(jss::node) && + jle[jss::result][jss::node].isMember("LedgerEntryType") && + jle[jss::result][jss::node]["LedgerEntryType"] == + jss::Credential && + jle[jss::result][jss::node][jss::Issuer] == + issuer.human() && + jle[jss::result][jss::node][jss::Subject] == + subject.human() && + jle[jss::result][jss::node]["CredentialType"] == + strHex(std::string_view(credType))); + } + } + + { + using namespace jtx; + Env env{*this, features}; + + env.fund(XRP(5000), subject, issuer); + env.close(); + + { + env(credentials::create(subject, issuer, credType)); + env.close(); + + testcase("CredentialsAccept fail, invalid fee."); + auto jv = credentials::accept(subject, issuer, credType); + jv[jss::Fee] = -1; + env(jv, ter(temBAD_FEE)); + + testcase("CredentialsAccept fail, lsfAccepted already set."); + env(credentials::accept(subject, issuer, credType)); + env.close(); + env(credentials::accept(subject, issuer, credType), + ter(tecDUPLICATE)); + env.close(); + + // check credential still present + auto const jle = + credentials::ledgerEntry(env, subject, issuer, credType); + BEAST_EXPECT( + jle.isObject() && jle.isMember(jss::result) && + !jle[jss::result].isMember(jss::error) && + jle[jss::result].isMember(jss::node) && + jle[jss::result][jss::node].isMember("LedgerEntryType") && + jle[jss::result][jss::node]["LedgerEntryType"] == + jss::Credential && + jle[jss::result][jss::node][jss::Issuer] == + issuer.human() && + jle[jss::result][jss::node][jss::Subject] == + subject.human() && + jle[jss::result][jss::node]["CredentialType"] == + strHex(std::string_view(credType))); + } + + { + const char credType2[] = "efghi"; + + testcase("CredentialsAccept fail, expired credentials."); + auto jv = credentials::create(subject, issuer, credType2); + uint32_t const t = env.current() + ->info() + .parentCloseTime.time_since_epoch() + .count(); + jv[sfExpiration.jsonName] = t; + env(jv); + env.close(); + + // credentials are expired now + env(credentials::accept(subject, issuer, credType2), + ter(tecEXPIRED)); + env.close(); + + // check that expired credentials were deleted + auto const jDelCred = + credentials::ledgerEntry(env, subject, issuer, credType2); + BEAST_EXPECT( + jDelCred.isObject() && jDelCred.isMember(jss::result) && + jDelCred[jss::result].isMember(jss::error) && + jDelCred[jss::result][jss::error] == "entryNotFound"); + + BEAST_EXPECT(ownerCount(env, issuer) == 0); + BEAST_EXPECT(ownerCount(env, subject) == 1); + } + } + + { + using namespace jtx; + Env env{*this, features}; + + env.fund(XRP(5000), issuer, subject, other); + env.close(); + + { + testcase("CredentialsAccept fail, issuer doesn't exist."); + auto jv = credentials::create(subject, issuer, credType); + env(jv); + env.close(); + + // delete issuer + int const delta = env.seq(issuer) + 255; + for (int i = 0; i < delta; ++i) + env.close(); + auto const acctDelFee{drops(env.current()->fees().increment)}; + env(acctdelete(issuer, other), fee(acctDelFee)); + + // can't accept - no issuer account + jv = credentials::accept(subject, issuer, credType); + env(jv, ter(tecNO_ISSUER)); + env.close(); + + // check that expired credentials were deleted + auto const jDelCred = + credentials::ledgerEntry(env, subject, issuer, credType); + BEAST_EXPECT( + jDelCred.isObject() && jDelCred.isMember(jss::result) && + jDelCred[jss::result].isMember(jss::error) && + jDelCred[jss::result][jss::error] == "entryNotFound"); + } + } + } + + void + testDeleteFailed(FeatureBitset features) + { + using namespace test::jtx; + + const char credType[] = "abcde"; + Account const issuer{"issuer"}; + Account const subject{"subject"}; + Account const other{"other"}; + + { + using namespace jtx; + Env env{*this, features}; + + env.fund(XRP(5000), subject, issuer, other); + env.close(); + + { + testcase("CredentialsDelete fail, no Credentials."); + env(credentials::deleteCred(subject, subject, issuer, credType), + ter(tecNO_ENTRY)); + env.close(); + } + + { + testcase("CredentialsDelete fail, invalid Subject account."); + auto jv = + credentials::deleteCred(subject, subject, issuer, credType); + jv[jss::Subject] = to_string(xrpAccount()); + env(jv, ter(temINVALID_ACCOUNT_ID)); + env.close(); + } + + { + testcase("CredentialsDelete fail, invalid Issuer account."); + auto jv = + credentials::deleteCred(subject, subject, issuer, credType); + jv[jss::Issuer] = to_string(xrpAccount()); + env(jv, ter(temINVALID_ACCOUNT_ID)); + env.close(); + } + + { + testcase( + "CredentialsDelete fail, invalid credentialType param."); + auto jv = credentials::deleteCred(subject, subject, issuer, ""); + env(jv, ter(temMALFORMED)); + } + + { + const char credType2[] = "fghij"; + + env(credentials::create(subject, issuer, credType2)); + env.close(); + + // Other account can't delete credentials without expiration + env(credentials::deleteCred(other, subject, issuer, credType2), + ter(tecNO_PERMISSION)); + env.close(); + + // check credential still present + auto const jle = + credentials::ledgerEntry(env, subject, issuer, credType2); + BEAST_EXPECT( + jle.isObject() && jle.isMember(jss::result) && + !jle[jss::result].isMember(jss::error) && + jle[jss::result].isMember(jss::node) && + jle[jss::result][jss::node].isMember("LedgerEntryType") && + jle[jss::result][jss::node]["LedgerEntryType"] == + jss::Credential && + jle[jss::result][jss::node][jss::Issuer] == + issuer.human() && + jle[jss::result][jss::node][jss::Subject] == + subject.human() && + jle[jss::result][jss::node]["CredentialType"] == + strHex(std::string_view(credType2))); + } + + { + testcase("CredentialsDelete fail, time not expired yet."); + + auto jv = credentials::create(subject, issuer, credType); + // current time in ripple epoch + 1000s + uint32_t const t = env.current() + ->info() + .parentCloseTime.time_since_epoch() + .count() + + 1000; + jv[sfExpiration.jsonName] = t; + env(jv); + env.close(); + + // Other account can't delete credentials that not expired + env(credentials::deleteCred(other, subject, issuer, credType), + ter(tecNO_PERMISSION)); + env.close(); + + // check credential still present + auto const jle = + credentials::ledgerEntry(env, subject, issuer, credType); + BEAST_EXPECT( + jle.isObject() && jle.isMember(jss::result) && + !jle[jss::result].isMember(jss::error) && + jle[jss::result].isMember(jss::node) && + jle[jss::result][jss::node].isMember("LedgerEntryType") && + jle[jss::result][jss::node]["LedgerEntryType"] == + jss::Credential && + jle[jss::result][jss::node][jss::Issuer] == + issuer.human() && + jle[jss::result][jss::node][jss::Subject] == + subject.human() && + jle[jss::result][jss::node]["CredentialType"] == + strHex(std::string_view(credType))); + } + + { + testcase("CredentialsDelete fail, no Issuer and Subject."); + + auto jv = + credentials::deleteCred(subject, subject, issuer, credType); + jv.removeMember(jss::Subject); + jv.removeMember(jss::Issuer); + env(jv, ter(temMALFORMED)); + env.close(); + } + + { + testcase("CredentialsDelete fail, invalid fee."); + + auto jv = + credentials::deleteCred(subject, subject, issuer, credType); + jv[jss::Fee] = -1; + env(jv, ter(temBAD_FEE)); + env.close(); + } + + { + testcase("deleteSLE fail, bad SLE."); + auto view = std::make_shared( + env.current().get(), ApplyFlags::tapNONE); + auto ter = + ripple::credentials::deleteSLE(*view, {}, env.journal); + BEAST_EXPECT(ter == tecNO_ENTRY); + } + } + } + + void + testFeatureFailed(FeatureBitset features) + { + using namespace test::jtx; + + const char credType[] = "abcde"; + Account const issuer{"issuer"}; + Account const subject{"subject"}; + + { + using namespace jtx; + Env env{*this, features}; + + env.fund(XRP(5000), subject, issuer); + env.close(); + + { + testcase("Credentials fail, Feature is not enabled."); + env(credentials::create(subject, issuer, credType), + ter(temDISABLED)); + env(credentials::accept(subject, issuer, credType), + ter(temDISABLED)); + env(credentials::deleteCred(subject, subject, issuer, credType), + ter(temDISABLED)); + } + } + } + + void + testRPC() + { + using namespace test::jtx; + + const char credType[] = "abcde"; + Account const issuer{"issuer"}; + Account const subject{"subject"}; + + { + using namespace jtx; + Env env{*this}; + + env.fund(XRP(5000), subject, issuer); + env.close(); + + env(credentials::create(subject, issuer, credType)); + env.close(); + + env(credentials::accept(subject, issuer, credType)); + env.close(); + + testcase("account_tx"); + + std::string txHash0, txHash1; + { + Json::Value params; + params[jss::account] = subject.human(); + auto const jv = env.rpc( + "json", "account_tx", to_string(params))[jss::result]; + + BEAST_EXPECT(jv[jss::transactions].size() == 4); + auto const& tx0(jv[jss::transactions][0u][jss::tx]); + BEAST_EXPECT( + tx0[jss::TransactionType] == jss::CredentialAccept); + auto const& tx1(jv[jss::transactions][1u][jss::tx]); + BEAST_EXPECT( + tx1[jss::TransactionType] == jss::CredentialCreate); + txHash0 = tx0[jss::hash].asString(); + txHash1 = tx1[jss::hash].asString(); + } + + { + Json::Value params; + params[jss::account] = issuer.human(); + auto const jv = env.rpc( + "json", "account_tx", to_string(params))[jss::result]; + + BEAST_EXPECT(jv[jss::transactions].size() == 4); + auto const& tx0(jv[jss::transactions][0u][jss::tx]); + BEAST_EXPECT( + tx0[jss::TransactionType] == jss::CredentialAccept); + auto const& tx1(jv[jss::transactions][1u][jss::tx]); + BEAST_EXPECT( + tx1[jss::TransactionType] == jss::CredentialCreate); + + BEAST_EXPECT(txHash0 == tx0[jss::hash].asString()); + BEAST_EXPECT(txHash1 == tx1[jss::hash].asString()); + } + + testcase("account_objects"); + std::string objectIdx; + { + Json::Value params; + params[jss::account] = subject.human(); + auto jv = env.rpc( + "json", "account_objects", to_string(params))[jss::result]; + + BEAST_EXPECT(jv[jss::account_objects].size() == 1); + auto const& object(jv[jss::account_objects][0u]); + + BEAST_EXPECT( + object["LedgerEntryType"].asString() == jss::Credential); + objectIdx = object[jss::index].asString(); + } + + { + Json::Value params; + params[jss::account] = issuer.human(); + auto jv = env.rpc( + "json", "account_objects", to_string(params))[jss::result]; + + BEAST_EXPECT(jv[jss::account_objects].size() == 1); + auto const& object(jv[jss::account_objects][0u]); + + BEAST_EXPECT( + object["LedgerEntryType"].asString() == jss::Credential); + BEAST_EXPECT(objectIdx == object[jss::index].asString()); + } + } + } + + void + run() override + { + using namespace test::jtx; + FeatureBitset const all{supported_amendments()}; + testSuccessful(all); + testCredentialsDelete(all); + testCreateFailed(all); + testAcceptFailed(all); + testDeleteFailed(all); + testFeatureFailed(all - featureCredentials); + testRPC(); + } +}; + +BEAST_DEFINE_TESTSUITE(Credentials, app, ripple); + +} // namespace test +} // namespace ripple diff --git a/src/test/app/DID_test.cpp b/src/test/app/DID_test.cpp index 20734518887..3f9cce1d33e 100644 --- a/src/test/app/DID_test.cpp +++ b/src/test/app/DID_test.cpp @@ -30,16 +30,6 @@ namespace ripple { namespace test { -// Helper function that returns the owner count of an account root. -static std::uint32_t -ownerCount(test::jtx::Env const& env, test::jtx::Account const& acct) -{ - std::uint32_t ret{0}; - if (auto const sleAcct = env.le(acct)) - ret = sleAcct->at(sfOwnerCount); - return ret; -} - bool checkVL(Slice const& result, std::string expected) { diff --git a/src/test/app/DepositAuth_test.cpp b/src/test/app/DepositAuth_test.cpp index 9a11785b38c..0f2481a7c9e 100644 --- a/src/test/app/DepositAuth_test.cpp +++ b/src/test/app/DepositAuth_test.cpp @@ -20,6 +20,8 @@ #include #include +#include + namespace ripple { namespace test { @@ -381,6 +383,25 @@ struct DepositAuth_test : public beast::unit_test::suite } }; +static Json::Value +ledgerEntryDepositPreauth( + jtx::Env& env, + jtx::Account const& acc, + std::vector const& auth) +{ + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = acc.human(); + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr(jvParams[jss::deposit_preauth][jss::authorized_credentials]); + for (auto const& o : auth) + { + arr.append(o.toLEJson()); + } + return env.rpc("json", "ledger_entry", to_string(jvParams)); +} + struct DepositPreauth_test : public beast::unit_test::suite { void @@ -634,6 +655,69 @@ struct DepositPreauth_test : public beast::unit_test::suite sendmax(XRP(10)), ter(expect)); env.close(); + + { + // becky setup depositpreauth with credentials + const char credType[] = "abcde"; + Account const carol{"carol"}; + env.fund(XRP(5000), carol); + + bool const supportsCredentials = features[featureCredentials]; + + TER const expectCredentials( + supportsCredentials ? TER(tesSUCCESS) : TER(temDISABLED)); + TER const expectPayment( + !supportsCredentials + ? TER(temDISABLED) + : (!supportsPreauth ? TER(tecNO_PERMISSION) + : TER(tesSUCCESS))); + TER const expectDP( + !supportsPreauth + ? TER(temDISABLED) + : (!supportsCredentials ? TER(temDISABLED) + : TER(tesSUCCESS))); + + env(deposit::authCredentials(becky, {{carol, credType}}), + ter(expectDP)); + env.close(); + + // gw accept credentials + env(credentials::create(gw, carol, credType), + ter(expectCredentials)); + env.close(); + env(credentials::accept(gw, carol, credType), + ter(expectCredentials)); + env.close(); + + auto jv = credentials::ledgerEntry(env, gw, carol, credType); + std::string const credIdx = supportsCredentials + ? jv[jss::result][jss::index].asString() + : "48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6" + "EA288BE4"; + + env(pay(gw, becky, USD(100)), + credentials::ids({credIdx}), + ter(expectPayment)); + env.close(); + } + + { + using namespace std::chrono; + + if (!supportsPreauth) + { + auto const seq1 = env.seq(alice); + env(escrow(alice, becky, XRP(100)), + finish_time(env.now() + 1s)); + env.close(); + + // Failed as rule is disabled + env(finish(gw, alice, seq1), + fee(1500), + ter(tecNO_PERMISSION)); + env.close(); + } + } } if (supportsPreauth) @@ -724,14 +808,759 @@ struct DepositPreauth_test : public beast::unit_test::suite } } + void + testCredentialsPayment() + { + using namespace jtx; + + const char credType[] = "abcde"; + Account const issuer{"issuer"}; + Account const alice{"alice"}; + Account const bob{"bob"}; + Account const maria{"maria"}; + Account const john{"john"}; + + { + testcase("Payment failed with disabled credentials rule."); + + Env env(*this, supported_amendments() - featureCredentials); + + env.fund(XRP(5000), issuer, bob, alice); + env.close(); + + // Bob require preauthorization + env(fset(bob, asfDepositAuth)); + env.close(); + + // Setup DepositPreauth object failed - amendent is not supported + env(deposit::authCredentials(bob, {{issuer, credType}}), + ter(temDISABLED)); + env.close(); + + // But can create old DepositPreauth + env(deposit::auth(bob, alice)); + env.close(); + + // And alice can't pay with any credentials, amendement is not + // enabled + std::string const invalidIdx = + "0E0B04ED60588A758B67E21FBBE95AC5A63598BA951761DC0EC9C08D7E" + "01E034"; + env(pay(alice, bob, XRP(10)), + credentials::ids({invalidIdx}), + ter(temDISABLED)); + env.close(); + } + + { + testcase("Payment with credentials."); + + Env env(*this); + + env.fund(XRP(5000), issuer, alice, bob, john); + env.close(); + + // Issuer create credentials, but Alice didn't accept them yet + env(credentials::create(alice, issuer, credType)); + env.close(); + + // Get the index of the credentials + auto const jv = + credentials::ledgerEntry(env, alice, issuer, credType); + std::string const credIdx = jv[jss::result][jss::index].asString(); + + // Bob require preauthorization + env(fset(bob, asfDepositAuth)); + env.close(); + + // Bob will accept payements from accounts with credentials signed + // by 'issuer' + env(deposit::authCredentials(bob, {{issuer, credType}})); + env.close(); + + auto const jDP = + ledgerEntryDepositPreauth(env, bob, {{issuer, credType}}); + BEAST_EXPECT( + jDP.isObject() && jDP.isMember(jss::result) && + !jDP[jss::result].isMember(jss::error) && + jDP[jss::result].isMember(jss::node) && + jDP[jss::result][jss::node].isMember("LedgerEntryType") && + jDP[jss::result][jss::node]["LedgerEntryType"] == + jss::DepositPreauth); + + // Alice can't pay - empty credentials array + { + auto jv = pay(alice, bob, XRP(100)); + jv[sfCredentialIDs.jsonName] = Json::arrayValue; + env(jv, ter(temMALFORMED)); + env.close(); + } + + // Alice can't pay - not accepted credentials + env(pay(alice, bob, XRP(100)), + credentials::ids({credIdx}), + ter(tecBAD_CREDENTIALS)); + env.close(); + + // Alice accept the credentials + env(credentials::accept(alice, issuer, credType)); + env.close(); + + // Now Alice can pay + env(pay(alice, bob, XRP(100)), credentials::ids({credIdx})); + env.close(); + + // Alice can pay Maria without depositPreauth enabled + env(pay(alice, maria, XRP(250)), credentials::ids({credIdx})); + env.close(); + + // john can accept payment with old depositPreauth and valid + // credentials + env(fset(john, asfDepositAuth)); + env(deposit::auth(john, alice)); + env(pay(alice, john, XRP(100)), credentials::ids({credIdx})); + env.close(); + } + + { + testcase("Payment failed with invalid credentials."); + + Env env(*this); + + env.fund(XRP(10000), issuer, alice, bob, maria); + env.close(); + + // Issuer create credentials, but Alice didn't accept them yet + env(credentials::create(alice, issuer, credType)); + env.close(); + // Alice accept the credentials + env(credentials::accept(alice, issuer, credType)); + env.close(); + // Get the index of the credentials + auto const jv = + credentials::ledgerEntry(env, alice, issuer, credType); + std::string const credIdx = jv[jss::result][jss::index].asString(); + + { + // Success as destination didn't enable preauthorization so + // valid credentials will not fail + env(pay(alice, bob, XRP(100)), credentials::ids({credIdx})); + } + + // Bob require preauthorization + env(fset(bob, asfDepositAuth)); + env.close(); + + { + // Fail as destination didn't setup DepositPreauth object + env(pay(alice, bob, XRP(100)), + credentials::ids({credIdx}), + ter(tecNO_PERMISSION)); + } + + // Bob setup DepositPreauth object, duplicates is not allowed + env(deposit::authCredentials( + bob, {{issuer, credType}, {issuer, credType}}), + ter(temMALFORMED)); + + // Bob setup DepositPreauth object + env(deposit::authCredentials(bob, {{issuer, credType}})); + env.close(); + + { + std::string const invalidIdx = + "0E0B04ED60588A758B67E21FBBE95AC5A63598BA951761DC0EC9C08D7E" + "01E034"; + // Alice can't pay with non-existing credentials + env(pay(alice, bob, XRP(100)), + credentials::ids({invalidIdx}), + ter(tecBAD_CREDENTIALS)); + } + + { // maria can't pay using valid credentials but issued for + // different account + env(pay(maria, bob, XRP(100)), + credentials::ids({credIdx}), + ter(tecBAD_CREDENTIALS)); + } + + { + // create another valid credential + const char credType2[] = "fghij"; + env(credentials::create(alice, issuer, credType2)); + env.close(); + env(credentials::accept(alice, issuer, credType2)); + env.close(); + auto const jv = + credentials::ledgerEntry(env, alice, issuer, credType2); + std::string const credIdx2 = + jv[jss::result][jss::index].asString(); + + // Alice can't pay with invalid set of valid credentials + env(pay(alice, bob, XRP(100)), + credentials::ids({credIdx, credIdx2}), + ter(tecNO_PERMISSION)); + } + + // Error, duplicate credentials + env(pay(alice, bob, XRP(100)), + credentials::ids({credIdx, credIdx}), + ter(temMALFORMED)); + + // Alice can pay + env(pay(alice, bob, XRP(100)), credentials::ids({credIdx})); + env.close(); + } + } + + void + testCredentialsCreation() + { + using namespace jtx; + + const char credType[] = "abcde"; + Account const issuer{"issuer"}; + Account const alice{"alice"}; + Account const bob{"bob"}; + Account const maria{"maria"}; + + { + testcase("Creating / deleting with credentials."); + + Env env(*this); + + env.fund(XRP(5000), issuer, alice, bob); + env.close(); + + { + // both included [AuthorizeCredentials UnauthorizeCredentials] + auto jv = deposit::authCredentials(bob, {{issuer, credType}}); + jv[sfUnauthorizeCredentials.jsonName] = Json::arrayValue; + env(jv, ter(temMALFORMED)); + } + + { + // both included [Unauthorize, AuthorizeCredentials] + auto jv = deposit::authCredentials(bob, {{issuer, credType}}); + jv[sfUnauthorize.jsonName] = issuer.human(); + env(jv, ter(temMALFORMED)); + } + + { + // both included [Authorize, AuthorizeCredentials] + auto jv = deposit::authCredentials(bob, {{issuer, credType}}); + jv[sfAuthorize.jsonName] = issuer.human(); + env(jv, ter(temMALFORMED)); + } + + { + // both included [Unauthorize, UnauthorizeCredentials] + auto jv = deposit::unauthCredentials(bob, {{issuer, credType}}); + jv[sfUnauthorize.jsonName] = issuer.human(); + env(jv, ter(temMALFORMED)); + } + + { + // both included [Authorize, UnauthorizeCredentials] + auto jv = deposit::unauthCredentials(bob, {{issuer, credType}}); + jv[sfAuthorize.jsonName] = issuer.human(); + env(jv, ter(temMALFORMED)); + } + + { + // AuthorizeCredentials is empty + auto jv = deposit::authCredentials(bob, {}); + env(jv, ter(temMALFORMED)); + } + + { + // invalid issuer + auto jv = deposit::authCredentials(bob, {}); + auto& arr(jv[sfAuthorizeCredentials.jsonName]); + Json::Value cred = Json::objectValue; + cred[jss::Issuer] = to_string(xrpAccount()); + cred[sfCredentialType.jsonName] = + strHex(std::string_view(credType)); + Json::Value credParent; + credParent[jss::Credential] = cred; + arr.append(std::move(credParent)); + + env(jv, ter(temINVALID_ACCOUNT_ID)); + } + + { + // empty credential type + auto jv = deposit::authCredentials(bob, {{issuer, {}}}); + env(jv, ter(temMALFORMED)); + } + + { + // AuthorizeCredentials is larger than 8 elements + Account const a("a"), b("b"), c("c"), d("d"), e("e"), f("f"), + g("g"), h("h"), i("i"); + auto const& z = credType; + auto jv = deposit::authCredentials( + bob, + {{a, z}, + {b, z}, + {c, z}, + {d, z}, + {e, z}, + {f, z}, + {g, z}, + {h, z}, + {i, z}}); + env(jv, ter(temMALFORMED)); + } + + { + // Can't create with non-existing issuer + Account const rick{"rick"}; + auto jv = deposit::authCredentials(bob, {{rick, credType}}); + env(jv, ter(tecNO_ISSUER)); + env.close(); + } + + { + // not enough reserve + Account const john{"john"}; + env.fund(env.current()->fees().accountReserve(0), john); + auto jv = deposit::authCredentials(john, {{issuer, credType}}); + env(jv, ter(tecINSUFFICIENT_RESERVE)); + } + + { + // NO deposit object exists + env(deposit::unauthCredentials(bob, {{issuer, credType}}), + ter(tecNO_ENTRY)); + } + + // Create DepositPreauth object + { + env(deposit::authCredentials(bob, {{issuer, credType}})); + env.close(); + + auto const jDP = + ledgerEntryDepositPreauth(env, bob, {{issuer, credType}}); + BEAST_EXPECT( + jDP.isObject() && jDP.isMember(jss::result) && + !jDP[jss::result].isMember(jss::error) && + jDP[jss::result].isMember(jss::node) && + jDP[jss::result][jss::node].isMember("LedgerEntryType") && + jDP[jss::result][jss::node]["LedgerEntryType"] == + jss::DepositPreauth); + + // Check object fields + BEAST_EXPECT( + jDP[jss::result][jss::node][jss::Account] == bob.human()); + auto const& credentials( + jDP[jss::result][jss::node]["AuthorizeCredentials"]); + BEAST_EXPECT(credentials.isArray() && credentials.size() == 1); + for (auto const& o : credentials) + { + auto const& c(o[jss::Credential]); + BEAST_EXPECT(c[jss::Issuer].asString() == issuer.human()); + BEAST_EXPECT( + c["CredentialType"].asString() == + strHex(std::string_view(credType))); + } + + // can't create duplicate + env(deposit::authCredentials(bob, {{issuer, credType}}), + ter(tecDUPLICATE)); + } + + // Delete DepositPreauth object + { + env(deposit::unauthCredentials(bob, {{issuer, credType}})); + env.close(); + auto const jDP = + ledgerEntryDepositPreauth(env, bob, {{issuer, credType}}); + BEAST_EXPECT( + jDP.isObject() && jDP.isMember(jss::result) && + jDP[jss::result].isMember(jss::error) && + jDP[jss::result][jss::error] == "entryNotFound"); + } + } + } + + void + testExpiredCreds() + { + using namespace jtx; + const char credType[] = "abcde"; + const char credType2[] = "fghijkl"; + Account const issuer{"issuer"}; + Account const alice{"alice"}; + Account const bob{"bob"}; + Account const gw{"gw"}; + IOU const USD = gw["USD"]; + Account const zelda{"zelda"}; + + { + testcase("Payment failed with expired credentials."); + + Env env(*this); + + env.fund(XRP(10000), issuer, alice, bob, gw); + env.close(); + + // Create credentials + auto jv = credentials::create(alice, issuer, credType); + // Current time in ripple epoch. + // Every time ledger close, unittest timer increase by 10s + uint32_t const t = env.current() + ->info() + .parentCloseTime.time_since_epoch() + .count() + + 60; + jv[sfExpiration.jsonName] = t; + env(jv); + env.close(); + + // Alice accept the credentials + env(credentials::accept(alice, issuer, credType)); + env.close(); + + // Create credential which not expired + jv = credentials::create(alice, issuer, credType2); + uint32_t const t2 = env.current() + ->info() + .parentCloseTime.time_since_epoch() + .count() + + 1000; + jv[sfExpiration.jsonName] = t2; + env(jv); + env.close(); + env(credentials::accept(alice, issuer, credType2)); + env.close(); + + BEAST_EXPECT(ownerCount(env, issuer) == 0); + BEAST_EXPECT(ownerCount(env, alice) == 2); + + // Get the index of the credentials + jv = credentials::ledgerEntry(env, alice, issuer, credType); + std::string const credIdx = jv[jss::result][jss::index].asString(); + jv = credentials::ledgerEntry(env, alice, issuer, credType2); + std::string const credIdx2 = jv[jss::result][jss::index].asString(); + + // Bob require preauthorization + env(fset(bob, asfDepositAuth)); + env.close(); + // Bob setup DepositPreauth object + env(deposit::authCredentials( + bob, {{issuer, credType}, {issuer, credType2}})); + env.close(); + + { + // Alice can pay + env(pay(alice, bob, XRP(100)), + credentials::ids({credIdx, credIdx2})); + env.close(); + env.close(); + + // Ledger closed, time increased, alice can't pay anymore + env(pay(alice, bob, XRP(100)), + credentials::ids({credIdx, credIdx2}), + ter(tecEXPIRED)); + env.close(); + + { + // check that expired credentials were deleted + auto const jDelCred = + credentials::ledgerEntry(env, alice, issuer, credType); + BEAST_EXPECT( + jDelCred.isObject() && jDelCred.isMember(jss::result) && + jDelCred[jss::result].isMember(jss::error) && + jDelCred[jss::result][jss::error] == "entryNotFound"); + } + + { + // check that non-expired credential still present + auto const jle = + credentials::ledgerEntry(env, alice, issuer, credType2); + BEAST_EXPECT( + jle.isObject() && jle.isMember(jss::result) && + !jle[jss::result].isMember(jss::error) && + jle[jss::result].isMember(jss::node) && + jle[jss::result][jss::node].isMember( + "LedgerEntryType") && + jle[jss::result][jss::node]["LedgerEntryType"] == + jss::Credential && + jle[jss::result][jss::node][jss::Issuer] == + issuer.human() && + jle[jss::result][jss::node][jss::Subject] == + alice.human() && + jle[jss::result][jss::node]["CredentialType"] == + strHex(std::string_view(credType2))); + } + + BEAST_EXPECT(ownerCount(env, issuer) == 0); + BEAST_EXPECT(ownerCount(env, alice) == 1); + } + + { + auto jv = credentials::create(gw, issuer, credType); + uint32_t const t = env.current() + ->info() + .parentCloseTime.time_since_epoch() + .count() + + 40; + jv[sfExpiration.jsonName] = t; + env(jv); + env.close(); + env(credentials::accept(gw, issuer, credType)); + env.close(); + + jv = credentials::ledgerEntry(env, gw, issuer, credType); + std::string const credIdx = + jv[jss::result][jss::index].asString(); + + BEAST_EXPECT(ownerCount(env, issuer) == 0); + BEAST_EXPECT(ownerCount(env, gw) == 1); + + env.close(); + env.close(); + env.close(); + + // credentials are expired + env(pay(gw, bob, USD(150)), + credentials::ids({credIdx}), + ter(tecEXPIRED)); + env.close(); + + // check that expired credentials were deleted + auto const jDelCred = + credentials::ledgerEntry(env, gw, issuer, credType); + BEAST_EXPECT( + jDelCred.isObject() && jDelCred.isMember(jss::result) && + jDelCred[jss::result].isMember(jss::error) && + jDelCred[jss::result][jss::error] == "entryNotFound"); + + BEAST_EXPECT(ownerCount(env, issuer) == 0); + BEAST_EXPECT(ownerCount(env, gw) == 0); + } + } + + { + using namespace std::chrono; + + testcase("Escrow failed with expired credentials."); + + Env env(*this); + + env.fund(XRP(5000), issuer, alice, bob, zelda); + env.close(); + + // Create credentials + auto jv = credentials::create(zelda, issuer, credType); + uint32_t const t = env.current() + ->info() + .parentCloseTime.time_since_epoch() + .count() + + 50; + jv[sfExpiration.jsonName] = t; + env(jv); + env.close(); + + // Zelda accept the credentials + env(credentials::accept(zelda, issuer, credType)); + env.close(); + + // Get the index of the credentials + jv = credentials::ledgerEntry(env, zelda, issuer, credType); + std::string const credIdx = jv[jss::result][jss::index].asString(); + + // Bob require preauthorization + env(fset(bob, asfDepositAuth)); + env.close(); + // Bob setup DepositPreauth object + env(deposit::authCredentials(bob, {{issuer, credType}})); + env.close(); + + auto const seq = env.seq(alice); + env(escrow(alice, bob, XRP(1000)), finish_time(env.now() + 1s)); + env.close(); + + // zelda can't finish escrow with invalid credentials + { + env(finish(zelda, alice, seq), + credentials::ids({}), + ter(temMALFORMED)); + env.close(); + } + + { + // zelda can't finish escrow with invalid credentials + std::string const invalidIdx = + "0E0B04ED60588A758B67E21FBBE95AC5A63598BA951761DC0EC9C08D7E" + "01E034"; + + env(finish(zelda, alice, seq), + credentials::ids({invalidIdx}), + ter(tecBAD_CREDENTIALS)); + env.close(); + } + + { // Ledger closed, time increased, zelda can't finish escrow + env(finish(zelda, alice, seq), + credentials::ids({credIdx}), + fee(1500), + ter(tecEXPIRED)); + env.close(); + } + + // check that expired credentials were deleted + auto const jDelCred = + credentials::ledgerEntry(env, zelda, issuer, credType); + BEAST_EXPECT( + jDelCred.isObject() && jDelCred.isMember(jss::result) && + jDelCred[jss::result].isMember(jss::error) && + jDelCred[jss::result][jss::error] == "entryNotFound"); + } + } + + void + testSortingCredentials() + { + using namespace jtx; + + Account const stock{"stock"}; + Account const alice{"alice"}; + Account const bob{"bob"}; + + Env env(*this); + + testcase("Sorting credentials."); + + env.fund(XRP(5000), stock, alice, bob); + + std::vector credentials = { + {"a", "a"}, + {"b", "b"}, + {"c", "c"}, + {"d", "d"}, + {"e", "e"}, + {"f", "f"}, + {"g", "g"}, + {"h", "h"}}; + + for (auto const& c : credentials) + env.fund(XRP(5000), c.issuer); + env.close(); + + std::random_device rd; + std::mt19937 gen(rd()); + + { + std::unordered_map pubKey2Acc; + for (auto const& c : credentials) + pubKey2Acc.emplace(c.issuer.human(), c.issuer); + + // check sorting in object + for (int i = 0; i < 10; ++i) + { + std::ranges::shuffle(credentials, gen); + env(deposit::authCredentials(stock, credentials)); + env.close(); + + auto const dp = + ledgerEntryDepositPreauth(env, stock, credentials); + auto const& authCred( + dp[jss::result][jss::node]["AuthorizeCredentials"]); + BEAST_EXPECT( + authCred.isArray() && + authCred.size() == credentials.size()); + std::vector> readedCreds; + for (auto const& o : authCred) + { + auto const& c(o[jss::Credential]); + auto issuer = c[jss::Issuer].asString(); + + if (BEAST_EXPECT(pubKey2Acc.contains(issuer))) + readedCreds.emplace_back( + pubKey2Acc.at(issuer), + c["CredentialType"].asString()); + } + + BEAST_EXPECT(std::ranges::is_sorted(readedCreds)); + + env(deposit::unauthCredentials(stock, credentials)); + env.close(); + } + } + + { + std::ranges::shuffle(credentials, gen); + env(deposit::authCredentials(stock, credentials)); + env.close(); + + // check sorting in params + for (int i = 0; i < 10; ++i) + { + std::ranges::shuffle(credentials, gen); + env(deposit::authCredentials(stock, credentials), + ter(tecDUPLICATE)); + } + } + + testcase("Check duplicate credentials."); + { + // check duplicates in depositPreauth params + std::ranges::shuffle(credentials, gen); + for (auto const& c : credentials) + { + auto credentials2 = credentials; + credentials2.push_back(c); + + env(deposit::authCredentials(stock, credentials2), + ter(temMALFORMED)); + } + + // create batch of credentials and save their hashes + std::vector credentialIDs; + for (auto const& c : credentials) + { + env(credentials::create(alice, c.issuer, c.credType)); + env.close(); + env(credentials::accept(alice, c.issuer, c.credType)); + env.close(); + + credentialIDs.push_back(credentials::ledgerEntry( + env, + alice, + c.issuer, + c.credType)[jss::result][jss::index] + .asString()); + } + + // check duplicates in payment params + for (auto const& h : credentialIDs) + { + auto credentialIDs2 = credentialIDs; + credentialIDs2.push_back(h); + + env(pay(alice, bob, XRP(100)), + credentials::ids(credentialIDs2), + ter(temMALFORMED)); + } + } + } + void run() override { testEnable(); testInvalid(); auto const supported{jtx::supported_amendments()}; + testPayment(supported - featureDepositPreauth - featureCredentials); testPayment(supported - featureDepositPreauth); + testPayment(supported - featureCredentials); testPayment(supported); + testCredentialsPayment(); + testCredentialsCreation(); + testExpiredCreds(); + testSortingCredentials(); } }; diff --git a/src/test/app/Escrow_test.cpp b/src/test/app/Escrow_test.cpp index 0f465a14f4d..714fc7734d9 100644 --- a/src/test/app/Escrow_test.cpp +++ b/src/test/app/Escrow_test.cpp @@ -1508,6 +1508,154 @@ struct Escrow_test : public beast::unit_test::suite } } + void + testCredentials() + { + testcase("Test with credentials"); + + using namespace jtx; + using namespace std::chrono; + + Account const alice{"alice"}; + Account const bob{"bob"}; + Account const carol{"carol"}; + Account const dillon{"dillon "}; + Account const zelda{"zelda"}; + + const char credType[] = "abcde"; + + { + // Credentials amendment not enabled + Env env(*this, supported_amendments() - featureCredentials); + env.fund(XRP(5000), alice, bob); + env.close(); + + auto const seq = env.seq(alice); + env(escrow(alice, bob, XRP(1000)), finish_time(env.now() + 1s)); + env.close(); + + env(fset(bob, asfDepositAuth)); + env.close(); + env(deposit::auth(bob, alice)); + env.close(); + + std::string const credIdx = + "48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" + "E4"; + env(finish(bob, alice, seq), + credentials::ids({credIdx}), + ter(temDISABLED)); + } + + { + Env env(*this); + + env.fund(XRP(5000), alice, bob, carol, dillon, zelda); + env.close(); + + env(credentials::create(carol, zelda, credType)); + env.close(); + auto const jv = + credentials::ledgerEntry(env, carol, zelda, credType); + std::string const credIdx = jv[jss::result][jss::index].asString(); + + auto const seq = env.seq(alice); + env(escrow(alice, bob, XRP(1000)), finish_time(env.now() + 50s)); + env.close(); + + // Bob require preauthorization + env(fset(bob, asfDepositAuth)); + env.close(); + + // Fail, credentials not accepted + env(finish(carol, alice, seq), + credentials::ids({credIdx}), + ter(tecBAD_CREDENTIALS)); + + env.close(); + + env(credentials::accept(carol, zelda, credType)); + env.close(); + + // Fail, credentials doesn’t belong to root account + env(finish(dillon, alice, seq), + credentials::ids({credIdx}), + ter(tecBAD_CREDENTIALS)); + + // Fail, no depositPreauth + env(finish(carol, alice, seq), + credentials::ids({credIdx}), + ter(tecNO_PERMISSION)); + + env(deposit::authCredentials(bob, {{zelda, credType}})); + env.close(); + + // Success + env.close(); + env(finish(carol, alice, seq), credentials::ids({credIdx})); + env.close(); + } + + { + testcase("Escrow with credentials without depositPreauth"); + using namespace std::chrono; + + Env env(*this); + + env.fund(XRP(5000), alice, bob, carol, dillon, zelda); + env.close(); + + env(credentials::create(carol, zelda, credType)); + env.close(); + env(credentials::accept(carol, zelda, credType)); + env.close(); + auto const jv = + credentials::ledgerEntry(env, carol, zelda, credType); + std::string const credIdx = jv[jss::result][jss::index].asString(); + + auto const seq = env.seq(alice); + env(escrow(alice, bob, XRP(1000)), finish_time(env.now() + 50s)); + // time advance + env.close(); + env.close(); + env.close(); + env.close(); + env.close(); + env.close(); + + // Succeed, Bob doesn't require preauthorization + env(finish(carol, alice, seq), credentials::ids({credIdx})); + env.close(); + + { + const char credType2[] = "fghijk"; + + env(credentials::create(bob, zelda, credType2)); + env.close(); + env(credentials::accept(bob, zelda, credType2)); + env.close(); + auto const credIdxBob = + credentials::ledgerEntry( + env, bob, zelda, credType2)[jss::result][jss::index] + .asString(); + + auto const seq = env.seq(alice); + env(escrow(alice, bob, XRP(1000)), finish_time(env.now() + 1s)); + env.close(); + + // Bob require preauthorization + env(fset(bob, asfDepositAuth)); + env.close(); + env(deposit::authCredentials(bob, {{zelda, credType}})); + env.close(); + + // Use any valid credentials if account == dst + env(finish(bob, alice, seq), credentials::ids({credIdxBob})); + env.close(); + } + } + } + void run() override { @@ -1522,6 +1670,7 @@ struct Escrow_test : public beast::unit_test::suite testMetaAndOwnership(); testConsequences(); testEscrowWithTickets(); + testCredentials(); } }; diff --git a/src/test/app/FixNFTokenPageLinks_test.cpp b/src/test/app/FixNFTokenPageLinks_test.cpp index dea6d4569e0..f8db4df4f92 100644 --- a/src/test/app/FixNFTokenPageLinks_test.cpp +++ b/src/test/app/FixNFTokenPageLinks_test.cpp @@ -27,16 +27,6 @@ namespace ripple { class FixNFTokenPageLinks_test : public beast::unit_test::suite { - // Helper function that returns the owner count of an account root. - static std::uint32_t - ownerCount(test::jtx::Env const& env, test::jtx::Account const& acct) - { - std::uint32_t ret{0}; - if (auto const sleAcct = env.le(acct)) - ret = sleAcct->at(sfOwnerCount); - return ret; - } - // Helper function that returns the number of nfts owned by an account. static std::uint32_t nftCount(test::jtx::Env& env, test::jtx::Account const& acct) diff --git a/src/test/app/MPToken_test.cpp b/src/test/app/MPToken_test.cpp index 69c5d90111c..796a3f14c88 100644 --- a/src/test/app/MPToken_test.cpp +++ b/src/test/app/MPToken_test.cpp @@ -1316,6 +1316,157 @@ class MPToken_test : public beast::unit_test::suite } } + void + testDepositPreauth() + { + testcase("DepositPreauth"); + + using namespace test::jtx; + Account const alice("alice"); // issuer + Account const bob("bob"); // holder + Account const diana("diana"); + Account const dpIssuer("dpIssuer"); // holder + + const char credType[] = "abcde"; + + { + Env env(*this); + + env.fund(XRP(50000), diana, dpIssuer); + env.close(); + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + mptAlice.create( + {.ownerCount = 1, + .holderCount = 0, + .flags = tfMPTRequireAuth | tfMPTCanTransfer}); + + env(pay(diana, bob, XRP(500))); + env.close(); + + // bob creates an empty MPToken + mptAlice.authorize({.account = bob}); + // alice authorizes bob to hold funds + mptAlice.authorize({.account = alice, .holder = bob}); + + // Bob require preauthorization + env(fset(bob, asfDepositAuth)); + env.close(); + + // alice try to send 100 MPT to bob, not authorized + mptAlice.pay(alice, bob, 100, tecNO_PERMISSION); + env.close(); + + // Bob authorize alice + env(deposit::auth(bob, alice)); + env.close(); + + // alice sends 100 MPT to bob + mptAlice.pay(alice, bob, 100); + env.close(); + + // Create credentials + env(credentials::create(alice, dpIssuer, credType)); + env.close(); + env(credentials::accept(alice, dpIssuer, credType)); + env.close(); + auto const jv = + credentials::ledgerEntry(env, alice, dpIssuer, credType); + std::string const credIdx = jv[jss::result][jss::index].asString(); + + // alice sends 100 MPT to bob with credentials which aren't required + mptAlice.pay(alice, bob, 100, tesSUCCESS, {{credIdx}}); + env.close(); + + // Bob revoke authorization + env(deposit::unauth(bob, alice)); + env.close(); + + // alice try to send 100 MPT to bob, not authorized + mptAlice.pay(alice, bob, 100, tecNO_PERMISSION); + env.close(); + + // alice sends 100 MPT to bob with credentials, not authorized + mptAlice.pay(alice, bob, 100, tecNO_PERMISSION, {{credIdx}}); + env.close(); + + // Bob authorize credentials + env(deposit::authCredentials(bob, {{dpIssuer, credType}})); + env.close(); + + // alice try to send 100 MPT to bob, not authorized + mptAlice.pay(alice, bob, 100, tecNO_PERMISSION); + env.close(); + + // alice sends 100 MPT to bob with credentials + mptAlice.pay(alice, bob, 100, tesSUCCESS, {{credIdx}}); + env.close(); + } + + testcase("DepositPreauth disabled featureCredentials"); + { + Env env(*this, supported_amendments() - featureCredentials); + + std::string const credIdx = + "D007AE4B6E1274B4AF872588267B810C2F82716726351D1C7D38D3E5499FC6" + "E2"; + + env.fund(XRP(50000), diana, dpIssuer); + env.close(); + + MPTTester mptAlice(env, alice, {.holders = {bob}}); + mptAlice.create( + {.ownerCount = 1, + .holderCount = 0, + .flags = tfMPTRequireAuth | tfMPTCanTransfer}); + + env(pay(diana, bob, XRP(500))); + env.close(); + + // bob creates an empty MPToken + mptAlice.authorize({.account = bob}); + // alice authorizes bob to hold funds + mptAlice.authorize({.account = alice, .holder = bob}); + + // Bob require preauthorization + env(fset(bob, asfDepositAuth)); + env.close(); + + // alice try to send 100 MPT to bob, not authorized + mptAlice.pay(alice, bob, 100, tecNO_PERMISSION); + env.close(); + + // alice try to send 100 MPT to bob with credentials, amendment + // disabled + mptAlice.pay(alice, bob, 100, temDISABLED, {{credIdx}}); + env.close(); + + // Bob authorize alice + env(deposit::auth(bob, alice)); + env.close(); + + // alice sends 100 MPT to bob + mptAlice.pay(alice, bob, 100); + env.close(); + + // alice sends 100 MPT to bob with credentials, amendment disabled + mptAlice.pay(alice, bob, 100, temDISABLED, {{credIdx}}); + env.close(); + + // Bob revoke authorization + env(deposit::unauth(bob, alice)); + env.close(); + + // alice try to send 100 MPT to bob + mptAlice.pay(alice, bob, 100, tecNO_PERMISSION); + env.close(); + + // alice sends 100 MPT to bob with credentials, amendment disabled + mptAlice.pay(alice, bob, 100, temDISABLED, {{credIdx}}); + env.close(); + } + } + void testMPTInvalidInTx(FeatureBitset features) { @@ -2105,6 +2256,7 @@ class MPToken_test : public beast::unit_test::suite // Test Direct Payment testPayment(all); + testDepositPreauth(); // Test MPT Amount is invalid in Tx, which don't support MPT testMPTInvalidInTx(all); diff --git a/src/test/app/NFTokenBurn_test.cpp b/src/test/app/NFTokenBurn_test.cpp index a84ac63da9d..a56f0a45674 100644 --- a/src/test/app/NFTokenBurn_test.cpp +++ b/src/test/app/NFTokenBurn_test.cpp @@ -28,16 +28,6 @@ namespace ripple { class NFTokenBurnBaseUtil_test : public beast::unit_test::suite { - // Helper function that returns the owner count of an account root. - static std::uint32_t - ownerCount(test::jtx::Env const& env, test::jtx::Account const& acct) - { - std::uint32_t ret{0}; - if (auto const sleAcct = env.le(acct)) - ret = sleAcct->at(sfOwnerCount); - return ret; - } - // Helper function that returns the number of nfts owned by an account. static std::uint32_t nftCount(test::jtx::Env& env, test::jtx::Account const& acct) diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index 9c0e09d6711..0d4786ae72e 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -31,16 +31,6 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite { FeatureBitset const disallowIncoming{featureDisallowIncoming}; - // Helper function that returns the owner count of an account root. - static std::uint32_t - ownerCount(test::jtx::Env const& env, test::jtx::Account const& acct) - { - std::uint32_t ret{0}; - if (auto const sleAcct = env.le(acct)) - ret = sleAcct->at(sfOwnerCount); - return ret; - } - // Helper function that returns the number of NFTs minted by an issuer. static std::uint32_t mintedCount(test::jtx::Env const& env, test::jtx::Account const& issuer) @@ -3948,7 +3938,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite for (Account const& acct : accounts) { if (std::uint32_t ownerCount = - this->ownerCount(env, acct); + test::jtx::ownerCount(env, acct); ownerCount != 1) { std::stringstream ss; diff --git a/src/test/app/Oracle_test.cpp b/src/test/app/Oracle_test.cpp index c2f3c271265..44eeb1c9f98 100644 --- a/src/test/app/Oracle_test.cpp +++ b/src/test/app/Oracle_test.cpp @@ -28,16 +28,6 @@ namespace oracle { struct Oracle_test : public beast::unit_test::suite { private: - // Helper function that returns the owner count of an account root. - static std::uint32_t - ownerCount(jtx::Env const& env, jtx::Account const& acct) - { - std::uint32_t ret{0}; - if (auto const sleAcct = env.le(acct)) - ret = sleAcct->at(sfOwnerCount); - return ret; - } - void testInvalidSet() { diff --git a/src/test/app/PayChan_test.cpp b/src/test/app/PayChan_test.cpp index e49e5cbd6dc..bc1cbba69c0 100644 --- a/src/test/app/PayChan_test.cpp +++ b/src/test/app/PayChan_test.cpp @@ -832,6 +832,190 @@ struct PayChan_test : public beast::unit_test::suite } } + void + testDepositAuthCreds() + { + testcase("Deposit Authorization with Credentials"); + using namespace jtx; + using namespace std::literals::chrono_literals; + + const char credType[] = "abcde"; + + Account const alice("alice"); + Account const bob("bob"); + Account const carol("carol"); + Account const dillon("dillon"); + Account const zelda("zelda"); + + { + Env env{*this}; + env.fund(XRP(10000), alice, bob, carol, dillon, zelda); + + auto const pk = alice.pk(); + auto const settleDelay = 100s; + auto const chan = channel(alice, bob, env.seq(alice)); + env(create(alice, bob, XRP(1000), settleDelay, pk)); + env.close(); + + // alice add funds to the channel + env(fund(alice, chan, XRP(1000))); + env.close(); + + std::string const credBadIdx = + "D007AE4B6E1274B4AF872588267B810C2F82716726351D1C7D38D3E5499FC6" + "E1"; + + auto const delta = XRP(500).value(); + + { // create credentials + auto jv = credentials::create(alice, carol, credType); + uint32_t const t = env.current() + ->info() + .parentCloseTime.time_since_epoch() + .count() + + 100; + jv[sfExpiration.jsonName] = t; + env(jv); + env.close(); + } + + auto const jv = + credentials::ledgerEntry(env, alice, carol, credType); + std::string const credIdx = jv[jss::result][jss::index].asString(); + + // Bob require preauthorization + env(fset(bob, asfDepositAuth)); + env.close(); + + // Fail, credentials not accepted + env(claim(alice, chan, delta, delta), + credentials::ids({credIdx}), + ter(tecBAD_CREDENTIALS)); + env.close(); + + env(credentials::accept(alice, carol, credType)); + env.close(); + + // Fail, no depositPreauth object + env(claim(alice, chan, delta, delta), + credentials::ids({credIdx}), + ter(tecNO_PERMISSION)); + env.close(); + + // Setup deposit authorization + env(deposit::authCredentials(bob, {{carol, credType}})); + env.close(); + + // Fail, credentials doesn’t belong to root account + env(claim(dillon, chan, delta, delta), + credentials::ids({credIdx}), + ter(tecBAD_CREDENTIALS)); + + // Fails because bob's lsfDepositAuth flag is set. + env(claim(alice, chan, delta, delta), ter(tecNO_PERMISSION)); + + // Fail, bad credentials index. + env(claim(alice, chan, delta, delta), + credentials::ids({credBadIdx}), + ter(tecBAD_CREDENTIALS)); + + // Fail, empty credentials + env(claim(alice, chan, delta, delta), + credentials::ids({}), + ter(temMALFORMED)); + + { + // claim fails cause of expired credentials + + // Every cycle +10sec. + for (int i = 0; i < 10; ++i) + env.close(); + + env(claim(alice, chan, delta, delta), + credentials::ids({credIdx}), + ter(tecEXPIRED)); + env.close(); + } + + { // create credentials once more + env(credentials::create(alice, carol, credType)); + env.close(); + env(credentials::accept(alice, carol, credType)); + env.close(); + + auto const jv = + credentials::ledgerEntry(env, alice, carol, credType); + std::string const credIdx = + jv[jss::result][jss::index].asString(); + + // Success + env(claim(alice, chan, delta, delta), + credentials::ids({credIdx})); + } + } + + { + Env env{*this}; + env.fund(XRP(10000), alice, bob, carol, dillon, zelda); + + auto const pk = alice.pk(); + auto const settleDelay = 100s; + auto const chan = channel(alice, bob, env.seq(alice)); + env(create(alice, bob, XRP(1000), settleDelay, pk)); + env.close(); + + // alice add funds to the channel + env(fund(alice, chan, XRP(1000))); + env.close(); + + auto const delta = XRP(500).value(); + + { // create credentials + env(credentials::create(alice, carol, credType)); + env.close(); + env(credentials::accept(alice, carol, credType)); + env.close(); + } + + auto const jv = + credentials::ledgerEntry(env, alice, carol, credType); + std::string const credIdx = jv[jss::result][jss::index].asString(); + + // Succeed, lsfDepositAuth is not set + env(claim(alice, chan, delta, delta), credentials::ids({credIdx})); + env.close(); + } + + { + // Credentials amendment not enabled + Env env(*this, supported_amendments() - featureCredentials); + env.fund(XRP(5000), "alice", "bob"); + env.close(); + + auto const pk = alice.pk(); + auto const settleDelay = 100s; + auto const chan = channel(alice, bob, env.seq(alice)); + env(create(alice, bob, XRP(1000), settleDelay, pk)); + env.close(); + + env(fund(alice, chan, XRP(1000))); + env.close(); + std::string const credIdx = + "48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" + "E4"; + + // can't claim with old DepositPreauth because rule is not enabled. + env(fset(bob, asfDepositAuth)); + env.close(); + env(deposit::auth(bob, alice)); + env.close(); + + env(claim(alice, chan, XRP(500).value(), XRP(500).value()), + credentials::ids({credIdx}), + ter(temDISABLED)); + } + } + void testMultiple(FeatureBitset features) { @@ -2116,6 +2300,7 @@ struct PayChan_test : public beast::unit_test::suite FeatureBitset const all{supported_amendments()}; testWithFeats(all - disallowIncoming); testWithFeats(all); + testDepositAuthCreds(); } }; diff --git a/src/test/jtx.h b/src/test/jtx.h index 49790e34022..b7b9a9fa05c 100644 --- a/src/test/jtx.h +++ b/src/test/jtx.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/src/test/jtx/TestHelpers.h b/src/test/jtx/TestHelpers.h index 7165bc26970..d81551aa840 100644 --- a/src/test/jtx/TestHelpers.h +++ b/src/test/jtx/TestHelpers.h @@ -96,6 +96,10 @@ getAccountLines(Env& env, AccountID const& acctId, IOU... ious) [[nodiscard]] bool checkArraySize(Json::Value const& val, unsigned int size); +// Helper function that returns the owner count on an account. +std::uint32_t +ownerCount(test::jtx::Env const& env, test::jtx::Account const& account); + /* Path finding */ /******************************************************************************/ void diff --git a/src/test/jtx/credentials.h b/src/test/jtx/credentials.h new file mode 100644 index 00000000000..2f5c63dccb8 --- /dev/null +++ b/src/test/jtx/credentials.h @@ -0,0 +1,104 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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. +*/ +//============================================================================== + +#pragma once + +#include +#include +#include + +namespace ripple { +namespace test { +namespace jtx { + +namespace credentials { + +// Sets the optional URI. +class uri +{ +private: + std::string const uri_; + +public: + explicit uri(std::string_view u) : uri_(strHex(u)) + { + } + + void + operator()(jtx::Env&, jtx::JTx& jtx) const + { + jtx.jv[sfURI.jsonName] = uri_; + } +}; + +// Set credentialsIDs array +class ids +{ +private: + std::vector const credentials_; + +public: + explicit ids(std::vector const& creds) : credentials_(creds) + { + } + + void + operator()(jtx::Env&, jtx::JTx& jtx) const + { + auto& arr(jtx.jv[sfCredentialIDs.jsonName] = Json::arrayValue); + for (auto const& hash : credentials_) + arr.append(hash); + } +}; + +Json::Value +create( + jtx::Account const& subject, + jtx::Account const& issuer, + std::string_view credType); + +Json::Value +accept( + jtx::Account const& subject, + jtx::Account const& issuer, + std::string_view credType); + +Json::Value +deleteCred( + jtx::Account const& acc, + jtx::Account const& subject, + jtx::Account const& issuer, + std::string_view credType); + +Json::Value +ledgerEntry( + jtx::Env& env, + jtx::Account const& subject, + jtx::Account const& issuer, + std::string_view credType); + +Json::Value +ledgerEntry(jtx::Env& env, std::string const& credIdx); + +} // namespace credentials + +} // namespace jtx + +} // namespace test +} // namespace ripple diff --git a/src/test/jtx/deposit.h b/src/test/jtx/deposit.h index 720254e7eae..9de3416367c 100644 --- a/src/test/jtx/deposit.h +++ b/src/test/jtx/deposit.h @@ -38,6 +38,41 @@ auth(Account const& account, Account const& auth); Json::Value unauth(Account const& account, Account const& unauth); +struct AuthorizeCredentials +{ + jtx::Account issuer; + std::string credType; + + Json::Value + toJson() const + { + Json::Value jv; + jv[jss::Issuer] = issuer.human(); + jv[sfCredentialType.jsonName] = strHex(credType); + return jv; + } + + // "ledger_entry" uses a different naming convention + Json::Value + toLEJson() const + { + Json::Value jv; + jv[jss::issuer] = issuer.human(); + jv[jss::credential_type] = strHex(credType); + return jv; + } +}; + +Json::Value +authCredentials( + jtx::Account const& account, + std::vector const& auth); + +Json::Value +unauthCredentials( + jtx::Account const& account, + std::vector const& auth); + } // namespace deposit } // namespace jtx diff --git a/src/test/jtx/impl/TestHelpers.cpp b/src/test/jtx/impl/TestHelpers.cpp index b8105b1a631..b39cac7dcc1 100644 --- a/src/test/jtx/impl/TestHelpers.cpp +++ b/src/test/jtx/impl/TestHelpers.cpp @@ -50,6 +50,15 @@ checkArraySize(Json::Value const& val, unsigned int size) return val.isArray() && val.size() == size; } +std::uint32_t +ownerCount(Env const& env, Account const& account) +{ + std::uint32_t ret{0}; + if (auto const sleAccount = env.le(account)) + ret = sleAccount->getFieldU32(sfOwnerCount); + return ret; +} + /* Path finding */ /******************************************************************************/ void @@ -385,4 +394,4 @@ allpe(AccountID const& a, Issue const& iss) } // namespace jtx } // namespace test -} // namespace ripple \ No newline at end of file +} // namespace ripple diff --git a/src/test/jtx/impl/credentials.cpp b/src/test/jtx/impl/credentials.cpp new file mode 100644 index 00000000000..bc7ccf93cd4 --- /dev/null +++ b/src/test/jtx/impl/credentials.cpp @@ -0,0 +1,110 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 +#include +#include + +namespace ripple { +namespace test { +namespace jtx { + +namespace credentials { + +Json::Value +create( + jtx::Account const& subject, + jtx::Account const& issuer, + std::string_view credType) +{ + Json::Value jv; + jv[jss::TransactionType] = jss::CredentialCreate; + + jv[jss::Account] = issuer.human(); + jv[jss::Subject] = subject.human(); + + jv[jss::Flags] = tfUniversal; + jv[sfCredentialType.jsonName] = strHex(credType); + + return jv; +} + +Json::Value +accept( + jtx::Account const& subject, + jtx::Account const& issuer, + std::string_view credType) +{ + Json::Value jv; + jv[jss::TransactionType] = jss::CredentialAccept; + jv[jss::Account] = subject.human(); + jv[jss::Issuer] = issuer.human(); + jv[sfCredentialType.jsonName] = strHex(credType); + jv[jss::Flags] = tfUniversal; + + return jv; +} + +Json::Value +deleteCred( + jtx::Account const& acc, + jtx::Account const& subject, + jtx::Account const& issuer, + std::string_view credType) +{ + Json::Value jv; + jv[jss::TransactionType] = jss::CredentialDelete; + jv[jss::Account] = acc.human(); + jv[jss::Subject] = subject.human(); + jv[jss::Issuer] = issuer.human(); + jv[sfCredentialType.jsonName] = strHex(credType); + jv[jss::Flags] = tfUniversal; + return jv; +} + +Json::Value +ledgerEntry( + jtx::Env& env, + jtx::Account const& subject, + jtx::Account const& issuer, + std::string_view credType) +{ + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::credential][jss::subject] = subject.human(); + jvParams[jss::credential][jss::issuer] = issuer.human(); + jvParams[jss::credential][jss::credential_type] = strHex(credType); + return env.rpc("json", "ledger_entry", to_string(jvParams)); +} + +Json::Value +ledgerEntry(jtx::Env& env, std::string const& credIdx) +{ + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::credential] = credIdx; + return env.rpc("json", "ledger_entry", to_string(jvParams)); +} + +} // namespace credentials + +} // namespace jtx + +} // namespace test +} // namespace ripple diff --git a/src/test/jtx/impl/deposit.cpp b/src/test/jtx/impl/deposit.cpp index 09f0cb704b0..d91607c9906 100644 --- a/src/test/jtx/impl/deposit.cpp +++ b/src/test/jtx/impl/deposit.cpp @@ -48,6 +48,46 @@ unauth(jtx::Account const& account, jtx::Account const& unauth) return jv; } +// Add DepositPreauth. +Json::Value +authCredentials( + jtx::Account const& account, + std::vector const& auth) +{ + Json::Value jv; + jv[sfAccount.jsonName] = account.human(); + jv[sfAuthorizeCredentials.jsonName] = Json::arrayValue; + auto& arr(jv[sfAuthorizeCredentials.jsonName]); + for (auto const& o : auth) + { + Json::Value j2; + j2[jss::Credential] = o.toJson(); + arr.append(std::move(j2)); + } + jv[sfTransactionType.jsonName] = jss::DepositPreauth; + return jv; +} + +// Remove DepositPreauth. +Json::Value +unauthCredentials( + jtx::Account const& account, + std::vector const& auth) +{ + Json::Value jv; + jv[sfAccount.jsonName] = account.human(); + jv[sfUnauthorizeCredentials.jsonName] = Json::arrayValue; + auto& arr(jv[sfUnauthorizeCredentials.jsonName]); + for (auto const& o : auth) + { + Json::Value j2; + j2[jss::Credential] = o.toJson(); + arr.append(std::move(j2)); + } + jv[sfTransactionType.jsonName] = jss::DepositPreauth; + return jv; +} + } // namespace deposit } // namespace jtx diff --git a/src/test/jtx/impl/mpt.cpp b/src/test/jtx/impl/mpt.cpp index d3611efe462..ead6a47c25e 100644 --- a/src/test/jtx/impl/mpt.cpp +++ b/src/test/jtx/impl/mpt.cpp @@ -301,14 +301,23 @@ MPTTester::pay( Account const& src, Account const& dest, std::int64_t amount, - std::optional err) + std::optional err, + std::optional> credentials) { if (!id_) Throw("MPT has not been created"); auto const srcAmt = getBalance(src); auto const destAmt = getBalance(dest); auto const outstnAmt = getBalance(issuer_); - env_(jtx::pay(src, dest, mpt(amount)), ter(err.value_or(tesSUCCESS))); + + if (credentials) + env_( + jtx::pay(src, dest, mpt(amount)), + ter(err.value_or(tesSUCCESS)), + credentials::ids(*credentials)); + else + env_(jtx::pay(src, dest, mpt(amount)), ter(err.value_or(tesSUCCESS))); + if (env_.ter() != tesSUCCESS) amount = 0; if (close_) diff --git a/src/test/jtx/mpt.h b/src/test/jtx/mpt.h index 16a08d8bad9..12b9d74d27c 100644 --- a/src/test/jtx/mpt.h +++ b/src/test/jtx/mpt.h @@ -186,7 +186,8 @@ class MPTTester pay(Account const& src, Account const& dest, std::int64_t amount, - std::optional err = std::nullopt); + std::optional err = std::nullopt, + std::optional> credentials = std::nullopt); void claw( diff --git a/src/test/rpc/DepositAuthorized_test.cpp b/src/test/rpc/DepositAuthorized_test.cpp index ebabe1fbe3f..46637d421e1 100644 --- a/src/test/rpc/DepositAuthorized_test.cpp +++ b/src/test/rpc/DepositAuthorized_test.cpp @@ -31,13 +31,22 @@ class DepositAuthorized_test : public beast::unit_test::suite depositAuthArgs( jtx::Account const& source, jtx::Account const& dest, - std::string const& ledger = "") + std::string const& ledger = "", + std::vector const& credentials = {}) { Json::Value args{Json::objectValue}; args[jss::source_account] = source.human(); args[jss::destination_account] = dest.human(); if (!ledger.empty()) args[jss::ledger_index] = ledger; + + if (!credentials.empty()) + { + auto& arr(args[jss::credentials] = Json::arrayValue); + for (auto const& s : credentials) + arr.append(s); + } + return args; } @@ -276,11 +285,351 @@ class DepositAuthorized_test : public beast::unit_test::suite } } + void + checkCredentialsResponse( + Json::Value const& result, + jtx::Account const& src, + jtx::Account const& dst, + bool authorized, + std::vector credentialIDs = {}, + std::string_view error = "") + { + BEAST_EXPECT( + result[jss::status] == authorized ? jss::success : jss::error); + if (result.isMember(jss::deposit_authorized)) + BEAST_EXPECT(result[jss::deposit_authorized] == authorized); + if (authorized) + BEAST_EXPECT( + result.isMember(jss::deposit_authorized) && + (result[jss::deposit_authorized] == true)); + + BEAST_EXPECT(result.isMember(jss::error) == !error.empty()); + if (!error.empty()) + BEAST_EXPECT(result[jss::error].asString() == error); + + if (authorized) + { + BEAST_EXPECT(result[jss::source_account] == src.human()); + BEAST_EXPECT(result[jss::destination_account] == dst.human()); + + for (unsigned i = 0; i < credentialIDs.size(); ++i) + BEAST_EXPECT(result[jss::credentials][i] == credentialIDs[i]); + } + else + { + BEAST_EXPECT(result[jss::request].isObject()); + + auto const& request = result[jss::request]; + BEAST_EXPECT(request[jss::command] == jss::deposit_authorized); + BEAST_EXPECT(request[jss::source_account] == src.human()); + BEAST_EXPECT(request[jss::destination_account] == dst.human()); + + for (unsigned i = 0; i < credentialIDs.size(); ++i) + BEAST_EXPECT(request[jss::credentials][i] == credentialIDs[i]); + } + } + + void + testCredentials() + { + using namespace jtx; + + const char credType[] = "abcde"; + + Account const alice{"alice"}; + Account const becky{"becky"}; + Account const diana{"diana"}; + Account const carol{"carol"}; + + Env env(*this); + env.fund(XRP(1000), alice, becky, carol, diana); + env.close(); + + // carol recognize alice + env(credentials::create(alice, carol, credType)); + env.close(); + // retrieve the index of the credentials + auto const jv = credentials::ledgerEntry(env, alice, carol, credType); + std::string const credIdx = jv[jss::result][jss::index].asString(); + + // becky sets the DepositAuth flag in the current ledger. + env(fset(becky, asfDepositAuth)); + env.close(); + + // becky authorize any account recognized by carol to make a payment + env(deposit::authCredentials(becky, {{carol, credType}})); + env.close(); + + { + testcase( + "deposit_authorized with credentials failed: empty array."); + + auto args = depositAuthArgs(alice, becky, "validated"); + args[jss::credentials] = Json::arrayValue; + + auto const jv = + env.rpc("json", "deposit_authorized", args.toStyledString()); + checkCredentialsResponse( + jv[jss::result], alice, becky, false, {}, "invalidParams"); + } + + { + testcase( + "deposit_authorized with credentials failed: not a string " + "credentials"); + + auto args = depositAuthArgs(alice, becky, "validated"); + args[jss::credentials] = Json::arrayValue; + args[jss::credentials].append(1); + args[jss::credentials].append(3); + + auto const jv = + env.rpc("json", "deposit_authorized", args.toStyledString()); + checkCredentialsResponse( + jv[jss::result], alice, becky, false, {}, "invalidParams"); + } + + { + testcase( + "deposit_authorized with credentials failed: not a hex string " + "credentials"); + + auto args = depositAuthArgs(alice, becky, "validated"); + args[jss::credentials] = Json::arrayValue; + args[jss::credentials].append("hello world"); + + auto const jv = + env.rpc("json", "deposit_authorized", args.toStyledString()); + checkCredentialsResponse( + jv[jss::result], + alice, + becky, + false, + {"hello world"}, + "invalidParams"); + } + + { + testcase( + "deposit_authorized with credentials failed: not a credential " + "index"); + + auto args = depositAuthArgs( + alice, + becky, + "validated", + {"0127AB8B4B29CCDBB61AA51C0799A8A6BB80B86A9899807C11ED576AF8516" + "473"}); + + auto const jv = + env.rpc("json", "deposit_authorized", args.toStyledString()); + checkCredentialsResponse( + jv[jss::result], + alice, + becky, + false, + {"0127AB8B4B29CCDBB61AA51C0799A8A6BB80B86A9899807C11ED576AF8516" + "473"}, + "badCredentials"); + } + + { + testcase( + "deposit_authorized with credentials not authorized: " + "credential not accepted"); + auto const jv = env.rpc( + "json", + "deposit_authorized", + depositAuthArgs(alice, becky, "validated", {credIdx}) + .toStyledString()); + checkCredentialsResponse( + jv[jss::result], + alice, + becky, + false, + {credIdx}, + "badCredentials"); + } + + // alice accept credentials + env(credentials::accept(alice, carol, credType)); + env.close(); + + { + testcase("deposit_authorized with duplicates in credentials"); + auto const jv = env.rpc( + "json", + "deposit_authorized", + depositAuthArgs(alice, becky, "validated", {credIdx, credIdx}) + .toStyledString()); + checkCredentialsResponse( + jv[jss::result], + alice, + becky, + false, + {credIdx, credIdx}, + "badCredentials"); + } + + { + static const std::vector credIds = { + "18004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" + "E4", + "28004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" + "E4", + "38004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" + "E4", + "48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" + "E4", + "58004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" + "E4", + "68004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" + "E4", + "78004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" + "E4", + "88004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" + "E4", + "98004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" + "E4"}; + assert(credIds.size() > maxCredentialsArraySize); + + testcase("deposit_authorized too long credentials"); + auto const jv = env.rpc( + "json", + "deposit_authorized", + depositAuthArgs(alice, becky, "validated", credIds) + .toStyledString()); + checkCredentialsResponse( + jv[jss::result], alice, becky, false, credIds, "invalidParams"); + } + + { + testcase("deposit_authorized with credentials"); + auto const jv = env.rpc( + "json", + "deposit_authorized", + depositAuthArgs(alice, becky, "validated", {credIdx}) + .toStyledString()); + checkCredentialsResponse( + jv[jss::result], alice, becky, true, {credIdx}); + } + + { + // diana recognize becky + env(credentials::create(becky, diana, credType)); + env.close(); + env(credentials::accept(becky, diana, credType)); + env.close(); + + // retrieve the index of the credentials + auto jv = credentials::ledgerEntry(env, becky, diana, credType); + std::string const credBecky = + jv[jss::result][jss::index].asString(); + + testcase("deposit_authorized account without preauth"); + jv = env.rpc( + "json", + "deposit_authorized", + depositAuthArgs(becky, alice, "validated", {credBecky}) + .toStyledString()); + checkCredentialsResponse( + jv[jss::result], becky, alice, true, {credBecky}); + } + + { + // carol recognize diana + env(credentials::create(diana, carol, credType)); + env.close(); + env(credentials::accept(diana, carol, credType)); + env.close(); + // retrieve the index of the credentials + auto jv = credentials::ledgerEntry(env, alice, carol, credType); + std::string const credDiana = + jv[jss::result][jss::index].asString(); + + // alice try to use credential for different account + jv = env.rpc( + "json", + "deposit_authorized", + depositAuthArgs(becky, alice, "validated", {credDiana}) + .toStyledString()); + checkCredentialsResponse( + jv[jss::result], + becky, + alice, + false, + {credDiana}, + "badCredentials"); + } + + { + testcase("deposit_authorized with expired credentials"); + + // check expired credentials + const char credType2[] = "fghijk"; + std::uint32_t const x = env.current() + ->info() + .parentCloseTime.time_since_epoch() + .count() + + 40; + + // create credentials with expire time 40s + auto jv = credentials::create(alice, carol, credType2); + jv[sfExpiration.jsonName] = x; + env(jv); + env.close(); + env(credentials::accept(alice, carol, credType2)); + env.close(); + jv = credentials::ledgerEntry(env, alice, carol, credType2); + std::string const credIdx2 = jv[jss::result][jss::index].asString(); + + // becky sets the DepositAuth flag in the current ledger. + env(fset(becky, asfDepositAuth)); + env.close(); + + // becky authorize any account recognized by carol to make a payment + env(deposit::authCredentials(becky, {{carol, credType2}})); + env.close(); + + { + // this should be fine + jv = env.rpc( + "json", + "deposit_authorized", + depositAuthArgs(alice, becky, "validated", {credIdx2}) + .toStyledString()); + checkCredentialsResponse( + jv[jss::result], alice, becky, true, {credIdx2}); + } + + // increase timer by 20s + env.close(); + env.close(); + { + // now credentials expired + jv = env.rpc( + "json", + "deposit_authorized", + depositAuthArgs(alice, becky, "validated", {credIdx2}) + .toStyledString()); + + checkCredentialsResponse( + jv[jss::result], + alice, + becky, + false, + {credIdx2}, + "badCredentials"); + } + } + } + void run() override { testValid(); testErrors(); + testCredentials(); } }; diff --git a/src/test/rpc/LedgerRPC_test.cpp b/src/test/rpc/LedgerRPC_test.cpp index 792da88b5bc..c5e10198c49 100644 --- a/src/test/rpc/LedgerRPC_test.cpp +++ b/src/test/rpc/LedgerRPC_test.cpp @@ -727,6 +727,204 @@ class LedgerRPC_test : public beast::unit_test::suite } } + void + testLedgerEntryCredentials() + { + testcase("ledger_entry credentials"); + + using namespace test::jtx; + + Env env(*this); + Account const issuer{"issuer"}; + Account const alice{"alice"}; + Account const bob{"bob"}; + const char credType[] = "abcde"; + + env.fund(XRP(5000), issuer, alice, bob); + env.close(); + + // Setup credentials with DepositAuth object for Alice and Bob + env(credentials::create(alice, issuer, credType)); + env.close(); + + { + // Succeed + auto jv = credentials::ledgerEntry(env, alice, issuer, credType); + BEAST_EXPECT( + jv.isObject() && jv.isMember(jss::result) && + !jv[jss::result].isMember(jss::error) && + jv[jss::result].isMember(jss::node) && + jv[jss::result][jss::node].isMember( + sfLedgerEntryType.jsonName) && + jv[jss::result][jss::node][sfLedgerEntryType.jsonName] == + jss::Credential); + + std::string const credIdx = jv[jss::result][jss::index].asString(); + + jv = credentials::ledgerEntry(env, credIdx); + BEAST_EXPECT( + jv.isObject() && jv.isMember(jss::result) && + !jv[jss::result].isMember(jss::error) && + jv[jss::result].isMember(jss::node) && + jv[jss::result][jss::node].isMember( + sfLedgerEntryType.jsonName) && + jv[jss::result][jss::node][sfLedgerEntryType.jsonName] == + jss::Credential); + } + + { + // Fail, index not a hash + auto const jv = credentials::ledgerEntry(env, ""); + checkErrorValue(jv[jss::result], "malformedRequest", ""); + } + + { + // Fail, credential doesn't exist + auto const jv = credentials::ledgerEntry( + env, + "48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" + "E4"); + checkErrorValue(jv[jss::result], "entryNotFound", ""); + } + + { + // Fail, invalid subject + Json::Value jv; + jv[jss::ledger_index] = jss::validated; + jv[jss::credential][jss::subject] = 42; + jv[jss::credential][jss::issuer] = issuer.human(); + jv[jss::credential][jss::credential_type] = + strHex(std::string_view(credType)); + auto const jrr = env.rpc("json", "ledger_entry", to_string(jv)); + checkErrorValue(jrr[jss::result], "malformedRequest", ""); + } + + { + // Fail, invalid issuer + Json::Value jv; + jv[jss::ledger_index] = jss::validated; + jv[jss::credential][jss::subject] = alice.human(); + jv[jss::credential][jss::issuer] = 42; + jv[jss::credential][jss::credential_type] = + strHex(std::string_view(credType)); + auto const jrr = env.rpc("json", "ledger_entry", to_string(jv)); + checkErrorValue(jrr[jss::result], "malformedRequest", ""); + } + + { + // Fail, invalid credentials type + Json::Value jv; + jv[jss::ledger_index] = jss::validated; + jv[jss::credential][jss::subject] = alice.human(); + jv[jss::credential][jss::issuer] = issuer.human(); + jv[jss::credential][jss::credential_type] = 42; + auto const jrr = env.rpc("json", "ledger_entry", to_string(jv)); + checkErrorValue(jrr[jss::result], "malformedRequest", ""); + } + + { + // Fail, empty subject + Json::Value jv; + jv[jss::ledger_index] = jss::validated; + jv[jss::credential][jss::subject] = ""; + jv[jss::credential][jss::issuer] = issuer.human(); + jv[jss::credential][jss::credential_type] = + strHex(std::string_view(credType)); + auto const jrr = env.rpc("json", "ledger_entry", to_string(jv)); + checkErrorValue(jrr[jss::result], "malformedRequest", ""); + } + + { + // Fail, empty issuer + Json::Value jv; + jv[jss::ledger_index] = jss::validated; + jv[jss::credential][jss::subject] = alice.human(); + jv[jss::credential][jss::issuer] = ""; + jv[jss::credential][jss::credential_type] = + strHex(std::string_view(credType)); + auto const jrr = env.rpc("json", "ledger_entry", to_string(jv)); + checkErrorValue(jrr[jss::result], "malformedRequest", ""); + } + + { + // Fail, empty credentials type + Json::Value jv; + jv[jss::ledger_index] = jss::validated; + jv[jss::credential][jss::subject] = alice.human(); + jv[jss::credential][jss::issuer] = issuer.human(); + jv[jss::credential][jss::credential_type] = ""; + auto const jrr = env.rpc("json", "ledger_entry", to_string(jv)); + checkErrorValue(jrr[jss::result], "malformedRequest", ""); + } + + { + // Fail, no subject + Json::Value jv; + jv[jss::ledger_index] = jss::validated; + jv[jss::credential][jss::issuer] = issuer.human(); + jv[jss::credential][jss::credential_type] = + strHex(std::string_view(credType)); + auto const jrr = env.rpc("json", "ledger_entry", to_string(jv)); + checkErrorValue(jrr[jss::result], "malformedRequest", ""); + } + + { + // Fail, no issuer + Json::Value jv; + jv[jss::ledger_index] = jss::validated; + jv[jss::credential][jss::subject] = alice.human(); + jv[jss::credential][jss::credential_type] = + strHex(std::string_view(credType)); + auto const jrr = env.rpc("json", "ledger_entry", to_string(jv)); + checkErrorValue(jrr[jss::result], "malformedRequest", ""); + } + + { + // Fail, no credentials type + Json::Value jv; + jv[jss::ledger_index] = jss::validated; + jv[jss::credential][jss::subject] = alice.human(); + jv[jss::credential][jss::issuer] = issuer.human(); + auto const jrr = env.rpc("json", "ledger_entry", to_string(jv)); + checkErrorValue(jrr[jss::result], "malformedRequest", ""); + } + + { + // Fail, not AccountID subject + Json::Value jv; + jv[jss::ledger_index] = jss::validated; + jv[jss::credential][jss::subject] = "wehsdbvasbdfvj"; + jv[jss::credential][jss::issuer] = issuer.human(); + jv[jss::credential][jss::credential_type] = + strHex(std::string_view(credType)); + auto const jrr = env.rpc("json", "ledger_entry", to_string(jv)); + checkErrorValue(jrr[jss::result], "malformedRequest", ""); + } + + { + // Fail, not AccountID issuer + Json::Value jv; + jv[jss::ledger_index] = jss::validated; + jv[jss::credential][jss::subject] = alice.human(); + jv[jss::credential][jss::issuer] = "c4p93ugndfbsiu"; + jv[jss::credential][jss::credential_type] = + strHex(std::string_view(credType)); + auto const jrr = env.rpc("json", "ledger_entry", to_string(jv)); + checkErrorValue(jrr[jss::result], "malformedRequest", ""); + } + + { + // Fail, credentials type isn't hex encoded + Json::Value jv; + jv[jss::ledger_index] = jss::validated; + jv[jss::credential][jss::subject] = alice.human(); + jv[jss::credential][jss::issuer] = issuer.human(); + jv[jss::credential][jss::credential_type] = "12KK"; + auto const jrr = env.rpc("json", "ledger_entry", to_string(jv)); + checkErrorValue(jrr[jss::result], "malformedRequest", ""); + } + } + void testLedgerEntryDepositPreauth() { @@ -858,6 +1056,302 @@ class LedgerRPC_test : public beast::unit_test::suite } } + void + testLedgerEntryDepositPreauthCred() + { + testcase("ledger_entry Deposit Preauth with credentials"); + + using namespace test::jtx; + + Env env(*this); + Account const issuer{"issuer"}; + Account const alice{"alice"}; + Account const bob{"bob"}; + const char credType[] = "abcde"; + + env.fund(XRP(5000), issuer, alice, bob); + env.close(); + + { + // Setup Bob with DepositAuth + env(fset(bob, asfDepositAuth), fee(drops(10))); + env.close(); + env(deposit::authCredentials(bob, {{issuer, credType}})); + env.close(); + } + + { + // Succeed + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + + Json::Value jo; + jo[jss::issuer] = issuer.human(); + jo[jss::credential_type] = strHex(std::string_view(credType)); + arr.append(std::move(jo)); + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + + BEAST_EXPECT( + jrr.isObject() && jrr.isMember(jss::result) && + !jrr[jss::result].isMember(jss::error) && + jrr[jss::result].isMember(jss::node) && + jrr[jss::result][jss::node].isMember( + sfLedgerEntryType.jsonName) && + jrr[jss::result][jss::node][sfLedgerEntryType.jsonName] == + jss::DepositPreauth); + } + + { + // Failed, invalid account + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + + Json::Value jo; + jo[jss::issuer] = to_string(xrpAccount()); + jo[jss::credential_type] = strHex(std::string_view(credType)); + arr.append(std::move(jo)); + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); + } + + { + // Failed, duplicates in credentials + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + + Json::Value jo; + jo[jss::issuer] = issuer.human(); + jo[jss::credential_type] = strHex(std::string_view(credType)); + arr.append(jo); + arr.append(std::move(jo)); + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); + } + + { + // Failed, invalid credential_type + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + + Json::Value jo; + jo[jss::issuer] = issuer.human(); + jo[jss::credential_type] = ""; + arr.append(std::move(jo)); + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); + } + + { + // Failed, authorized and authorized_credentials both present + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + jvParams[jss::deposit_preauth][jss::authorized] = alice.human(); + + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + + Json::Value jo; + jo[jss::issuer] = issuer.human(); + jo[jss::credential_type] = strHex(std::string_view(credType)); + arr.append(std::move(jo)); + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue(jrr[jss::result], "malformedRequest", ""); + } + + { + // Failed, authorized_credentials is not an array + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + jvParams[jss::deposit_preauth][jss::authorized_credentials] = 42; + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue(jrr[jss::result], "malformedRequest", ""); + } + + { + // Failed, authorized_credentials is empty array + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); + } + + { + // Failed, authorized_credentials is too long + + static const std::string_view credTypes[] = { + "cred1", + "cred2", + "cred3", + "cred4", + "cred5", + "cred6", + "cred7", + "cred8", + "cred9"}; + static_assert( + sizeof(credTypes) / sizeof(credTypes[0]) > + maxCredentialsArraySize); + + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + + for (unsigned i = 0; i < sizeof(credTypes) / sizeof(credTypes[0]); + ++i) + { + Json::Value jo; + jo[jss::issuer] = issuer.human(); + jo[jss::credential_type] = + strHex(std::string_view(credTypes[i])); + arr.append(std::move(jo)); + } + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); + } + + { + // Failed, issuer isn't string + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + + Json::Value jo; + jo[jss::issuer] = 42; + jo[jss::credential_type] = strHex(std::string_view(credType)); + arr.append(std::move(jo)); + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); + } + + { + // Failed, issuer isn't valid encoded account + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + + Json::Value jo; + jo[jss::issuer] = "invalid_account"; + jo[jss::credential_type] = strHex(std::string_view(credType)); + arr.append(std::move(jo)); + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); + } + + { + // Failed, credential_type isn't string + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + jvParams[jss::deposit_preauth][jss::authorized] = alice.human(); + + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + + Json::Value jo; + jo[jss::issuer] = issuer.human(); + jo[jss::credential_type] = 42; + arr.append(std::move(jo)); + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue(jrr[jss::result], "malformedRequest", ""); + } + + { + // Failed, credential_type isn't hex encoded + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + jvParams[jss::deposit_preauth][jss::authorized] = alice.human(); + + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + + Json::Value jo; + jo[jss::issuer] = issuer.human(); + jo[jss::credential_type] = "12KK"; + arr.append(std::move(jo)); + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue(jrr[jss::result], "malformedRequest", ""); + } + } + void testLedgerEntryDirectory() { @@ -2447,7 +2941,9 @@ class LedgerRPC_test : public beast::unit_test::suite testLedgerAccounts(); testLedgerEntryAccountRoot(); testLedgerEntryCheck(); + testLedgerEntryCredentials(); testLedgerEntryDepositPreauth(); + testLedgerEntryDepositPreauthCred(); testLedgerEntryDirectory(); testLedgerEntryEscrow(); testLedgerEntryOffer(); diff --git a/src/test/rpc/RPCCall_test.cpp b/src/test/rpc/RPCCall_test.cpp index 5f13c9799a1..b812740fb3f 100644 --- a/src/test/rpc/RPCCall_test.cpp +++ b/src/test/rpc/RPCCall_test.cpp @@ -2458,7 +2458,15 @@ static RPCCallTestData const rpcCallTestArray[] = { {"deposit_authorized", "source_account_NotValidated", "destination_account_NotValidated", - "4294967295"}, + "4294967295", + "cred1", + "cred2", + "cred3", + "cred4", + "cred5", + "cred6", + "cred7", + "cred8"}, RPCCallTestData::no_exception, R"({ "method" : "deposit_authorized", @@ -2467,7 +2475,8 @@ static RPCCallTestData const rpcCallTestArray[] = { "api_version" : %API_VER%, "destination_account" : "destination_account_NotValidated", "ledger_index" : 4294967295, - "source_account" : "source_account_NotValidated" + "source_account" : "source_account_NotValidated", + "credentials": ["cred1", "cred2", "cred3", "cred4", "cred5", "cred6", "cred7", "cred8"] } ] })"}, @@ -2512,7 +2521,15 @@ static RPCCallTestData const rpcCallTestArray[] = { "source_account_NotValidated", "destination_account_NotValidated", "ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789", - "spare"}, + "cred1", + "cred2", + "cred3", + "cred4", + "cred5", + "cred6", + "cred7", + "cred8", + "too_much"}, RPCCallTestData::no_exception, R"({ "method" : "deposit_authorized", diff --git a/src/xrpld/app/main/Main.cpp b/src/xrpld/app/main/Main.cpp index 54d5ab1f96a..169a6dad912 100644 --- a/src/xrpld/app/main/Main.cpp +++ b/src/xrpld/app/main/Main.cpp @@ -143,7 +143,7 @@ printHelp(const po::options_description& desc) " connect []\n" " consensus_info\n" " deposit_authorized " - "[]\n" + "[ [, ...]]\n" " feature [ [accept|reject]]\n" " fetch_info [clear]\n" " gateway_balances [] [ [ " diff --git a/src/xrpld/app/misc/CredentialHelpers.cpp b/src/xrpld/app/misc/CredentialHelpers.cpp new file mode 100644 index 00000000000..08b5d804d4b --- /dev/null +++ b/src/xrpld/app/misc/CredentialHelpers.cpp @@ -0,0 +1,262 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 +#include + +#include + +namespace ripple { +namespace credentials { + +bool +checkExpired( + std::shared_ptr const& sleCredential, + NetClock::time_point const& closed) +{ + std::uint32_t const exp = (*sleCredential)[~sfExpiration].value_or( + std::numeric_limits::max()); + std::uint32_t const now = closed.time_since_epoch().count(); + return now > exp; +} + +bool +removeExpired(ApplyView& view, STTx const& tx, beast::Journal const j) +{ + auto const closeTime = view.info().parentCloseTime; + bool foundExpired = false; + + STVector256 const& arr(tx.getFieldV256(sfCredentialIDs)); + for (auto const& h : arr) + { + // Credentials already checked in preclaim. Look only for expired here. + auto const k = keylet::credential(h); + auto const sleCred = view.peek(k); + + if (sleCred && checkExpired(sleCred, closeTime)) + { + JLOG(j.trace()) + << "Credentials are expired. Cred: " << sleCred->getText(); + // delete expired credentials even if the transaction failed + deleteSLE(view, sleCred, j); + foundExpired = true; + } + } + + return foundExpired; +} + +TER +deleteSLE( + ApplyView& view, + std::shared_ptr const& sleCredential, + beast::Journal j) +{ + if (!sleCredential) + return tecNO_ENTRY; + + auto delSLE = + [&view, &sleCredential, j]( + AccountID const& account, SField const& node, bool isOwner) -> TER { + auto const sleAccount = view.peek(keylet::account(account)); + if (!sleAccount) + { + JLOG(j.fatal()) << "Internal error: can't retrieve Owner account."; + return tecINTERNAL; + } + + // Remove object from owner directory + std::uint64_t const page = sleCredential->getFieldU64(node); + if (!view.dirRemove( + keylet::ownerDir(account), page, sleCredential->key(), false)) + { + JLOG(j.fatal()) << "Unable to delete Credential from owner."; + return tefBAD_LEDGER; + } + + if (isOwner) + adjustOwnerCount(view, sleAccount, -1, j); + + return tesSUCCESS; + }; + + auto const issuer = sleCredential->getAccountID(sfIssuer); + auto const subject = sleCredential->getAccountID(sfSubject); + bool const accepted = sleCredential->getFlags() & lsfAccepted; + + auto err = delSLE(issuer, sfIssuerNode, !accepted || (subject == issuer)); + if (!isTesSuccess(err)) + return err; + + if (subject != issuer) + { + err = delSLE(subject, sfSubjectNode, accepted); + if (!isTesSuccess(err)) + return err; + } + + // Remove object from ledger + view.erase(sleCredential); + + return tesSUCCESS; +} + +NotTEC +checkFields(PreflightContext const& ctx) +{ + if (!ctx.tx.isFieldPresent(sfCredentialIDs)) + return tesSUCCESS; + + auto const& credentials = ctx.tx.getFieldV256(sfCredentialIDs); + if (credentials.empty() || (credentials.size() > maxCredentialsArraySize)) + { + JLOG(ctx.j.trace()) + << "Malformed transaction: Credentials array size is invalid: " + << credentials.size(); + return temMALFORMED; + } + + std::unordered_set duplicates; + for (auto const& cred : credentials) + { + auto [it, ins] = duplicates.insert(cred); + if (!ins) + { + JLOG(ctx.j.trace()) + << "Malformed transaction: duplicates in credentials."; + return temMALFORMED; + } + } + + return tesSUCCESS; +} + +TER +valid(PreclaimContext const& ctx, AccountID const& src) +{ + if (!ctx.tx.isFieldPresent(sfCredentialIDs)) + return tesSUCCESS; + + auto const& credIDs(ctx.tx.getFieldV256(sfCredentialIDs)); + for (auto const& h : credIDs) + { + auto const sleCred = ctx.view.read(keylet::credential(h)); + if (!sleCred) + { + JLOG(ctx.j.trace()) << "Credential doesn't exist. Cred: " << h; + return tecBAD_CREDENTIALS; + } + + if (sleCred->getAccountID(sfSubject) != src) + { + JLOG(ctx.j.trace()) + << "Credential doesn’t belong to the source account. Cred: " + << h; + return tecBAD_CREDENTIALS; + } + + if (!(sleCred->getFlags() & lsfAccepted)) + { + JLOG(ctx.j.trace()) << "Credential isn't accepted. Cred: " << h; + return tecBAD_CREDENTIALS; + } + + // Expiration checks are in doApply + } + + return tesSUCCESS; +} + +TER +authorized(ApplyContext const& ctx, AccountID const& dst) +{ + auto const& credIDs(ctx.tx.getFieldV256(sfCredentialIDs)); + std::set> sorted; + std::vector> lifeExtender; + lifeExtender.reserve(credIDs.size()); + for (auto const& h : credIDs) + { + auto sleCred = ctx.view().read(keylet::credential(h)); + if (!sleCred) // already checked in preclaim + return tefINTERNAL; + + auto [it, ins] = + sorted.emplace((*sleCred)[sfIssuer], (*sleCred)[sfCredentialType]); + if (!ins) + return tefINTERNAL; + lifeExtender.push_back(std::move(sleCred)); + } + + if (!ctx.view().exists(keylet::depositPreauth(dst, sorted))) + { + JLOG(ctx.journal.trace()) << "DepositPreauth doesn't exist"; + return tecNO_PERMISSION; + } + + return tesSUCCESS; +} + +std::set> +makeSorted(STArray const& in) +{ + std::set> out; + for (auto const& cred : in) + { + auto [it, ins] = out.emplace(cred[sfIssuer], cred[sfCredentialType]); + if (!ins) + return {}; + } + return out; +} + +} // namespace credentials + +TER +verifyDepositPreauth( + ApplyContext& ctx, + AccountID const& src, + AccountID const& dst, + std::shared_ptr const& sleDst) +{ + // If depositPreauth is enabled, then an account that requires + // authorization has at least two ways to get a payment in: + // 1. If src == dst, or + // 2. If src is deposit preauthorized by dst (either by account or by + // credentials). + + bool const credentialsPresent = ctx.tx.isFieldPresent(sfCredentialIDs); + + if (credentialsPresent && + credentials::removeExpired(ctx.view(), ctx.tx, ctx.journal)) + return tecEXPIRED; + + if (sleDst && (sleDst->getFlags() & lsfDepositAuth)) + { + if (src != dst) + { + if (!ctx.view().exists(keylet::depositPreauth(dst, src))) + return !credentialsPresent ? tecNO_PERMISSION + : credentials::authorized(ctx, dst); + } + } + + return tesSUCCESS; +} + +} // namespace ripple diff --git a/src/xrpld/app/misc/CredentialHelpers.h b/src/xrpld/app/misc/CredentialHelpers.h new file mode 100644 index 00000000000..3291fc1daa6 --- /dev/null +++ b/src/xrpld/app/misc/CredentialHelpers.h @@ -0,0 +1,77 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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. +*/ +//============================================================================== + +#pragma once + +#include + +#include + +namespace ripple { +namespace credentials { + +// These function will be used by the code that use DepositPreauth / Credentials +// (and any future preauthorization modes) as part of authorization (all the +// transfer funds transactions) + +// Check if credential sfExpiration field has passed ledger's parentCloseTime +bool +checkExpired( + std::shared_ptr const& sleCredential, + NetClock::time_point const& closed); + +// Return true if at least 1 expired credentials was found(and deleted) +bool +removeExpired(ApplyView& view, STTx const& tx, beast::Journal const j); + +// Actually remove a credentials object from the ledger +TER +deleteSLE( + ApplyView& view, + std::shared_ptr const& sleCredential, + beast::Journal j); + +// Amendment and parameters checks for sfCredentialIDs field +NotTEC +checkFields(PreflightContext const& ctx); + +// Accessing the ledger to check if provided credentials are valid +TER +valid(PreclaimContext const& ctx, AccountID const& src); + +// This function is only called when we about to return tecNO_PERMISSION because +// all the checks for the DepositPreauth authorization failed. +TER +authorized(ApplyContext const& ctx, AccountID const& dst); + +// return empty set if there are duplicates +std::set> +makeSorted(STArray const& in); + +} // namespace credentials + +// Check expired credentials and for existing DepositPreauth ledger object +TER +verifyDepositPreauth( + ApplyContext& ctx, + AccountID const& src, + AccountID const& dst, + std::shared_ptr const& sleDst); + +} // namespace ripple diff --git a/src/xrpld/app/tx/detail/Credentials.cpp b/src/xrpld/app/tx/detail/Credentials.cpp new file mode 100644 index 00000000000..4da875f8d7c --- /dev/null +++ b/src/xrpld/app/tx/detail/Credentials.cpp @@ -0,0 +1,382 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace ripple { + +/* + Credentials + ====== + + A verifiable credentials (VC + https://en.wikipedia.org/wiki/Verifiable_credentials), as defined by the W3C + specification (https://www.w3.org/TR/vc-data-model-2.0/), is a + secure and tamper-evident way to represent information about a subject, such + as an individual, organization, or even an IoT device. These credentials are + issued by a trusted entity and can be verified by third parties without + directly involving the issuer at all. +*/ + +using namespace credentials; + +// ------- CREATE -------------------------- + +NotTEC +CredentialCreate::preflight(PreflightContext const& ctx) +{ + if (!ctx.rules.enabled(featureCredentials)) + { + JLOG(ctx.j.trace()) << "featureCredentials is disabled."; + return temDISABLED; + } + + if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) + return ret; + + auto const& tx = ctx.tx; + auto& j = ctx.j; + + if (!tx[sfSubject]) + { + JLOG(j.trace()) << "Malformed transaction: Invalid Subject"; + return temMALFORMED; + } + + auto const uri = tx[~sfURI]; + if (uri && (uri->empty() || (uri->size() > maxCredentialURILength))) + { + JLOG(j.trace()) << "Malformed transaction: invalid size of URI."; + return temMALFORMED; + } + + auto const credType = tx[sfCredentialType]; + if (credType.empty() || (credType.size() > maxCredentialTypeLength)) + { + JLOG(j.trace()) + << "Malformed transaction: invalid size of CredentialType."; + return temMALFORMED; + } + + return preflight2(ctx); +} + +TER +CredentialCreate::preclaim(PreclaimContext const& ctx) +{ + auto const credType(ctx.tx[sfCredentialType]); + auto const subject = ctx.tx[sfSubject]; + + if (!ctx.view.exists(keylet::account(subject))) + { + JLOG(ctx.j.trace()) << "Subject doesn't exist."; + return tecNO_TARGET; + } + + if (ctx.view.exists( + keylet::credential(subject, ctx.tx[sfAccount], credType))) + { + JLOG(ctx.j.trace()) << "Credential already exists."; + return tecDUPLICATE; + } + + return tesSUCCESS; +} + +TER +CredentialCreate::doApply() +{ + auto const subject = ctx_.tx[sfSubject]; + auto const credType(ctx_.tx[sfCredentialType]); + Keylet const credentialKey = + keylet::credential(subject, account_, credType); + + auto const sleCred = std::make_shared(credentialKey); + if (!sleCred) + return tefINTERNAL; + + auto const optExp = ctx_.tx[~sfExpiration]; + if (optExp) + { + std::uint32_t const closeTime = + ctx_.view().info().parentCloseTime.time_since_epoch().count(); + + if (closeTime > *optExp) + { + JLOG(j_.trace()) << "Malformed transaction: " + "Expiration time is in the past."; + return tecEXPIRED; + } + + sleCred->setFieldU32(sfExpiration, ctx_.tx.getFieldU32(sfExpiration)); + } + + auto const sleIssuer = view().peek(keylet::account(account_)); + if (!sleIssuer) + return tefINTERNAL; + + { + STAmount const reserve{view().fees().accountReserve( + sleIssuer->getFieldU32(sfOwnerCount) + 1)}; + if (mPriorBalance < reserve) + return tecINSUFFICIENT_RESERVE; + } + + sleCred->setAccountID(sfSubject, subject); + sleCred->setAccountID(sfIssuer, account_); + sleCred->setFieldVL(sfCredentialType, credType); + + if (ctx_.tx.isFieldPresent(sfURI)) + sleCred->setFieldVL(sfURI, ctx_.tx.getFieldVL(sfURI)); + + { + auto const page = view().dirInsert( + keylet::ownerDir(account_), + credentialKey, + describeOwnerDir(account_)); + JLOG(j_.trace()) << "Adding Credential to owner directory " + << to_string(credentialKey.key) << ": " + << (page ? "success" : "failure"); + if (!page) + return tecDIR_FULL; + sleCred->setFieldU64(sfIssuerNode, *page); + + adjustOwnerCount(view(), sleIssuer, 1, j_); + } + + if (subject == account_) + { + sleCred->setFieldU32(sfFlags, lsfAccepted); + } + else + { + auto const page = view().dirInsert( + keylet::ownerDir(subject), + credentialKey, + describeOwnerDir(subject)); + JLOG(j_.trace()) << "Adding Credential to owner directory " + << to_string(credentialKey.key) << ": " + << (page ? "success" : "failure"); + if (!page) + return tecDIR_FULL; + sleCred->setFieldU64(sfSubjectNode, *page); + view().update(view().peek(keylet::account(subject))); + } + + view().insert(sleCred); + + return tesSUCCESS; +} + +// ------- DELETE -------------------------- +NotTEC +CredentialDelete::preflight(PreflightContext const& ctx) +{ + if (!ctx.rules.enabled(featureCredentials)) + { + JLOG(ctx.j.trace()) << "featureCredentials is disabled."; + return temDISABLED; + } + + if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) + return ret; + + auto const subject = ctx.tx[~sfSubject]; + auto const issuer = ctx.tx[~sfIssuer]; + + if (!subject && !issuer) + { + // Neither field is present, the transaction is malformed. + JLOG(ctx.j.trace()) << "Malformed transaction: " + "No Subject or Issuer fields."; + return temMALFORMED; + } + + // Make sure that the passed account is valid. + if ((subject && subject->isZero()) || (issuer && issuer->isZero())) + { + JLOG(ctx.j.trace()) << "Malformed transaction: Subject or Issuer " + "field zeroed."; + return temINVALID_ACCOUNT_ID; + } + + auto const credType = ctx.tx[sfCredentialType]; + if (credType.empty() || (credType.size() > maxCredentialTypeLength)) + { + JLOG(ctx.j.trace()) + << "Malformed transaction: invalid size of CredentialType."; + return temMALFORMED; + } + + return preflight2(ctx); +} + +TER +CredentialDelete::preclaim(PreclaimContext const& ctx) +{ + AccountID const account{ctx.tx[sfAccount]}; + auto const subject = ctx.tx[~sfSubject].value_or(account); + auto const issuer = ctx.tx[~sfIssuer].value_or(account); + auto const credType(ctx.tx[sfCredentialType]); + + if (!ctx.view.exists(keylet::credential(subject, issuer, credType))) + return tecNO_ENTRY; + + return tesSUCCESS; +} + +TER +CredentialDelete::doApply() +{ + auto const subject = ctx_.tx[~sfSubject].value_or(account_); + auto const issuer = ctx_.tx[~sfIssuer].value_or(account_); + + auto const credType(ctx_.tx[sfCredentialType]); + auto const sleCred = + view().peek(keylet::credential(subject, issuer, credType)); + if (!sleCred) + return tefINTERNAL; + + if ((subject != account_) && (issuer != account_) && + !checkExpired(sleCred, ctx_.view().info().parentCloseTime)) + { + JLOG(j_.trace()) << "Can't delete non-expired credential."; + return tecNO_PERMISSION; + } + + return deleteSLE(view(), sleCred, j_); +} + +// ------- APPLY -------------------------- + +NotTEC +CredentialAccept::preflight(PreflightContext const& ctx) +{ + if (!ctx.rules.enabled(featureCredentials)) + { + JLOG(ctx.j.trace()) << "featureCredentials is disabled."; + return temDISABLED; + } + + if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) + return ret; + + if (!ctx.tx[sfIssuer]) + { + JLOG(ctx.j.trace()) << "Malformed transaction: Issuer field zeroed."; + return temINVALID_ACCOUNT_ID; + } + + auto const credType = ctx.tx[sfCredentialType]; + if (credType.empty() || (credType.size() > maxCredentialTypeLength)) + { + JLOG(ctx.j.trace()) + << "Malformed transaction: invalid size of CredentialType."; + return temMALFORMED; + } + + return preflight2(ctx); +} + +TER +CredentialAccept::preclaim(PreclaimContext const& ctx) +{ + AccountID const subject = ctx.tx[sfAccount]; + AccountID const issuer = ctx.tx[sfIssuer]; + auto const credType(ctx.tx[sfCredentialType]); + + if (!ctx.view.exists(keylet::account(issuer))) + { + JLOG(ctx.j.warn()) << "No issuer: " << to_string(issuer); + return tecNO_ISSUER; + } + + auto const sleCred = + ctx.view.read(keylet::credential(subject, issuer, credType)); + if (!sleCred) + { + JLOG(ctx.j.warn()) << "No credential: " << to_string(subject) << ", " + << to_string(issuer) << ", " << credType; + return tecNO_ENTRY; + } + + if (sleCred->getFieldU32(sfFlags) & lsfAccepted) + { + JLOG(ctx.j.warn()) << "Credential already accepted: " + << to_string(subject) << ", " << to_string(issuer) + << ", " << credType; + return tecDUPLICATE; + } + + return tesSUCCESS; +} + +TER +CredentialAccept::doApply() +{ + AccountID const issuer{ctx_.tx[sfIssuer]}; + + // Both exist as credential object exist itself (checked in preclaim) + auto const sleSubject = view().peek(keylet::account(account_)); + auto const sleIssuer = view().peek(keylet::account(issuer)); + + if (!sleSubject || !sleIssuer) + return tefINTERNAL; + + { + STAmount const reserve{view().fees().accountReserve( + sleSubject->getFieldU32(sfOwnerCount) + 1)}; + if (mPriorBalance < reserve) + return tecINSUFFICIENT_RESERVE; + } + + auto const credType(ctx_.tx[sfCredentialType]); + Keylet const credentialKey = keylet::credential(account_, issuer, credType); + auto const sleCred = view().peek(credentialKey); // Checked in preclaim() + + if (checkExpired(sleCred, view().info().parentCloseTime)) + { + JLOG(j_.trace()) << "Credential is expired: " << sleCred->getText(); + // delete expired credentials even if the transaction failed + auto const err = credentials::deleteSLE(view(), sleCred, j_); + return isTesSuccess(err) ? tecEXPIRED : err; + } + + sleCred->setFieldU32(sfFlags, lsfAccepted); + view().update(sleCred); + + adjustOwnerCount(view(), sleIssuer, -1, j_); + adjustOwnerCount(view(), sleSubject, 1, j_); + + return tesSUCCESS; +} + +} // namespace ripple diff --git a/src/xrpld/app/tx/detail/Credentials.h b/src/xrpld/app/tx/detail/Credentials.h new file mode 100644 index 00000000000..7e7522d82c1 --- /dev/null +++ b/src/xrpld/app/tx/detail/Credentials.h @@ -0,0 +1,87 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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. +*/ +//============================================================================== + +#pragma once + +#include + +namespace ripple { + +class CredentialCreate : public Transactor +{ +public: + static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; + + explicit CredentialCreate(ApplyContext& ctx) : Transactor(ctx) + { + } + + static NotTEC + preflight(PreflightContext const& ctx); + + static TER + preclaim(PreclaimContext const& ctx); + + TER + doApply() override; +}; + +//------------------------------------------------------------------------------ + +class CredentialDelete : public Transactor +{ +public: + static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; + + explicit CredentialDelete(ApplyContext& ctx) : Transactor(ctx) + { + } + + static NotTEC + preflight(PreflightContext const& ctx); + + static TER + preclaim(PreclaimContext const& ctx); + + TER + doApply() override; +}; + +//------------------------------------------------------------------------------ + +class CredentialAccept : public Transactor +{ +public: + static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; + + explicit CredentialAccept(ApplyContext& ctx) : Transactor(ctx) + { + } + + static NotTEC + preflight(PreflightContext const& ctx); + + static TER + preclaim(PreclaimContext const& ctx); + + TER + doApply() override; +}; + +} // namespace ripple diff --git a/src/xrpld/app/tx/detail/DeleteAccount.cpp b/src/xrpld/app/tx/detail/DeleteAccount.cpp index fb2f3fc507f..a7f33a3d8dd 100644 --- a/src/xrpld/app/tx/detail/DeleteAccount.cpp +++ b/src/xrpld/app/tx/detail/DeleteAccount.cpp @@ -17,6 +17,7 @@ */ //============================================================================== +#include #include #include #include @@ -41,6 +42,10 @@ DeleteAccount::preflight(PreflightContext const& ctx) if (!ctx.rules.enabled(featureDeletableAccounts)) return temDISABLED; + if (ctx.tx.isFieldPresent(sfCredentialIDs) && + !ctx.rules.enabled(featureCredentials)) + return temDISABLED; + if (ctx.tx.getFlags() & tfUniversalMask) return temINVALID_FLAG; @@ -51,6 +56,9 @@ DeleteAccount::preflight(PreflightContext const& ctx) // An account cannot be deleted and give itself the resulting XRP. return temDST_IS_SRC; + if (auto const err = credentials::checkFields(ctx); !isTesSuccess(err)) + return err; + return preflight2(ctx); } @@ -110,14 +118,14 @@ removeTicketFromLedger( TER removeDepositPreauthFromLedger( - Application& app, + Application&, ApplyView& view, - AccountID const& account, + AccountID const&, uint256 const& delIndex, - std::shared_ptr const& sleDel, + std::shared_ptr const&, beast::Journal j) { - return DepositPreauth::removeFromLedger(app, view, delIndex, j); + return DepositPreauth::removeFromLedger(view, delIndex, j); } TER @@ -159,6 +167,18 @@ removeOracleFromLedger( return DeleteOracle::deleteOracle(view, sleDel, account, j); } +TER +removeCredentialFromLedger( + Application&, + ApplyView& view, + AccountID const&, + uint256 const&, + std::shared_ptr const& sleDel, + beast::Journal j) +{ + return credentials::deleteSLE(view, sleDel, j); +} + // Return nullptr if the LedgerEntryType represents an obligation that can't // be deleted. Otherwise return the pointer to the function that can delete // the non-obligation @@ -181,6 +201,8 @@ nonObligationDeleter(LedgerEntryType t) return removeDIDFromLedger; case ltORACLE: return removeOracleFromLedger; + case ltCREDENTIAL: + return removeCredentialFromLedger; default: return nullptr; } @@ -202,12 +224,21 @@ DeleteAccount::preclaim(PreclaimContext const& ctx) if ((*sleDst)[sfFlags] & lsfRequireDestTag && !ctx.tx[~sfDestinationTag]) return tecDST_TAG_NEEDED; - // Check whether the destination account requires deposit authorization. - if (ctx.view.rules().enabled(featureDepositAuth) && - (sleDst->getFlags() & lsfDepositAuth)) + // If credentials are provided - check them anyway + if (auto const err = credentials::valid(ctx, account); !isTesSuccess(err)) + return err; + + // if credentials then postpone auth check to doApply, to check for expired + // credentials + if (!ctx.tx.isFieldPresent(sfCredentialIDs)) { - if (!ctx.view.exists(keylet::depositPreauth(dst, account))) - return tecNO_PERMISSION; + // Check whether the destination account requires deposit authorization. + if (ctx.view.rules().enabled(featureDepositAuth) && + (sleDst->getFlags() & lsfDepositAuth)) + { + if (!ctx.view.exists(keylet::depositPreauth(dst, account))) + return tecNO_PERMISSION; + } } auto sleAccount = ctx.view.read(keylet::account(account)); @@ -316,12 +347,21 @@ DeleteAccount::doApply() auto src = view().peek(keylet::account(account_)); assert(src); - auto dst = view().peek(keylet::account(ctx_.tx[sfDestination])); + auto const dstID = ctx_.tx[sfDestination]; + auto dst = view().peek(keylet::account(dstID)); assert(dst); if (!src || !dst) return tefBAD_LEDGER; + if (ctx_.view().rules().enabled(featureDepositAuth) && + ctx_.tx.isFieldPresent(sfCredentialIDs)) + { + if (auto err = verifyDepositPreauth(ctx_, account_, dstID, dst); + !isTesSuccess(err)) + return err; + } + Keylet const ownerDirKeylet{keylet::ownerDir(account_)}; auto const ter = cleanupOnAccountDelete( view(), diff --git a/src/xrpld/app/tx/detail/DepositPreauth.cpp b/src/xrpld/app/tx/detail/DepositPreauth.cpp index b60fd3e0eae..73cd19e4120 100644 --- a/src/xrpld/app/tx/detail/DepositPreauth.cpp +++ b/src/xrpld/app/tx/detail/DepositPreauth.cpp @@ -17,14 +17,19 @@ */ //============================================================================== +#include #include #include #include #include #include #include +#include #include +#include +#include + namespace ripple { NotTEC @@ -33,45 +38,101 @@ DepositPreauth::preflight(PreflightContext const& ctx) if (!ctx.rules.enabled(featureDepositPreauth)) return temDISABLED; + bool const authArrPresent = ctx.tx.isFieldPresent(sfAuthorizeCredentials); + bool const unauthArrPresent = + ctx.tx.isFieldPresent(sfUnauthorizeCredentials); + int const authCredPresent = + static_cast(authArrPresent) + static_cast(unauthArrPresent); + + if (authCredPresent && !ctx.rules.enabled(featureCredentials)) + return temDISABLED; + if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) return ret; auto& tx = ctx.tx; - auto& j = ctx.j; if (tx.getFlags() & tfUniversalMask) { - JLOG(j.trace()) << "Malformed transaction: Invalid flags set."; + JLOG(ctx.j.trace()) << "Malformed transaction: Invalid flags set."; return temINVALID_FLAG; } auto const optAuth = ctx.tx[~sfAuthorize]; auto const optUnauth = ctx.tx[~sfUnauthorize]; - if (static_cast(optAuth) == static_cast(optUnauth)) + int const authPresent = static_cast(optAuth.has_value()) + + static_cast(optUnauth.has_value()); + + if (authPresent + authCredPresent != 1) { - // Either both fields are present or neither field is present. In - // either case the transaction is malformed. - JLOG(j.trace()) + // There can only be 1 field out of 4 or the transaction is malformed. + JLOG(ctx.j.trace()) << "Malformed transaction: " "Invalid Authorize and Unauthorize field combination."; return temMALFORMED; } - // Make sure that the passed account is valid. - AccountID const target{optAuth ? *optAuth : *optUnauth}; - if (target == beast::zero) + if (authPresent) { - JLOG(j.trace()) << "Malformed transaction: Authorized or Unauthorized " - "field zeroed."; - return temINVALID_ACCOUNT_ID; - } + // Make sure that the passed account is valid. + AccountID const& target(optAuth ? *optAuth : *optUnauth); + if (!target) + { + JLOG(ctx.j.trace()) + << "Malformed transaction: Authorized or Unauthorized " + "field zeroed."; + return temINVALID_ACCOUNT_ID; + } - // An account may not preauthorize itself. - if (optAuth && (target == ctx.tx[sfAccount])) + // An account may not preauthorize itself. + if (optAuth && (target == ctx.tx[sfAccount])) + { + JLOG(ctx.j.trace()) + << "Malformed transaction: Attempting to DepositPreauth self."; + return temCANNOT_PREAUTH_SELF; + } + } + else { - JLOG(j.trace()) - << "Malformed transaction: Attempting to DepositPreauth self."; - return temCANNOT_PREAUTH_SELF; + STArray const& arr(ctx.tx.getFieldArray( + authArrPresent ? sfAuthorizeCredentials + : sfUnauthorizeCredentials)); + if (arr.empty() || (arr.size() > maxCredentialsArraySize)) + { + JLOG(ctx.j.trace()) << "Malformed transaction: " + "Invalid AuthorizeCredentials size: " + << arr.size(); + return temMALFORMED; + } + + std::unordered_set duplicates; + for (auto const& o : arr) + { + auto const& issuer(o[sfIssuer]); + if (!issuer) + { + JLOG(ctx.j.trace()) + << "Malformed transaction: " + "AuthorizeCredentials Issuer account is invalid."; + return temINVALID_ACCOUNT_ID; + } + + auto const ct = o[sfCredentialType]; + if (ct.empty() || (ct.size() > maxCredentialTypeLength)) + { + JLOG(ctx.j.trace()) + << "Malformed transaction: invalid size of CredentialType."; + return temMALFORMED; + } + + auto [it, ins] = duplicates.insert(sha512Half(issuer, ct)); + if (!ins) + { + JLOG(ctx.j.trace()) + << "Malformed transaction: duplicates in credentials."; + return temMALFORMED; + } + } } return preflight2(ctx); @@ -80,6 +141,8 @@ DepositPreauth::preflight(PreflightContext const& ctx) TER DepositPreauth::preclaim(PreclaimContext const& ctx) { + AccountID const account(ctx.tx[sfAccount]); + // Determine which operation we're performing: authorizing or unauthorizing. if (ctx.tx.isFieldPresent(sfAuthorize)) { @@ -90,14 +153,42 @@ DepositPreauth::preclaim(PreclaimContext const& ctx) // Verify that the Preauth entry they asked to add is not already // in the ledger. - if (ctx.view.exists(keylet::depositPreauth(ctx.tx[sfAccount], auth))) + if (ctx.view.exists(keylet::depositPreauth(account, auth))) return tecDUPLICATE; } - else + else if (ctx.tx.isFieldPresent(sfUnauthorize)) { // Verify that the Preauth entry they asked to remove is in the ledger. - AccountID const unauth{ctx.tx[sfUnauthorize]}; - if (!ctx.view.exists(keylet::depositPreauth(ctx.tx[sfAccount], unauth))) + if (!ctx.view.exists( + keylet::depositPreauth(account, ctx.tx[sfUnauthorize]))) + return tecNO_ENTRY; + } + else if (ctx.tx.isFieldPresent(sfAuthorizeCredentials)) + { + STArray const& authCred(ctx.tx.getFieldArray(sfAuthorizeCredentials)); + std::set> sorted; + for (auto const& o : authCred) + { + auto const& issuer = o[sfIssuer]; + if (!ctx.view.exists(keylet::account(issuer))) + return tecNO_ISSUER; + auto [it, ins] = sorted.emplace(issuer, o[sfCredentialType]); + if (!ins) + return tefINTERNAL; + } + + // Verify that the Preauth entry they asked to add is not already + // in the ledger. + if (ctx.view.exists(keylet::depositPreauth(account, sorted))) + return tecDUPLICATE; + } + else if (ctx.tx.isFieldPresent(sfUnauthorizeCredentials)) + { + // Verify that the Preauth entry is in the ledger. + if (!ctx.view.exists(keylet::depositPreauth( + account, + credentials::makeSorted( + ctx.tx.getFieldArray(sfUnauthorizeCredentials))))) return tecNO_ENTRY; } return tesSUCCESS; @@ -133,7 +224,6 @@ DepositPreauth::doApply() slePreauth->setAccountID(sfAuthorize, auth); view().insert(slePreauth); - auto viewJ = ctx_.app.journal("View"); auto const page = view().dirInsert( keylet::ownerDir(account_), preauthKeylet, @@ -149,30 +239,92 @@ DepositPreauth::doApply() slePreauth->setFieldU64(sfOwnerNode, *page); // If we succeeded, the new entry counts against the creator's reserve. - adjustOwnerCount(view(), sleOwner, 1, viewJ); + adjustOwnerCount(view(), sleOwner, 1, j_); } - else + else if (ctx_.tx.isFieldPresent(sfUnauthorize)) { auto const preauth = keylet::depositPreauth(account_, ctx_.tx[sfUnauthorize]); - return DepositPreauth::removeFromLedger( - ctx_.app, view(), preauth.key, j_); + return DepositPreauth::removeFromLedger(view(), preauth.key, j_); + } + else if (ctx_.tx.isFieldPresent(sfAuthorizeCredentials)) + { + auto const sleOwner = view().peek(keylet::account(account_)); + if (!sleOwner) + return tefINTERNAL; + + // A preauth counts against the reserve of the issuing account, but we + // check the starting balance because we want to allow dipping into the + // reserve to pay fees. + { + STAmount const reserve{view().fees().accountReserve( + sleOwner->getFieldU32(sfOwnerCount) + 1)}; + + if (mPriorBalance < reserve) + return tecINSUFFICIENT_RESERVE; + } + + // Preclaim already verified that the Preauth entry does not yet exist. + // Create and populate the Preauth entry. + + auto const sortedTX = credentials::makeSorted( + ctx_.tx.getFieldArray(sfAuthorizeCredentials)); + STArray sortedLE(sfAuthorizeCredentials, sortedTX.size()); + for (auto const& p : sortedTX) + { + auto cred = STObject::makeInnerObject(sfCredential); + cred.setAccountID(sfIssuer, p.first); + cred.setFieldVL(sfCredentialType, p.second); + sortedLE.push_back(std::move(cred)); + } + + Keylet const preauthKey = keylet::depositPreauth(account_, sortedTX); + auto slePreauth = std::make_shared(preauthKey); + if (!slePreauth) + return tefINTERNAL; + + slePreauth->setAccountID(sfAccount, account_); + slePreauth->peekFieldArray(sfAuthorizeCredentials) = + std::move(sortedLE); + + view().insert(slePreauth); + + auto const page = view().dirInsert( + keylet::ownerDir(account_), preauthKey, describeOwnerDir(account_)); + + JLOG(j_.trace()) << "Adding DepositPreauth to owner directory " + << to_string(preauthKey.key) << ": " + << (page ? "success" : "failure"); + + if (!page) + return tecDIR_FULL; + + slePreauth->setFieldU64(sfOwnerNode, *page); + + // If we succeeded, the new entry counts against the creator's reserve. + adjustOwnerCount(view(), sleOwner, 1, j_); + } + else if (ctx_.tx.isFieldPresent(sfUnauthorizeCredentials)) + { + auto const preauthKey = keylet::depositPreauth( + account_, + credentials::makeSorted( + ctx_.tx.getFieldArray(sfUnauthorizeCredentials))); + return DepositPreauth::removeFromLedger(view(), preauthKey.key, j_); } + return tesSUCCESS; } TER DepositPreauth::removeFromLedger( - Application& app, ApplyView& view, uint256 const& preauthIndex, beast::Journal j) { - // Verify that the Preauth entry they asked to remove is - // in the ledger. - std::shared_ptr const slePreauth{ - view.peek(keylet::depositPreauth(preauthIndex))}; + // Existence already checked in preclaim and DeleteAccount + auto const slePreauth{view.peek(keylet::depositPreauth(preauthIndex))}; if (!slePreauth) { JLOG(j.warn()) << "Selected DepositPreauth does not exist."; @@ -192,7 +344,7 @@ DepositPreauth::removeFromLedger( if (!sleOwner) return tefINTERNAL; - adjustOwnerCount(view, sleOwner, -1, app.journal("View")); + adjustOwnerCount(view, sleOwner, -1, j); // Remove DepositPreauth from ledger. view.erase(slePreauth); diff --git a/src/xrpld/app/tx/detail/DepositPreauth.h b/src/xrpld/app/tx/detail/DepositPreauth.h index 5edcee104d0..76a7c080737 100644 --- a/src/xrpld/app/tx/detail/DepositPreauth.h +++ b/src/xrpld/app/tx/detail/DepositPreauth.h @@ -45,7 +45,6 @@ class DepositPreauth : public Transactor // Interface used by DeleteAccount static TER removeFromLedger( - Application& app, ApplyView& view, uint256 const& delIndex, beast::Journal j); diff --git a/src/xrpld/app/tx/detail/Escrow.cpp b/src/xrpld/app/tx/detail/Escrow.cpp index e34b675998d..f98e72f23dd 100644 --- a/src/xrpld/app/tx/detail/Escrow.cpp +++ b/src/xrpld/app/tx/detail/Escrow.cpp @@ -19,6 +19,7 @@ #include +#include #include #include #include @@ -309,6 +310,10 @@ EscrowFinish::preflight(PreflightContext const& ctx) if (ctx.rules.enabled(fix1543) && ctx.tx.getFlags() & tfUniversalMask) return temINVALID_FLAG; + if (ctx.tx.isFieldPresent(sfCredentialIDs) && + !ctx.rules.enabled(featureCredentials)) + return temDISABLED; + if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) return ret; @@ -347,6 +352,9 @@ EscrowFinish::preflight(PreflightContext const& ctx) } } + if (auto const err = credentials::checkFields(ctx); !isTesSuccess(err)) + return err; + return tesSUCCESS; } @@ -363,6 +371,19 @@ EscrowFinish::calculateBaseFee(ReadView const& view, STTx const& tx) return Transactor::calculateBaseFee(view, tx) + extraFee; } +TER +EscrowFinish::preclaim(PreclaimContext const& ctx) +{ + if (!ctx.view.rules().enabled(featureCredentials)) + return Transactor::preclaim(ctx); + + if (auto const err = credentials::valid(ctx, ctx.tx[sfAccount]); + !isTesSuccess(err)) + return err; + + return tesSUCCESS; +} + TER EscrowFinish::doApply() { @@ -456,19 +477,9 @@ EscrowFinish::doApply() if (ctx_.view().rules().enabled(featureDepositAuth)) { - // Is EscrowFinished authorized? - if (sled->getFlags() & lsfDepositAuth) - { - // A destination account that requires authorization has two - // ways to get an EscrowFinished into the account: - // 1. If Account == Destination, or - // 2. If Account is deposit preauthorized by destination. - if (account_ != destID) - { - if (!view().exists(keylet::depositPreauth(destID, account_))) - return tecNO_PERMISSION; - } - } + if (auto err = verifyDepositPreauth(ctx_, account_, destID, sled); + !isTesSuccess(err)) + return err; } AccountID const account = (*slep)[sfAccount]; diff --git a/src/xrpld/app/tx/detail/Escrow.h b/src/xrpld/app/tx/detail/Escrow.h index 9e30da76175..78acdbee00c 100644 --- a/src/xrpld/app/tx/detail/Escrow.h +++ b/src/xrpld/app/tx/detail/Escrow.h @@ -63,6 +63,9 @@ class EscrowFinish : public Transactor static XRPAmount calculateBaseFee(ReadView const& view, STTx const& tx); + static TER + preclaim(PreclaimContext const& ctx); + TER doApply() override; }; diff --git a/src/xrpld/app/tx/detail/InvariantCheck.cpp b/src/xrpld/app/tx/detail/InvariantCheck.cpp index d1eaf86844d..90fc399b344 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.cpp +++ b/src/xrpld/app/tx/detail/InvariantCheck.cpp @@ -481,6 +481,7 @@ LedgerEntryTypesMatch::visitEntry( case ltORACLE: case ltMPTOKEN_ISSUANCE: case ltMPTOKEN: + case ltCREDENTIAL: break; default: invalidTypeAdded_ = true; diff --git a/src/xrpld/app/tx/detail/PayChan.cpp b/src/xrpld/app/tx/detail/PayChan.cpp index d17736c4738..b2d4c0c9449 100644 --- a/src/xrpld/app/tx/detail/PayChan.cpp +++ b/src/xrpld/app/tx/detail/PayChan.cpp @@ -17,6 +17,7 @@ */ //============================================================================== +#include #include #include #include @@ -403,6 +404,10 @@ PayChanFund::doApply() NotTEC PayChanClaim::preflight(PreflightContext const& ctx) { + if (ctx.tx.isFieldPresent(sfCredentialIDs) && + !ctx.rules.enabled(featureCredentials)) + return temDISABLED; + if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) return ret; @@ -453,9 +458,25 @@ PayChanClaim::preflight(PreflightContext const& ctx) return temBAD_SIGNATURE; } + if (auto const err = credentials::checkFields(ctx); !isTesSuccess(err)) + return err; + return preflight2(ctx); } +TER +PayChanClaim::preclaim(PreclaimContext const& ctx) +{ + if (!ctx.view.rules().enabled(featureCredentials)) + return Transactor::preclaim(ctx); + + if (auto const err = credentials::valid(ctx, ctx.tx[sfAccount]); + !isTesSuccess(err)) + return err; + + return tesSUCCESS; +} + TER PayChanClaim::doApply() { @@ -516,18 +537,11 @@ PayChanClaim::doApply() (txAccount == src && (sled->getFlags() & lsfDisallowXRP))) return tecNO_TARGET; - // Check whether the destination account requires deposit authorization. - if (depositAuth && (sled->getFlags() & lsfDepositAuth)) + if (depositAuth) { - // A destination account that requires authorization has two - // ways to get a Payment Channel Claim into the account: - // 1. If Account == Destination, or - // 2. If Account is deposit preauthorized by destination. - if (txAccount != dst) - { - if (!view().exists(keylet::depositPreauth(dst, txAccount))) - return tecNO_PERMISSION; - } + if (auto err = verifyDepositPreauth(ctx_, txAccount, dst, sled); + !isTesSuccess(err)) + return err; } (*slep)[sfBalance] = ctx_.tx[sfBalance]; diff --git a/src/xrpld/app/tx/detail/PayChan.h b/src/xrpld/app/tx/detail/PayChan.h index 5eef7e51c0c..2e09c473dc0 100644 --- a/src/xrpld/app/tx/detail/PayChan.h +++ b/src/xrpld/app/tx/detail/PayChan.h @@ -85,6 +85,9 @@ class PayChanClaim : public Transactor static NotTEC preflight(PreflightContext const& ctx); + static TER + preclaim(PreclaimContext const& ctx); + TER doApply() override; }; diff --git a/src/xrpld/app/tx/detail/Payment.cpp b/src/xrpld/app/tx/detail/Payment.cpp index 77c8d015d1e..2ea13ffabc8 100644 --- a/src/xrpld/app/tx/detail/Payment.cpp +++ b/src/xrpld/app/tx/detail/Payment.cpp @@ -17,6 +17,7 @@ */ //============================================================================== +#include #include #include #include @@ -65,6 +66,10 @@ getMaxSourceAmount( NotTEC Payment::preflight(PreflightContext const& ctx) { + if (ctx.tx.isFieldPresent(sfCredentialIDs) && + !ctx.rules.enabled(featureCredentials)) + return temDISABLED; + if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) return ret; @@ -227,6 +232,9 @@ Payment::preflight(PreflightContext const& ctx) } } + if (auto const err = credentials::checkFields(ctx); !isTesSuccess(err)) + return err; + return preflight2(ctx); } @@ -311,6 +319,10 @@ Payment::preclaim(PreclaimContext const& ctx) } } + if (auto const err = credentials::valid(ctx, ctx.tx[sfAccount]); + !isTesSuccess(err)) + return err; + return tesSUCCESS; } @@ -362,8 +374,9 @@ Payment::doApply() } // Determine whether the destination requires deposit authorization. - bool const reqDepositAuth = sleDst->getFlags() & lsfDepositAuth && - view().rules().enabled(featureDepositAuth); + bool const depositAuth = view().rules().enabled(featureDepositAuth); + bool const reqDepositAuth = + sleDst->getFlags() & lsfDepositAuth && depositAuth; bool const depositPreauth = view().rules().enabled(featureDepositPreauth); @@ -380,18 +393,17 @@ Payment::doApply() // Ripple payment with at least one intermediate step and uses // transitive balances. - if (depositPreauth && reqDepositAuth) + if (depositPreauth && depositAuth) { // If depositPreauth is enabled, then an account that requires // authorization has two ways to get an IOU Payment in: // 1. If Account == Destination, or // 2. If Account is deposit preauthorized by destination. - if (dstAccountID != account_) - { - if (!view().exists( - keylet::depositPreauth(dstAccountID, account_))) - return tecNO_PERMISSION; - } + + if (auto err = + verifyDepositPreauth(ctx_, account_, dstAccountID, sleDst); + !isTesSuccess(err)) + return err; } path::RippleCalc::Input rcInput; @@ -458,6 +470,11 @@ Payment::doApply() ter != tesSUCCESS) return ter; + if (auto err = + verifyDepositPreauth(ctx_, account_, dstAccountID, sleDst); + !isTesSuccess(err)) + return err; + auto const& issuer = mptIssue.getIssuer(); // Transfer rate @@ -547,7 +564,7 @@ Payment::doApply() // The source account does have enough money. Make sure the // source account has authority to deposit to the destination. - if (reqDepositAuth) + if (depositAuth) { // If depositPreauth is enabled, then an account that requires // authorization has three ways to get an XRP Payment in: @@ -567,17 +584,17 @@ Payment::doApply() // We choose the base reserve as our bound because it is // a small number that seldom changes but is always sufficient // to get the account un-wedged. - if (dstAccountID != account_) + + // Get the base reserve. + XRPAmount const dstReserve{view().fees().accountReserve(0)}; + + if (dstAmount > dstReserve || + sleDst->getFieldAmount(sfBalance) > dstReserve) { - if (!view().exists(keylet::depositPreauth(dstAccountID, account_))) - { - // Get the base reserve. - XRPAmount const dstReserve{view().fees().accountReserve(0)}; - - if (dstAmount > dstReserve || - sleDst->getFieldAmount(sfBalance) > dstReserve) - return tecNO_PERMISSION; - } + if (auto err = + verifyDepositPreauth(ctx_, account_, dstAccountID, sleDst); + !isTesSuccess(err)) + return err; } } diff --git a/src/xrpld/app/tx/detail/Transactor.cpp b/src/xrpld/app/tx/detail/Transactor.cpp index 7ea024ee6dc..052a735a2fd 100644 --- a/src/xrpld/app/tx/detail/Transactor.cpp +++ b/src/xrpld/app/tx/detail/Transactor.cpp @@ -18,6 +18,7 @@ //============================================================================== #include +#include #include #include #include @@ -226,9 +227,9 @@ Transactor::checkFee(PreclaimContext const& ctx, XRPAmount baseFee) if (balance < feePaid) { - JLOG(ctx.j.trace()) - << "Insufficient balance:" << " balance=" << to_string(balance) - << " paid=" << to_string(feePaid); + JLOG(ctx.j.trace()) << "Insufficient balance:" + << " balance=" << to_string(balance) + << " paid=" << to_string(feePaid); if ((balance > beast::zero) && !ctx.view.open()) { @@ -760,6 +761,19 @@ removeExpiredNFTokenOffers( } } +static void +removeExpiredCredentials( + ApplyView& view, + std::vector const& creds, + beast::Journal viewJ) +{ + for (auto const& index : creds) + { + if (auto const sle = view.peek(keylet::credential(index))) + credentials::deleteSLE(view, sle, viewJ); + } +} + static void removeDeletedTrustLines( ApplyView& view, @@ -907,19 +921,23 @@ Transactor::operator()() std::vector removedOffers; std::vector removedTrustLines; std::vector expiredNFTokenOffers; + std::vector expiredCredentials; bool const doOffers = ((result == tecOVERSIZE) || (result == tecKILLED)); bool const doLines = (result == tecINCOMPLETE); bool const doNFTokenOffers = (result == tecEXPIRED); - if (doOffers || doLines || doNFTokenOffers) + bool const doCredentials = (result == tecEXPIRED); + if (doOffers || doLines || doNFTokenOffers || doCredentials) { - ctx_.visit([&doOffers, + ctx_.visit([doOffers, &removedOffers, - &doLines, + doLines, &removedTrustLines, - &doNFTokenOffers, - &expiredNFTokenOffers]( + doNFTokenOffers, + &expiredNFTokenOffers, + doCredentials, + &expiredCredentials]( uint256 const& index, bool isDelete, std::shared_ptr const& before, @@ -946,6 +964,10 @@ Transactor::operator()() if (doNFTokenOffers && before && after && (before->getType() == ltNFTOKEN_OFFER)) expiredNFTokenOffers.push_back(index); + + if (doCredentials && before && after && + (before->getType() == ltCREDENTIAL)) + expiredCredentials.push_back(index); } }); } @@ -972,6 +994,10 @@ Transactor::operator()() removeDeletedTrustLines( view(), removedTrustLines, ctx_.app.journal("View")); + if (result == tecEXPIRED) + removeExpiredCredentials( + view(), expiredCredentials, ctx_.app.journal("View")); + applied = isTecClaim(result); } diff --git a/src/xrpld/app/tx/detail/applySteps.cpp b/src/xrpld/app/tx/detail/applySteps.cpp index 44c25cb22ef..b3c711084dc 100644 --- a/src/xrpld/app/tx/detail/applySteps.cpp +++ b/src/xrpld/app/tx/detail/applySteps.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff --git a/src/xrpld/net/detail/RPCCall.cpp b/src/xrpld/net/detail/RPCCall.cpp index c0d2e205434..b92f4b1a205 100644 --- a/src/xrpld/net/detail/RPCCall.cpp +++ b/src/xrpld/net/detail/RPCCall.cpp @@ -416,7 +416,8 @@ class RPCParser return jvRequest; } - // deposit_authorized [] + // deposit_authorized + // [ [, ...]] Json::Value parseDepositAuthorized(Json::Value const& jvParams) { @@ -424,9 +425,17 @@ class RPCParser jvRequest[jss::source_account] = jvParams[0u].asString(); jvRequest[jss::destination_account] = jvParams[1u].asString(); - if (jvParams.size() == 3) + if (jvParams.size() >= 3) jvParseLedger(jvRequest, jvParams[2u].asString()); + // 8 credentials max + if ((jvParams.size() >= 4) && (jvParams.size() <= 11)) + { + jvRequest[jss::credentials] = Json::Value(Json::arrayValue); + for (uint32_t i = 3; i < jvParams.size(); ++i) + jvRequest[jss::credentials].append(jvParams[i].asString()); + } + return jvRequest; } @@ -1161,7 +1170,7 @@ class RPCParser {"channel_verify", &RPCParser::parseChannelVerify, 4, 4}, {"connect", &RPCParser::parseConnect, 1, 2}, {"consensus_info", &RPCParser::parseAsIs, 0, 0}, - {"deposit_authorized", &RPCParser::parseDepositAuthorized, 2, 3}, + {"deposit_authorized", &RPCParser::parseDepositAuthorized, 2, 11}, {"feature", &RPCParser::parseFeature, 0, 2}, {"fetch_info", &RPCParser::parseFetchInfo, 0, 1}, {"gateway_balances", &RPCParser::parseGatewayBalances, 1, -1}, diff --git a/src/xrpld/rpc/detail/RPCHelpers.cpp b/src/xrpld/rpc/detail/RPCHelpers.cpp index 0e9481bf540..af204eaedf7 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.cpp +++ b/src/xrpld/rpc/detail/RPCHelpers.cpp @@ -33,7 +33,9 @@ #include #include #include + #include + #include namespace ripple { @@ -929,13 +931,14 @@ chooseLedgerEntryType(Json::Value const& params) std::pair result{RPC::Status::OK, ltANY}; if (params.isMember(jss::type)) { - static constexpr std::array, 24> + static constexpr std::array, 25> types{ {{jss::account, ltACCOUNT_ROOT}, {jss::amendments, ltAMENDMENTS}, {jss::amm, ltAMM}, {jss::bridge, ltBRIDGE}, {jss::check, ltCHECK}, + {jss::credential, ltCREDENTIAL}, {jss::deposit_preauth, ltDEPOSIT_PREAUTH}, {jss::did, ltDID}, {jss::directory, ltDIR_NODE}, diff --git a/src/xrpld/rpc/handlers/DepositAuthorized.cpp b/src/xrpld/rpc/handlers/DepositAuthorized.cpp index 0efa584625b..50aa9ef2898 100644 --- a/src/xrpld/rpc/handlers/DepositAuthorized.cpp +++ b/src/xrpld/rpc/handlers/DepositAuthorized.cpp @@ -17,6 +17,7 @@ */ //============================================================================== +#include #include #include #include @@ -32,6 +33,7 @@ namespace ripple { // destination_account : // ledger_hash : // ledger_index : +// credentials : [,...] // } Json::Value @@ -88,23 +90,111 @@ doDepositAuthorized(RPC::JsonContext& context) return result; } - // If the two accounts are the same, then the deposit should be fine. - bool depositAuthorized{true}; - if (srcAcct != dstAcct) + bool const reqAuth = + (sleDest->getFlags() & lsfDepositAuth) && (srcAcct != dstAcct); + bool const credentialsPresent = params.isMember(jss::credentials); + + std::set> sorted; + std::vector> lifeExtender; + if (credentialsPresent) { - // Check destination for the DepositAuth flag. If that flag is - // not set then a deposit should be just fine. - if (sleDest->getFlags() & lsfDepositAuth) + auto const& creds(params[jss::credentials]); + if (!creds.isArray() || !creds) + { + return RPC::make_error( + rpcINVALID_PARAMS, + RPC::expected_field_message( + jss::credentials, + "is non-empty array of CredentialID(hash256)")); + } + else if (creds.size() > maxCredentialsArraySize) + { + return RPC::make_error( + rpcINVALID_PARAMS, + RPC::expected_field_message( + jss::credentials, "array too long")); + } + + lifeExtender.reserve(creds.size()); + for (auto const& jo : creds) { - // See if a preauthorization entry is in the ledger. - auto const sleDepositAuth = - ledger->read(keylet::depositPreauth(dstAcct, srcAcct)); - depositAuthorized = static_cast(sleDepositAuth); + if (!jo.isString()) + { + return RPC::make_error( + rpcINVALID_PARAMS, + RPC::expected_field_message( + jss::credentials, "an array of CredentialID(hash256)")); + } + + uint256 credH; + auto const credS = jo.asString(); + if (!credH.parseHex(credS)) + { + return RPC::make_error( + rpcINVALID_PARAMS, + RPC::expected_field_message( + jss::credentials, "an array of CredentialID(hash256)")); + } + + std::shared_ptr sleCred = + ledger->read(keylet::credential(credH)); + if (!sleCred) + { + RPC::inject_error( + rpcBAD_CREDENTIALS, "credentials don't exist", result); + return result; + } + + if (!(sleCred->getFlags() & lsfAccepted)) + { + RPC::inject_error( + rpcBAD_CREDENTIALS, "credentials aren't accepted", result); + return result; + } + + if (credentials::checkExpired( + sleCred, ledger->info().parentCloseTime)) + { + RPC::inject_error( + rpcBAD_CREDENTIALS, "credentials are expired", result); + return result; + } + + if ((*sleCred)[sfSubject] != srcAcct) + { + RPC::inject_error( + rpcBAD_CREDENTIALS, + "credentials doesn't belong to the root account", + result); + return result; + } + + auto [it, ins] = sorted.emplace( + (*sleCred)[sfIssuer], (*sleCred)[sfCredentialType]); + if (!ins) + { + RPC::inject_error( + rpcBAD_CREDENTIALS, "duplicates in credentials", result); + return result; + } + lifeExtender.push_back(std::move(sleCred)); } } + + // If the two accounts are the same OR if that flag is + // not set, then the deposit should be fine. + bool depositAuthorized = true; + if (reqAuth) + depositAuthorized = + ledger->exists(keylet::depositPreauth(dstAcct, srcAcct)) || + (credentialsPresent && + ledger->exists(keylet::depositPreauth(dstAcct, sorted))); + result[jss::source_account] = params[jss::source_account].asString(); result[jss::destination_account] = params[jss::destination_account].asString(); + if (credentialsPresent) + result[jss::credentials] = params[jss::credentials]; result[jss::deposit_authorized] = depositAuthorized; return result; diff --git a/src/xrpld/rpc/handlers/LedgerEntry.cpp b/src/xrpld/rpc/handlers/LedgerEntry.cpp index b8937c528eb..6a3b7a48686 100644 --- a/src/xrpld/rpc/handlers/LedgerEntry.cpp +++ b/src/xrpld/rpc/handlers/LedgerEntry.cpp @@ -18,6 +18,7 @@ //============================================================================== #include +#include #include #include #include @@ -34,6 +35,31 @@ namespace ripple { +static STArray +parseAuthorizeCredentials(Json::Value const& jv) +{ + STArray arr(sfAuthorizeCredentials, jv.size()); + for (auto const& jo : jv) + { + auto const issuer = parseBase58(jo[jss::issuer].asString()); + if (!issuer || !*issuer) + return {}; + + auto const credentialType = + strUnHex(jo[jss::credential_type].asString()); + if (!credentialType || credentialType->empty() || + credentialType->size() > maxCredentialTypeLength) + return {}; + + auto credential = STObject::makeInnerObject(sfCredential); + credential.setAccountID(sfIssuer, *issuer); + credential.setFieldVL(sfCredentialType, *credentialType); + arr.push_back(std::move(credential)); + } + + return arr; +} + // { // ledger_hash : // ledger_index : @@ -84,44 +110,63 @@ doLedgerEntry(RPC::JsonContext& context) else if (context.params.isMember(jss::deposit_preauth)) { expectedType = ltDEPOSIT_PREAUTH; + auto const& dp = context.params[jss::deposit_preauth]; - if (!context.params[jss::deposit_preauth].isObject()) + if (!dp.isObject()) { - if (!context.params[jss::deposit_preauth].isString() || - !uNodeIndex.parseHex( - context.params[jss::deposit_preauth].asString())) + if (!dp.isString() || !uNodeIndex.parseHex(dp.asString())) { uNodeIndex = beast::zero; jvResult[jss::error] = "malformedRequest"; } } + // clang-format off else if ( - !context.params[jss::deposit_preauth].isMember(jss::owner) || - !context.params[jss::deposit_preauth][jss::owner].isString() || - !context.params[jss::deposit_preauth].isMember( - jss::authorized) || - !context.params[jss::deposit_preauth][jss::authorized] - .isString()) + (!dp.isMember(jss::owner) || !dp[jss::owner].isString()) || + (dp.isMember(jss::authorized) == dp.isMember(jss::authorized_credentials)) || + (dp.isMember(jss::authorized) && !dp[jss::authorized].isString()) || + (dp.isMember(jss::authorized_credentials) && !dp[jss::authorized_credentials].isArray()) + ) + // clang-format on { jvResult[jss::error] = "malformedRequest"; } else { - auto const owner = parseBase58( - context.params[jss::deposit_preauth][jss::owner] - .asString()); - - auto const authorized = parseBase58( - context.params[jss::deposit_preauth][jss::authorized] - .asString()); - + auto const owner = + parseBase58(dp[jss::owner].asString()); if (!owner) + { jvResult[jss::error] = "malformedOwner"; - else if (!authorized) - jvResult[jss::error] = "malformedAuthorized"; + } + else if (dp.isMember(jss::authorized)) + { + auto const authorized = + parseBase58(dp[jss::authorized].asString()); + if (!authorized) + jvResult[jss::error] = "malformedAuthorized"; + else + uNodeIndex = + keylet::depositPreauth(*owner, *authorized).key; + } else - uNodeIndex = - keylet::depositPreauth(*owner, *authorized).key; + { + auto const& ac(dp[jss::authorized_credentials]); + STArray const arr = parseAuthorizeCredentials(ac); + + if (arr.empty() || (arr.size() > maxCredentialsArraySize)) + jvResult[jss::error] = "malformedAuthorizedCredentials"; + else + { + auto sorted = credentials::makeSorted(arr); + if (sorted.empty()) + jvResult[jss::error] = + "malformedAuthorizedCredentials"; + else + uNodeIndex = + keylet::depositPreauth(*owner, sorted).key; + } + } } } else if (context.params.isMember(jss::directory)) @@ -644,6 +689,52 @@ doLedgerEntry(RPC::JsonContext& context) uNodeIndex = keylet::oracle(*account, *documentID).key; } } + else if (context.params.isMember(jss::credential)) + { + expectedType = ltCREDENTIAL; + auto const& cred = context.params[jss::credential]; + + if (cred.isString()) + { + if (!uNodeIndex.parseHex(cred.asString())) + { + uNodeIndex = beast::zero; + jvResult[jss::error] = "malformedRequest"; + } + } + else if ( + (!cred.isMember(jss::subject) || + !cred[jss::subject].isString()) || + (!cred.isMember(jss::issuer) || + !cred[jss::issuer].isString()) || + (!cred.isMember(jss::credential_type) || + !cred[jss::credential_type].isString())) + { + jvResult[jss::error] = "malformedRequest"; + } + else + { + auto const subject = + parseBase58(cred[jss::subject].asString()); + auto const issuer = + parseBase58(cred[jss::issuer].asString()); + auto const credType = + strUnHex(cred[jss::credential_type].asString()); + if (!subject || subject->isZero() || !issuer || + issuer->isZero() || !credType || credType->empty()) + { + jvResult[jss::error] = "malformedRequest"; + } + else + { + uNodeIndex = keylet::credential( + *subject, + *issuer, + Slice(credType->data(), credType->size())) + .key; + } + } + } else if (context.params.isMember(jss::mpt_issuance)) { expectedType = ltMPTOKEN_ISSUANCE; From 9e48fc0c834e8a6e340c521e9ec58b97b944c1fd Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Wed, 6 Nov 2024 22:22:42 +0000 Subject: [PATCH 73/82] Fix potential deadlock (#5124) * 2.2.2 changed functions acquireAsync and NetworkOPsImp::recvValidation to add an item to a collection under lock, unlock, do some work, then lock again to do remove the item. It will deadlock if an exception is thrown while adding the item - before unlocking. * Replace ScopedUnlock with scope_unlock. --- include/xrpl/basics/scope.h | 65 ++++++++++++++ .../app/ledger/detail/InboundLedgers.cpp | 5 +- src/xrpld/app/ledger/detail/LedgerMaster.cpp | 90 ++----------------- src/xrpld/app/misc/NetworkOPs.cpp | 6 +- 4 files changed, 77 insertions(+), 89 deletions(-) diff --git a/include/xrpl/basics/scope.h b/include/xrpl/basics/scope.h index 54c05998fa4..b1d13eae8ce 100644 --- a/include/xrpl/basics/scope.h +++ b/include/xrpl/basics/scope.h @@ -21,6 +21,7 @@ #define RIPPLE_BASICS_SCOPE_H_INCLUDED #include +#include #include #include @@ -186,6 +187,70 @@ class scope_success template scope_success(EF) -> scope_success; +/** + Automatically unlocks and re-locks a unique_lock object. + + This is the reverse of a std::unique_lock object - instead of locking the + mutex for the lifetime of this object, it unlocks it. + + Make sure you don't try to unlock mutexes that aren't actually locked! + + This is essentially a less-versatile boost::reverse_lock. + + e.g. @code + + std::mutex mut; + + for (;;) + { + std::unique_lock myScopedLock{mut}; + // mut is now locked + + ... do some stuff with it locked .. + + while (xyz) + { + ... do some stuff with it locked .. + + scope_unlock unlocker{myScopedLock}; + + // mut is now unlocked for the remainder of this block, + // and re-locked at the end. + + ...do some stuff with it unlocked ... + } // mut gets locked here. + + } // mut gets unlocked here + @endcode +*/ + +template +class scope_unlock +{ + std::unique_lock* plock; + +public: + explicit scope_unlock(std::unique_lock& lock) noexcept(true) + : plock(&lock) + { + assert(plock->owns_lock()); + plock->unlock(); + } + + // Immovable type + scope_unlock(scope_unlock const&) = delete; + scope_unlock& + operator=(scope_unlock const&) = delete; + + ~scope_unlock() noexcept(true) + { + plock->lock(); + } +}; + +template +scope_unlock(std::unique_lock&) -> scope_unlock; + } // namespace ripple #endif diff --git a/src/xrpld/app/ledger/detail/InboundLedgers.cpp b/src/xrpld/app/ledger/detail/InboundLedgers.cpp index 72eb9e27189..f6d86a4d737 100644 --- a/src/xrpld/app/ledger/detail/InboundLedgers.cpp +++ b/src/xrpld/app/ledger/detail/InboundLedgers.cpp @@ -25,9 +25,11 @@ #include #include #include +#include #include #include #include + #include #include #include @@ -139,7 +141,7 @@ class InboundLedgersImp : public InboundLedgers if (pendingAcquires_.contains(hash)) return; pendingAcquires_.insert(hash); - lock.unlock(); + scope_unlock unlock(lock); acquire(hash, seq, reason); } catch (std::exception const& e) @@ -154,7 +156,6 @@ class InboundLedgersImp : public InboundLedgers << "Unknown exception thrown for acquiring new inbound ledger " << hash; } - lock.lock(); pendingAcquires_.erase(hash); } diff --git a/src/xrpld/app/ledger/detail/LedgerMaster.cpp b/src/xrpld/app/ledger/detail/LedgerMaster.cpp index d1eeabeb619..53edef17d33 100644 --- a/src/xrpld/app/ledger/detail/LedgerMaster.cpp +++ b/src/xrpld/app/ledger/detail/LedgerMaster.cpp @@ -46,10 +46,12 @@ #include #include #include +#include #include #include #include #include + #include #include #include @@ -60,86 +62,6 @@ namespace ripple { -namespace { - -//============================================================================== -/** - Automatically unlocks and re-locks a unique_lock object. - - This is the reverse of a std::unique_lock object - instead of locking the - mutex for the lifetime of this object, it unlocks it. - - Make sure you don't try to unlock mutexes that aren't actually locked! - - This is essentially a less-versatile boost::reverse_lock. - - e.g. @code - - std::mutex mut; - - for (;;) - { - std::unique_lock myScopedLock{mut}; - // mut is now locked - - ... do some stuff with it locked .. - - while (xyz) - { - ... do some stuff with it locked .. - - ScopedUnlock unlocker{myScopedLock}; - - // mut is now unlocked for the remainder of this block, - // and re-locked at the end. - - ...do some stuff with it unlocked ... - } // mut gets locked here. - - } // mut gets unlocked here - @endcode -*/ -template -class ScopedUnlock -{ - std::unique_lock& lock_; - -public: - /** Creates a ScopedUnlock. - - As soon as it is created, this will unlock the unique_lock, and - when the ScopedLock object is deleted, the unique_lock will - be re-locked. - - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! Best just to use it - as a local stack object, rather than creating on the heap. - */ - explicit ScopedUnlock(std::unique_lock& lock) : lock_(lock) - { - assert(lock_.owns_lock()); - lock_.unlock(); - } - - ScopedUnlock(ScopedUnlock const&) = delete; - ScopedUnlock& - operator=(ScopedUnlock const&) = delete; - - /** Destructor. - - The unique_lock will be locked after the destructor is called. - - Make sure this object is created and deleted by the same thread, - otherwise there are no guarantees what will happen! - */ - ~ScopedUnlock() noexcept(false) - { - lock_.lock(); - } -}; - -} // namespace - // Don't catch up more than 100 ledgers (cannot exceed 256) static constexpr int MAX_LEDGER_GAP{100}; @@ -1336,7 +1258,7 @@ LedgerMaster::findNewLedgersToPublish( auto valLedger = mValidLedger.get(); std::uint32_t valSeq = valLedger->info().seq; - ScopedUnlock sul{sl}; + scope_unlock sul{sl}; try { for (std::uint32_t seq = pubSeq; seq <= valSeq; ++seq) @@ -1882,7 +1804,7 @@ LedgerMaster::fetchForHistory( InboundLedger::Reason reason, std::unique_lock& sl) { - ScopedUnlock sul{sl}; + scope_unlock sul{sl}; if (auto hash = getLedgerHashForHistory(missing, reason)) { assert(hash->isNonZero()); @@ -2052,7 +1974,7 @@ LedgerMaster::doAdvance(std::unique_lock& sl) for (auto const& ledger : pubLedgers) { { - ScopedUnlock sul{sl}; + scope_unlock sul{sl}; JLOG(m_journal.debug()) << "tryAdvance publishing seq " << ledger->info().seq; setFullLedger(ledger, true, true); @@ -2061,7 +1983,7 @@ LedgerMaster::doAdvance(std::unique_lock& sl) setPubLedger(ledger); { - ScopedUnlock sul{sl}; + scope_unlock sul{sl}; app_.getOPs().pubLedger(ledger); } } diff --git a/src/xrpld/app/misc/NetworkOPs.cpp b/src/xrpld/app/misc/NetworkOPs.cpp index 46a7dfcaacd..d647df91f1e 100644 --- a/src/xrpld/app/misc/NetworkOPs.cpp +++ b/src/xrpld/app/misc/NetworkOPs.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -2310,7 +2311,7 @@ NetworkOPsImp::recvValidation( bypassAccept = BypassAccept::yes; else pendingValidations_.insert(val->getLedgerHash()); - lock.unlock(); + scope_unlock unlock(lock); handleNewValidation(app_, val, source, bypassAccept, m_journal); } catch (std::exception const& e) @@ -2327,10 +2328,9 @@ NetworkOPsImp::recvValidation( } if (bypassAccept == BypassAccept::no) { - lock.lock(); pendingValidations_.erase(val->getLedgerHash()); - lock.unlock(); } + lock.unlock(); pubValidation(val); From 7b18006193c261fefda45e1ef05ac1c48375047c Mon Sep 17 00:00:00 2001 From: Shawn Xie <35279399+shawnxie999@users.noreply.github.com> Date: Wed, 6 Nov 2024 17:33:16 -0500 Subject: [PATCH 74/82] Replace Uint192 with Hash192 in server_definitions response (#5177) --- src/test/rpc/ServerInfo_test.cpp | 9 +++++++++ src/xrpld/rpc/handlers/ServerInfo.cpp | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/test/rpc/ServerInfo_test.cpp b/src/test/rpc/ServerInfo_test.cpp index a2eaa63eb42..fbeb4220d16 100644 --- a/src/test/rpc/ServerInfo_test.cpp +++ b/src/test/rpc/ServerInfo_test.cpp @@ -197,6 +197,15 @@ admin = 127.0.0.1 .asUInt() == 0); BEAST_EXPECT( result[jss::result][jss::TYPES]["AccountID"].asUInt() == 8); + + // test that base_uint types are replaced with "Hash" prefix + { + auto const types = result[jss::result][jss::TYPES]; + BEAST_EXPECT(types["Hash128"].asUInt() == 4); + BEAST_EXPECT(types["Hash160"].asUInt() == 17); + BEAST_EXPECT(types["Hash192"].asUInt() == 21); + BEAST_EXPECT(types["Hash256"].asUInt() == 5); + } } // test providing the same hash diff --git a/src/xrpld/rpc/handlers/ServerInfo.cpp b/src/xrpld/rpc/handlers/ServerInfo.cpp index 72beb37ed64..ea631491c65 100644 --- a/src/xrpld/rpc/handlers/ServerInfo.cpp +++ b/src/xrpld/rpc/handlers/ServerInfo.cpp @@ -80,7 +80,8 @@ ServerDefinitions::translate(std::string const& inp) if (contains("UINT")) { - if (contains("256") || contains("160") || contains("128")) + if (contains("256") || contains("192") || contains("160") || + contains("128")) return replace("UINT", "Hash"); else return replace("UINT", "UInt"); From 9d58f11a60881b3edb5de80cae52d8b758ae30a8 Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Wed, 6 Nov 2024 17:37:59 -0500 Subject: [PATCH 75/82] Set version to 2.3.0-rc1 --- src/libxrpl/protocol/BuildInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libxrpl/protocol/BuildInfo.cpp b/src/libxrpl/protocol/BuildInfo.cpp index 4c88a372ff3..833240f531d 100644 --- a/src/libxrpl/protocol/BuildInfo.cpp +++ b/src/libxrpl/protocol/BuildInfo.cpp @@ -33,7 +33,7 @@ namespace BuildInfo { // and follow the format described at http://semver.org/ //------------------------------------------------------------------------------ // clang-format off -char const* const versionString = "2.3.0-b4" +char const* const versionString = "2.3.0-rc1" // clang-format on #if defined(DEBUG) || defined(SANITIZER) From 2316d843d7f9bc6963b3519f4464913c27eb7335 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Tue, 12 Nov 2024 23:24:52 +0000 Subject: [PATCH 76/82] Fix ledger_entry crash on invalid credentials request (#5189) --- src/test/rpc/LedgerRPC_test.cpp | 135 ++++++++++++++++++++++++- src/xrpld/rpc/handlers/LedgerEntry.cpp | 6 ++ 2 files changed, 137 insertions(+), 4 deletions(-) diff --git a/src/test/rpc/LedgerRPC_test.cpp b/src/test/rpc/LedgerRPC_test.cpp index c5e10198c49..41657468666 100644 --- a/src/test/rpc/LedgerRPC_test.cpp +++ b/src/test/rpc/LedgerRPC_test.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -1207,6 +1208,42 @@ class LedgerRPC_test : public beast::unit_test::suite checkErrorValue(jrr[jss::result], "malformedRequest", ""); } + { + // Failed, authorized_credentials contains string data + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + arr.append("foobar"); + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); + } + + { + // Failed, authorized_credentials contains arrays + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + Json::Value payload = Json::arrayValue; + payload.append(42); + arr.append(std::move(payload)); + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); + } + { // Failed, authorized_credentials is empty array Json::Value jvParams; @@ -1263,6 +1300,27 @@ class LedgerRPC_test : public beast::unit_test::suite jrr[jss::result], "malformedAuthorizedCredentials", ""); } + { + // Failed, issuer is not set + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + + Json::Value jo; + jo[jss::credential_type] = strHex(std::string_view(credType)); + arr.append(std::move(jo)); + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); + } + { // Failed, issuer isn't string Json::Value jvParams; @@ -1285,6 +1343,30 @@ class LedgerRPC_test : public beast::unit_test::suite jrr[jss::result], "malformedAuthorizedCredentials", ""); } + { + // Failed, issuer is an array + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + + Json::Value jo; + Json::Value payload = Json::arrayValue; + payload.append(42); + jo[jss::issuer] = std::move(payload); + jo[jss::credential_type] = strHex(std::string_view(credType)); + arr.append(std::move(jo)); + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); + } + { // Failed, issuer isn't valid encoded account Json::Value jvParams; @@ -1307,12 +1389,32 @@ class LedgerRPC_test : public beast::unit_test::suite jrr[jss::result], "malformedAuthorizedCredentials", ""); } + { + // Failed, credential_type is not set + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + + Json::Value jo; + jo[jss::issuer] = issuer.human(); + arr.append(std::move(jo)); + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); + } + { // Failed, credential_type isn't string Json::Value jvParams; jvParams[jss::ledger_index] = jss::validated; jvParams[jss::deposit_preauth][jss::owner] = bob.human(); - jvParams[jss::deposit_preauth][jss::authorized] = alice.human(); jvParams[jss::deposit_preauth][jss::authorized_credentials] = Json::arrayValue; @@ -1326,7 +1428,32 @@ class LedgerRPC_test : public beast::unit_test::suite auto const jrr = env.rpc("json", "ledger_entry", to_string(jvParams)); - checkErrorValue(jrr[jss::result], "malformedRequest", ""); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); + } + + { + // Failed, credential_type is an array + Json::Value jvParams; + jvParams[jss::ledger_index] = jss::validated; + jvParams[jss::deposit_preauth][jss::owner] = bob.human(); + + jvParams[jss::deposit_preauth][jss::authorized_credentials] = + Json::arrayValue; + auto& arr( + jvParams[jss::deposit_preauth][jss::authorized_credentials]); + + Json::Value jo; + jo[jss::issuer] = issuer.human(); + Json::Value payload = Json::arrayValue; + payload.append(42); + jo[jss::credential_type] = std::move(payload); + arr.append(std::move(jo)); + + auto const jrr = + env.rpc("json", "ledger_entry", to_string(jvParams)); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); } { @@ -1334,7 +1461,6 @@ class LedgerRPC_test : public beast::unit_test::suite Json::Value jvParams; jvParams[jss::ledger_index] = jss::validated; jvParams[jss::deposit_preauth][jss::owner] = bob.human(); - jvParams[jss::deposit_preauth][jss::authorized] = alice.human(); jvParams[jss::deposit_preauth][jss::authorized_credentials] = Json::arrayValue; @@ -1348,7 +1474,8 @@ class LedgerRPC_test : public beast::unit_test::suite auto const jrr = env.rpc("json", "ledger_entry", to_string(jvParams)); - checkErrorValue(jrr[jss::result], "malformedRequest", ""); + checkErrorValue( + jrr[jss::result], "malformedAuthorizedCredentials", ""); } } diff --git a/src/xrpld/rpc/handlers/LedgerEntry.cpp b/src/xrpld/rpc/handlers/LedgerEntry.cpp index 6a3b7a48686..5d03bbb189d 100644 --- a/src/xrpld/rpc/handlers/LedgerEntry.cpp +++ b/src/xrpld/rpc/handlers/LedgerEntry.cpp @@ -41,6 +41,12 @@ parseAuthorizeCredentials(Json::Value const& jv) STArray arr(sfAuthorizeCredentials, jv.size()); for (auto const& jo : jv) { + if (!jo.isObject() || // + !jo.isMember(jss::issuer) || !jo[jss::issuer].isString() || + !jo.isMember(jss::credential_type) || + !jo[jss::credential_type].isString()) + return {}; + auto const issuer = parseBase58(jo[jss::issuer].asString()); if (!issuer || !*issuer) return {}; From 8186253707f2f60d1566878af5065799b6eb0ef8 Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Tue, 12 Nov 2024 18:37:15 -0500 Subject: [PATCH 77/82] fix: include `index` in `server_definitions` RPC (#5190) --- src/libxrpl/protocol/SField.cpp | 3 +++ src/test/rpc/ServerInfo_test.cpp | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/libxrpl/protocol/SField.cpp b/src/libxrpl/protocol/SField.cpp index 18226008504..537fa557fcc 100644 --- a/src/libxrpl/protocol/SField.cpp +++ b/src/libxrpl/protocol/SField.cpp @@ -72,7 +72,10 @@ TypedField::TypedField(private_access_tag_t pat, Args&&... args) // SFields which, for historical reasons, do not follow naming conventions. SField const sfInvalid(access, -1); SField const sfGeneric(access, 0); +// The following two fields aren't used anywhere, but they break tests/have +// downstream effects. SField const sfHash(access, STI_UINT256, 257, "hash"); +SField const sfIndex(access, STI_UINT256, 258, "index"); #include diff --git a/src/test/rpc/ServerInfo_test.cpp b/src/test/rpc/ServerInfo_test.cpp index fbeb4220d16..e6f889c5bdf 100644 --- a/src/test/rpc/ServerInfo_test.cpp +++ b/src/test/rpc/ServerInfo_test.cpp @@ -198,6 +198,28 @@ admin = 127.0.0.1 BEAST_EXPECT( result[jss::result][jss::TYPES]["AccountID"].asUInt() == 8); + // check exception SFields + { + auto const fieldExists = [&](std::string name) { + for (auto& field : result[jss::result][jss::FIELDS]) + { + if (field[0u].asString() == name) + { + return true; + } + } + return false; + }; + BEAST_EXPECT(fieldExists("Generic")); + BEAST_EXPECT(fieldExists("Invalid")); + BEAST_EXPECT(fieldExists("ObjectEndMarker")); + BEAST_EXPECT(fieldExists("ArrayEndMarker")); + BEAST_EXPECT(fieldExists("taker_gets_funded")); + BEAST_EXPECT(fieldExists("taker_pays_funded")); + BEAST_EXPECT(fieldExists("hash")); + BEAST_EXPECT(fieldExists("index")); + } + // test that base_uint types are replaced with "Hash" prefix { auto const types = result[jss::result][jss::TYPES]; From 838978b86957534e801859e805f748627af9529c Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Tue, 12 Nov 2024 18:40:22 -0500 Subject: [PATCH 78/82] Set version to 2.3.0-rc2 --- src/libxrpl/protocol/BuildInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libxrpl/protocol/BuildInfo.cpp b/src/libxrpl/protocol/BuildInfo.cpp index 833240f531d..c3d0bd1f92d 100644 --- a/src/libxrpl/protocol/BuildInfo.cpp +++ b/src/libxrpl/protocol/BuildInfo.cpp @@ -33,7 +33,7 @@ namespace BuildInfo { // and follow the format described at http://semver.org/ //------------------------------------------------------------------------------ // clang-format off -char const* const versionString = "2.3.0-rc1" +char const* const versionString = "2.3.0-rc2" // clang-format on #if defined(DEBUG) || defined(SANITIZER) From 0ec17b6026298dc150099b66a2cecad0fe561d1b Mon Sep 17 00:00:00 2001 From: Olek <115580134+oleks-rip@users.noreply.github.com> Date: Mon, 18 Nov 2024 13:58:25 -0500 Subject: [PATCH 79/82] fix: check for valid ammID field in amm_info RPC (#5188) --- src/test/rpc/AMMInfo_test.cpp | 19 +++++++++++++++++++ src/xrpld/rpc/handlers/AMMInfo.cpp | 2 ++ 2 files changed, 21 insertions(+) diff --git a/src/test/rpc/AMMInfo_test.cpp b/src/test/rpc/AMMInfo_test.cpp index e4523bb0473..c1e059a3ead 100644 --- a/src/test/rpc/AMMInfo_test.cpp +++ b/src/test/rpc/AMMInfo_test.cpp @@ -316,6 +316,24 @@ class AMMInfo_test : public jtx::AMMTestBase }); } + void + testInvalidAmmField() + { + using namespace jtx; + testcase("Invalid amm field"); + + testAMM([&](AMM& amm, Env&) { + auto const resp = amm.ammRpcInfo( + std::nullopt, + jss::validated.c_str(), + std::nullopt, + std::nullopt, + gw); + BEAST_EXPECT( + resp.isMember("error") && resp["error"] == "actNotFound"); + }); + } + void run() override { @@ -323,6 +341,7 @@ class AMMInfo_test : public jtx::AMMTestBase testSimpleRpc(); testVoteAndBid(); testFreeze(); + testInvalidAmmField(); } }; diff --git a/src/xrpld/rpc/handlers/AMMInfo.cpp b/src/xrpld/rpc/handlers/AMMInfo.cpp index aad8faea213..9d5b20f1d63 100644 --- a/src/xrpld/rpc/handlers/AMMInfo.cpp +++ b/src/xrpld/rpc/handlers/AMMInfo.cpp @@ -132,6 +132,8 @@ doAMMInfo(RPC::JsonContext& context) if (!sle) return Unexpected(rpcACT_MALFORMED); ammID = sle->getFieldH256(sfAMMID); + if (ammID->isZero()) + return Unexpected(rpcACT_NOT_FOUND); } if (params.isMember(jss::account)) From f419c18056889c857dbfa1f9a97c8ca4779ffa7d Mon Sep 17 00:00:00 2001 From: Elliot Lee Date: Mon, 25 Nov 2024 12:12:35 -0800 Subject: [PATCH 80/82] Add a new serialized type: STNumber (#5121) `STNumber` lets objects and transactions contain multiple fields for quantities of XRP, IOU, or MPT without duplicating information about the "issue" (represented by `STIssue`). It is a straightforward serialization of the `Number` type that uniformly represents those quantities. --------- Co-authored-by: John Freeman Co-authored-by: Howard Hinnant --- include/xrpl/basics/Number.h | 16 ++-- include/xrpl/protocol/SField.h | 5 +- include/xrpl/protocol/STNumber.h | 88 +++++++++++++++++ include/xrpl/protocol/STObject.h | 4 + include/xrpl/protocol/Serializer.h | 39 +++++++- include/xrpl/protocol/detail/sfields.macro | 3 + include/xrpl/protocol/st.h | 1 + src/libxrpl/protocol/STNumber.cpp | 105 +++++++++++++++++++++ src/libxrpl/protocol/STObject.cpp | 14 +++ src/libxrpl/protocol/STVar.cpp | 1 + src/libxrpl/protocol/Serializer.cpp | 51 +++++----- src/test/protocol/STNumber_test.cpp | 93 ++++++++++++++++++ src/test/protocol/Serializer_test.cpp | 69 ++++++++++++++ src/xrpld/app/tx/detail/Payment.cpp | 18 ++-- src/xrpld/ledger/detail/CachedView.cpp | 21 ++--- 15 files changed, 470 insertions(+), 58 deletions(-) create mode 100644 include/xrpl/protocol/STNumber.h create mode 100644 src/libxrpl/protocol/STNumber.cpp create mode 100644 src/test/protocol/STNumber_test.cpp create mode 100644 src/test/protocol/Serializer_test.cpp diff --git a/include/xrpl/basics/Number.h b/include/xrpl/basics/Number.h index 01b3adb22d4..70baf5d1e47 100644 --- a/include/xrpl/basics/Number.h +++ b/include/xrpl/basics/Number.h @@ -41,6 +41,14 @@ class Number int exponent_{std::numeric_limits::lowest()}; public: + // The range for the mantissa when normalized + constexpr static std::int64_t minMantissa = 1'000'000'000'000'000LL; + constexpr static std::int64_t maxMantissa = 9'999'999'999'999'999LL; + + // The range for the exponent when normalized + constexpr static int minExponent = -32768; + constexpr static int maxExponent = 32768; + struct unchecked { explicit unchecked() = default; @@ -191,14 +199,6 @@ class Number constexpr bool isnormal() const noexcept; - // The range for the mantissa when normalized - constexpr static std::int64_t minMantissa = 1'000'000'000'000'000LL; - constexpr static std::int64_t maxMantissa = 9'999'999'999'999'999LL; - - // The range for the exponent when normalized - constexpr static int minExponent = -32768; - constexpr static int maxExponent = 32768; - class Guard; }; diff --git a/include/xrpl/protocol/SField.h b/include/xrpl/protocol/SField.h index 942f2a8654b..01909b19862 100644 --- a/include/xrpl/protocol/SField.h +++ b/include/xrpl/protocol/SField.h @@ -49,6 +49,7 @@ template class STBitString; template class STInteger; +class STNumber; class STXChainBridge; class STVector256; class STCurrency; @@ -70,8 +71,9 @@ class STCurrency; STYPE(STI_AMOUNT, 6) \ STYPE(STI_VL, 7) \ STYPE(STI_ACCOUNT, 8) \ + STYPE(STI_NUMBER, 9) \ \ - /* 9-13 are reserved */ \ + /* 10-13 are reserved */ \ STYPE(STI_OBJECT, 14) \ STYPE(STI_ARRAY, 15) \ \ @@ -355,6 +357,7 @@ using SF_ACCOUNT = TypedField; using SF_AMOUNT = TypedField; using SF_ISSUE = TypedField; using SF_CURRENCY = TypedField; +using SF_NUMBER = TypedField; using SF_VL = TypedField; using SF_VECTOR256 = TypedField; using SF_XCHAIN_BRIDGE = TypedField; diff --git a/include/xrpl/protocol/STNumber.h b/include/xrpl/protocol/STNumber.h new file mode 100644 index 00000000000..c0fce572c8c --- /dev/null +++ b/include/xrpl/protocol/STNumber.h @@ -0,0 +1,88 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 XRPL_PROTOCOL_STNUMBER_H_INCLUDED +#define XRPL_PROTOCOL_STNUMBER_H_INCLUDED + +#include +#include +#include + +#include + +namespace ripple { + +/** + * A serializable number. + * + * This type is-a `Number`, and can be used everywhere that is accepted. + * This type simply integrates `Number` with the serialization framework, + * letting it be used for fields in ledger entries and transactions. + * It is effectively an `STAmount` sans `Asset`: + * it can represent a value of any token type (XRP, IOU, or MPT) + * without paying the storage cost of duplicating asset information + * that may be deduced from the context. + */ +class STNumber : public STBase, public CountedObject +{ +private: + Number value_; + +public: + using value_type = Number; + + STNumber() = default; + explicit STNumber(SField const& field, Number const& value = Number()); + STNumber(SerialIter& sit, SField const& field); + + SerializedTypeID + getSType() const override; + std::string + getText() const override; + void + add(Serializer& s) const override; + + Number const& + value() const; + void + setValue(Number const& v); + + bool + isEquivalent(STBase const& t) const override; + bool + isDefault() const override; + + operator Number() const + { + return value_; + } + +private: + STBase* + copy(std::size_t n, void* buf) const override; + STBase* + move(std::size_t n, void* buf) override; +}; + +std::ostream& +operator<<(std::ostream& out, STNumber const& rhs); + +} // namespace ripple + +#endif diff --git a/include/xrpl/protocol/STObject.h b/include/xrpl/protocol/STObject.h index c06f109dc56..748a2b5d685 100644 --- a/include/xrpl/protocol/STObject.h +++ b/include/xrpl/protocol/STObject.h @@ -245,6 +245,8 @@ class STObject : public STBase, public CountedObject getFieldArray(SField const& field) const; const STCurrency& getFieldCurrency(SField const& field) const; + STNumber const& + getFieldNumber(SField const& field) const; /** Get the value of a field. @param A TypedField built from an SField value representing the desired @@ -376,6 +378,8 @@ class STObject : public STBase, public CountedObject void setFieldCurrency(SField const& field, STCurrency const&); void + setFieldNumber(SField const& field, STNumber const&); + void setFieldPathSet(SField const& field, STPathSet const&); void setFieldV256(SField const& field, STVector256 const& v); diff --git a/include/xrpl/protocol/Serializer.h b/include/xrpl/protocol/Serializer.h index d8d0b9222e3..0e96078ed14 100644 --- a/include/xrpl/protocol/Serializer.h +++ b/include/xrpl/protocol/Serializer.h @@ -83,12 +83,43 @@ class Serializer add8(unsigned char i); int add16(std::uint16_t i); + + template + requires(std::is_same_v< + std::make_unsigned_t>, + std::uint32_t>) int - add32(std::uint32_t i); // ledger indexes, account sequence, timestamps + add32(T i) + { + int ret = mData.size(); + mData.push_back(static_cast((i >> 24) & 0xff)); + mData.push_back(static_cast((i >> 16) & 0xff)); + mData.push_back(static_cast((i >> 8) & 0xff)); + mData.push_back(static_cast(i & 0xff)); + return ret; + } + int add32(HashPrefix p); + + template + requires(std::is_same_v< + std::make_unsigned_t>, + std::uint64_t>) int - add64(std::uint64_t i); // native currency amounts + add64(T i) + { + int ret = mData.size(); + mData.push_back(static_cast((i >> 56) & 0xff)); + mData.push_back(static_cast((i >> 48) & 0xff)); + mData.push_back(static_cast((i >> 40) & 0xff)); + mData.push_back(static_cast((i >> 32) & 0xff)); + mData.push_back(static_cast((i >> 24) & 0xff)); + mData.push_back(static_cast((i >> 16) & 0xff)); + mData.push_back(static_cast((i >> 8) & 0xff)); + mData.push_back(static_cast(i & 0xff)); + return ret; + } template int addInteger(Integer); @@ -353,9 +384,13 @@ class SerialIter std::uint32_t get32(); + std::int32_t + geti32(); std::uint64_t get64(); + std::int64_t + geti64(); template base_uint diff --git a/include/xrpl/protocol/detail/sfields.macro b/include/xrpl/protocol/detail/sfields.macro index ccf6350cbfc..8384025ee3b 100644 --- a/include/xrpl/protocol/detail/sfields.macro +++ b/include/xrpl/protocol/detail/sfields.macro @@ -191,6 +191,9 @@ TYPED_SFIELD(sfHookHash, UINT256, 31) TYPED_SFIELD(sfHookNamespace, UINT256, 32) TYPED_SFIELD(sfHookSetTxnID, UINT256, 33) +// number (common) +TYPED_SFIELD(sfNumber, NUMBER, 1) + // currency amount (common) TYPED_SFIELD(sfAmount, AMOUNT, 1) TYPED_SFIELD(sfBalance, AMOUNT, 2) diff --git a/include/xrpl/protocol/st.h b/include/xrpl/protocol/st.h index 7b0e3a3b2df..0035deaa1bc 100644 --- a/include/xrpl/protocol/st.h +++ b/include/xrpl/protocol/st.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include diff --git a/src/libxrpl/protocol/STNumber.cpp b/src/libxrpl/protocol/STNumber.cpp new file mode 100644 index 00000000000..3a92bbb02f9 --- /dev/null +++ b/src/libxrpl/protocol/STNumber.cpp @@ -0,0 +1,105 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2023 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 + +#include + +namespace ripple { + +STNumber::STNumber(SField const& field, Number const& value) + : STBase(field), value_(value) +{ +} + +STNumber::STNumber(SerialIter& sit, SField const& field) : STBase(field) +{ + // We must call these methods in separate statements + // to guarantee their order of execution. + auto mantissa = sit.geti64(); + auto exponent = sit.geti32(); + value_ = Number{mantissa, exponent}; +} + +SerializedTypeID +STNumber::getSType() const +{ + return STI_NUMBER; +} + +std::string +STNumber::getText() const +{ + return to_string(value_); +} + +void +STNumber::add(Serializer& s) const +{ + assert(getFName().isBinary()); + assert(getFName().fieldType == getSType()); + s.add64(value_.mantissa()); + s.add32(value_.exponent()); +} + +Number const& +STNumber::value() const +{ + return value_; +} + +void +STNumber::setValue(Number const& v) +{ + value_ = v; +} + +STBase* +STNumber::copy(std::size_t n, void* buf) const +{ + return emplace(n, buf, *this); +} + +STBase* +STNumber::move(std::size_t n, void* buf) +{ + return emplace(n, buf, std::move(*this)); +} + +bool +STNumber::isEquivalent(STBase const& t) const +{ + assert(t.getSType() == this->getSType()); + STNumber const& v = dynamic_cast(t); + return value_ == v; +} + +bool +STNumber::isDefault() const +{ + return value_ == Number(); +} + +std::ostream& +operator<<(std::ostream& out, STNumber const& rhs) +{ + return out << rhs.getText(); +} + +} // namespace ripple diff --git a/src/libxrpl/protocol/STObject.cpp b/src/libxrpl/protocol/STObject.cpp index 7e62fc25bd6..c8fc88348e9 100644 --- a/src/libxrpl/protocol/STObject.cpp +++ b/src/libxrpl/protocol/STObject.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include namespace ripple { @@ -665,6 +666,13 @@ STObject::getFieldCurrency(SField const& field) const return getFieldByConstRef(field, empty); } +STNumber const& +STObject::getFieldNumber(SField const& field) const +{ + static STNumber const empty{}; + return getFieldByConstRef(field, empty); +} + void STObject::set(std::unique_ptr v) { @@ -765,6 +773,12 @@ STObject::setFieldIssue(SField const& field, STIssue const& v) setFieldUsingAssignment(field, v); } +void +STObject::setFieldNumber(SField const& field, STNumber const& v) +{ + setFieldUsingAssignment(field, v); +} + void STObject::setFieldPathSet(SField const& field, STPathSet const& v) { diff --git a/src/libxrpl/protocol/STVar.cpp b/src/libxrpl/protocol/STVar.cpp index f185595eadb..55927cb33aa 100644 --- a/src/libxrpl/protocol/STVar.cpp +++ b/src/libxrpl/protocol/STVar.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include diff --git a/src/libxrpl/protocol/Serializer.cpp b/src/libxrpl/protocol/Serializer.cpp index b99375f80dd..ceaf76faf34 100644 --- a/src/libxrpl/protocol/Serializer.cpp +++ b/src/libxrpl/protocol/Serializer.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include namespace ripple { @@ -34,17 +35,6 @@ Serializer::add16(std::uint16_t i) return ret; } -int -Serializer::add32(std::uint32_t i) -{ - int ret = mData.size(); - mData.push_back(static_cast(i >> 24)); - mData.push_back(static_cast((i >> 16) & 0xff)); - mData.push_back(static_cast((i >> 8) & 0xff)); - mData.push_back(static_cast(i & 0xff)); - return ret; -} - int Serializer::add32(HashPrefix p) { @@ -56,21 +46,6 @@ Serializer::add32(HashPrefix p) return add32(safe_cast(p)); } -int -Serializer::add64(std::uint64_t i) -{ - int ret = mData.size(); - mData.push_back(static_cast(i >> 56)); - mData.push_back(static_cast((i >> 48) & 0xff)); - mData.push_back(static_cast((i >> 40) & 0xff)); - mData.push_back(static_cast((i >> 32) & 0xff)); - mData.push_back(static_cast((i >> 24) & 0xff)); - mData.push_back(static_cast((i >> 16) & 0xff)); - mData.push_back(static_cast((i >> 8) & 0xff)); - mData.push_back(static_cast(i & 0xff)); - return ret; -} - template <> int Serializer::addInteger(unsigned char i) @@ -410,6 +385,30 @@ SerialIter::get64() (std::uint64_t(t[6]) << 8) + std::uint64_t(t[7]); } +std::int32_t +SerialIter::geti32() +{ + if (remain_ < 4) + Throw("invalid SerialIter geti32"); + auto t = p_; + p_ += 4; + used_ += 4; + remain_ -= 4; + return boost::endian::load_big_s32(t); +} + +std::int64_t +SerialIter::geti64() +{ + if (remain_ < 8) + Throw("invalid SerialIter geti64"); + auto t = p_; + p_ += 8; + used_ += 8; + remain_ -= 8; + return boost::endian::load_big_s64(t); +} + void SerialIter::getFieldID(int& type, int& name) { diff --git a/src/test/protocol/STNumber_test.cpp b/src/test/protocol/STNumber_test.cpp new file mode 100644 index 00000000000..ed255e32f1c --- /dev/null +++ b/src/test/protocol/STNumber_test.cpp @@ -0,0 +1,93 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 +#include +#include +#include + +#include +#include + +namespace ripple { + +struct STNumber_test : public beast::unit_test::suite +{ + void + testCombo(Number number) + { + STNumber const before{sfNumber, number}; + BEAST_EXPECT(number == before); + Serializer s; + before.add(s); + BEAST_EXPECT(s.size() == 12); + SerialIter sit(s.slice()); + STNumber const after{sit, sfNumber}; + BEAST_EXPECT(after.isEquivalent(before)); + BEAST_EXPECT(number == after); + } + + void + run() override + { + static_assert(!std::is_convertible_v); + + { + STNumber const stnum{sfNumber}; + BEAST_EXPECT(stnum.getSType() == STI_NUMBER); + BEAST_EXPECT(stnum.getText() == "0"); + BEAST_EXPECT(stnum.isDefault() == true); + BEAST_EXPECT(stnum.value() == Number{0}); + } + + std::initializer_list const mantissas = { + std::numeric_limits::min(), + -1, + 0, + 1, + std::numeric_limits::max()}; + for (std::int64_t mantissa : mantissas) + testCombo(Number{mantissa}); + + std::initializer_list const exponents = { + Number::minExponent, -1, 0, 1, Number::maxExponent - 1}; + for (std::int32_t exponent : exponents) + testCombo(Number{123, exponent}); + + { + STAmount const strikePrice{noIssue(), 100}; + STNumber const factor{sfNumber, 100}; + auto const iouValue = strikePrice.iou(); + IOUAmount totalValue{iouValue * factor}; + STAmount const totalAmount{totalValue, strikePrice.issue()}; + BEAST_EXPECT(totalAmount == Number{10'000}); + } + } +}; + +BEAST_DEFINE_TESTSUITE(STNumber, protocol, ripple); + +void +testCompile(std::ostream& out) +{ + STNumber number{sfNumber, 42}; + out << number; +} + +} // namespace ripple diff --git a/src/test/protocol/Serializer_test.cpp b/src/test/protocol/Serializer_test.cpp new file mode 100644 index 00000000000..d707943856f --- /dev/null +++ b/src/test/protocol/Serializer_test.cpp @@ -0,0 +1,69 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 +#include + +#include + +namespace ripple { + +struct Serializer_test : public beast::unit_test::suite +{ + void + run() override + { + { + std::initializer_list const values = { + std::numeric_limits::min(), + -1, + 0, + 1, + std::numeric_limits::max()}; + for (std::int32_t value : values) + { + Serializer s; + s.add32(value); + BEAST_EXPECT(s.size() == 4); + SerialIter sit(s.slice()); + BEAST_EXPECT(sit.geti32() == value); + } + } + { + std::initializer_list const values = { + std::numeric_limits::min(), + -1, + 0, + 1, + std::numeric_limits::max()}; + for (std::int64_t value : values) + { + Serializer s; + s.add64(value); + BEAST_EXPECT(s.size() == 8); + SerialIter sit(s.slice()); + BEAST_EXPECT(sit.geti64() == value); + } + } + } +}; + +BEAST_DEFINE_TESTSUITE(Serializer, protocol, ripple); + +} // namespace ripple diff --git a/src/xrpld/app/tx/detail/Payment.cpp b/src/xrpld/app/tx/detail/Payment.cpp index 2ea13ffabc8..2be784306cd 100644 --- a/src/xrpld/app/tx/detail/Payment.cpp +++ b/src/xrpld/app/tx/detail/Payment.cpp @@ -88,7 +88,7 @@ Payment::preflight(PreflightContext const& ctx) if (txFlags & paymentMask) { - JLOG(j.trace()) << "Malformed transaction: " << "Invalid flags set."; + JLOG(j.trace()) << "Malformed transaction: Invalid flags set."; return temINVALID_FLAG; } @@ -110,9 +110,9 @@ Payment::preflight(PreflightContext const& ctx) if ((mptDirect && dstAmount.asset() != maxSourceAmount.asset()) || (!mptDirect && maxSourceAmount.holds())) { - JLOG(j.trace()) << "Malformed transaction: " - << "inconsistent issues: " << dstAmount.getFullText() - << " " << maxSourceAmount.getFullText() << " " + JLOG(j.trace()) << "Malformed transaction: inconsistent issues: " + << dstAmount.getFullText() << " " + << maxSourceAmount.getFullText() << " " << deliverMin.value_or(STAmount{}).getFullText(); return temMALFORMED; } @@ -135,19 +135,19 @@ Payment::preflight(PreflightContext const& ctx) } if (hasMax && maxSourceAmount <= beast::zero) { - JLOG(j.trace()) << "Malformed transaction: " << "bad max amount: " + JLOG(j.trace()) << "Malformed transaction: bad max amount: " << maxSourceAmount.getFullText(); return temBAD_AMOUNT; } if (dstAmount <= beast::zero) { - JLOG(j.trace()) << "Malformed transaction: " - << "bad dst amount: " << dstAmount.getFullText(); + JLOG(j.trace()) << "Malformed transaction: bad dst amount: " + << dstAmount.getFullText(); return temBAD_AMOUNT; } if (badCurrency() == srcAsset || badCurrency() == dstAsset) { - JLOG(j.trace()) << "Malformed transaction: " << "Bad currency."; + JLOG(j.trace()) << "Malformed transaction: Bad currency."; return temBAD_CURRENCY; } if (account == dstAccountID && equalTokens(srcAsset, dstAsset) && !hasPaths) @@ -550,7 +550,7 @@ Payment::doApply() // Vote no. However the transaction might succeed, if applied in // a different order. JLOG(j_.trace()) << "Delay transaction: Insufficient funds: " - << " " << to_string(mPriorBalance) << " / " + << to_string(mPriorBalance) << " / " << to_string(dstAmount.xrp() + mmm) << " (" << to_string(reserve) << ")"; diff --git a/src/xrpld/ledger/detail/CachedView.cpp b/src/xrpld/ledger/detail/CachedView.cpp index 5502c40e6d5..645a2c79c13 100644 --- a/src/xrpld/ledger/detail/CachedView.cpp +++ b/src/xrpld/ledger/detail/CachedView.cpp @@ -63,20 +63,17 @@ CachedViewImpl::read(Keylet const& k) const hits.increment(); else misses.increment(); - std::lock_guard lock(mutex_); - auto const er = map_.emplace(k.key, *digest); - bool const inserted = er.second; - if (sle && !k.check(*sle)) + + if (!cacheHit) { - if (!inserted) - { - // On entry, this function did not find this key in map_. Now - // something (another thread?) has inserted the sle into the map and - // it has the wrong type. - LogicError("CachedView::read: wrong type"); - } - return nullptr; + // Avoid acquiring this lock unless necessary. It is only necessary if + // the key was not found in the map_. The lock is needed to add the key + // and digest. + std::lock_guard lock(mutex_); + map_.emplace(k.key, *digest); } + if (!sle || !k.check(*sle)) + return nullptr; return sle; } From b54d85d8620e622d567423a1a87dfe79ecdff71c Mon Sep 17 00:00:00 2001 From: Elliot Lee Date: Mon, 25 Nov 2024 11:40:11 -0800 Subject: [PATCH 81/82] refactor(AMMClawback): move tfClawTwoAssets check (#5201) Move tfClawTwoAssets check to preflight and return error temINVALID_FLAG --------- Co-authored-by: yinyiqian1 --- include/xrpl/protocol/detail/features.macro | 2 +- src/test/app/AMMClawback_test.cpp | 6 +++--- src/xrpld/app/tx/detail/AMMClawback.cpp | 21 +++++++++++---------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/include/xrpl/protocol/detail/features.macro b/include/xrpl/protocol/detail/features.macro index 24c6e72ae34..31fc90cef80 100644 --- a/include/xrpl/protocol/detail/features.macro +++ b/include/xrpl/protocol/detail/features.macro @@ -32,9 +32,9 @@ XRPL_FEATURE(Credentials, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(AMMClawback, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (AMMv1_2, Supported::yes, VoteBehavior::DefaultNo) +XRPL_FEATURE(MPTokensV1, Supported::yes, VoteBehavior::DefaultNo) // InvariantsV1_1 will be changes to Supported::yes when all the // invariants expected to be included under it are complete. -XRPL_FEATURE(MPTokensV1, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(InvariantsV1_1, Supported::no, VoteBehavior::DefaultNo) XRPL_FIX (NFTokenPageLinks, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (InnerObjTemplate2, Supported::yes, VoteBehavior::DefaultNo) diff --git a/src/test/app/AMMClawback_test.cpp b/src/test/app/AMMClawback_test.cpp index 705a1274073..c547a537bfb 100644 --- a/src/test/app/AMMClawback_test.cpp +++ b/src/test/app/AMMClawback_test.cpp @@ -303,13 +303,13 @@ class AMMClawback_test : public jtx::AMMTest // gw creates AMM pool of XRP/USD. AMM amm(env, gw, XRP(100), USD(100), ter(tesSUCCESS)); - // Return tecNO_PERMISSION because the issuer set tfClawTwoAssets, + // Return temINVALID_FLAG because the issuer set tfClawTwoAssets, // but the issuer only issues USD in the pool. The issuer is not // allowed to set tfClawTwoAssets flag if he did not issue both - // assts in the pool. + // assets in the pool. env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt), txflags(tfClawTwoAssets), - ter(tecNO_PERMISSION)); + ter(temINVALID_FLAG)); } // Test clawing back XRP is being prohibited. diff --git a/src/xrpld/app/tx/detail/AMMClawback.cpp b/src/xrpld/app/tx/detail/AMMClawback.cpp index 64150ded6da..cd1e3008e97 100644 --- a/src/xrpld/app/tx/detail/AMMClawback.cpp +++ b/src/xrpld/app/tx/detail/AMMClawback.cpp @@ -42,7 +42,8 @@ AMMClawback::preflight(PreflightContext const& ctx) if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) return ret; // LCOV_EXCL_LINE - if (ctx.tx.getFlags() & tfAMMClawbackMask) + auto const flags = ctx.tx.getFlags(); + if (flags & tfAMMClawbackMask) return temINVALID_FLAG; AccountID const issuer = ctx.tx[sfAccount]; @@ -57,10 +58,19 @@ AMMClawback::preflight(PreflightContext const& ctx) std::optional const clawAmount = ctx.tx[~sfAmount]; auto const asset = ctx.tx[sfAsset]; + auto const asset2 = ctx.tx[sfAsset2]; if (isXRP(asset)) return temMALFORMED; + if (flags & tfClawTwoAssets && asset.account != asset2.account) + { + JLOG(ctx.j.trace()) + << "AMMClawback: tfClawTwoAssets can only be enabled when two " + "assets in the AMM pool are both issued by the issuer"; + return temINVALID_FLAG; + } + if (asset.account != issuer) { JLOG(ctx.j.trace()) << "AMMClawback: Asset's account does not " @@ -108,15 +118,6 @@ AMMClawback::preclaim(PreclaimContext const& ctx) (issuerFlagsIn & lsfNoFreeze)) return tecNO_PERMISSION; - auto const flags = ctx.tx.getFlags(); - if (flags & tfClawTwoAssets && asset.account != asset2.account) - { - JLOG(ctx.j.trace()) - << "AMMClawback: tfClawTwoAssets can only be enabled when two " - "assets in the AMM pool are both issued by the issuer"; - return tecNO_PERMISSION; - } - return tesSUCCESS; } From f64cf9187affd69650907d0d92e097eb29693945 Mon Sep 17 00:00:00 2001 From: Elliot Lee Date: Mon, 25 Nov 2024 12:27:17 -0800 Subject: [PATCH 82/82] Set version to 2.3.0 --- RELEASENOTES.md | 73 ++++++++++++++++++++++++++++++ src/libxrpl/protocol/BuildInfo.cpp | 2 +- 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c6a43f4aa7d..c6e8266e348 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -6,6 +6,79 @@ This document contains the release notes for `rippled`, the reference server imp Have new ideas? Need help with setting up your node? [Please open an issue here](https://github.com/xrplf/rippled/issues/new/choose). +# Version 2.3.0 + +Version 2.3.0 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release includes 8 new amendments, including Multi-Purpose Tokens, Credentials, Clawback support for AMMs, and the ability to make offers as part of minting NFTs. Additionally, this release includes important fixes for stability, so server operators are encouraged to upgrade as soon as possible. + + +## Action Required + +If you run an XRP Ledger server, upgrade to version 2.3.0 as soon as possible to ensure service continuity. + +Additionally, new amendments are now open for voting according to the XRP Ledger's [amendment process](https://xrpl.org/amendments.html), which enables protocol changes following two weeks of >80% support from trusted validators. The exact time that protocol changes take effect depends on the voting decisions of the decentralized network. + +## Full Changelog + +### Amendments + +The following amendments are open for voting with this release: + +- **XLS-70 Credentials** - Users can issue Credentials on the ledger and use Credentials to pre-approve incoming payments when using Deposit Authorization instead of individually approving payers. ([#5103](https://github.com/XRPLF/rippled/pull/5103)) + - related fix: #5189 (https://github.com/XRPLF/rippled/pull/5189) +- **XLS-33 Multi-Purpose Tokens** - A new type of fungible token optimized for institutional DeFi including stablecoins. ([#5143](https://github.com/XRPLF/rippled/pull/5143)) +- **XLS-37 AMM Clawback** - Allows clawback-enabled tokens to be used in AMMs, with appropriate guardrails. ([#5142](https://github.com/XRPLF/rippled/pull/5142)) +- **XLS-52 NFTokenMintOffer** - Allows creating an NFT sell offer as part of minting a new NFT. ([#4845](https://github.com/XRPLF/rippled/pull/4845)) +- **fixAMMv1_2** - Fixes two bugs in Automated Market Maker (AMM) transaction processing. ([#5176](https://github.com/XRPLF/rippled/pull/5176)) +- **fixNFTokenPageLinks** - Fixes a bug that can cause NFT directories to have missing links, and introduces a transaction to repair corrupted ledger state. ([#4945](https://github.com/XRPLF/rippled/pull/4945)) +- **fixEnforceNFTokenTrustline** - Fixes two bugs in the interaction between NFT offers and trust lines. ([#4946](https://github.com/XRPLF/rippled/pull/4946)) +- **fixInnerObjTemplate2** - Standardizes the way inner objects are enforced across all transaction and ledger data. ([#5047](https://github.com/XRPLF/rippled/pull/5047)) + +The following amendment is partially implemented but not open for voting: + +- **InvariantsV1_1** - Adds new invariants to ensure transactions process as intended, starting with an invariant to ensure that ledger entries owned by an account are deleted when the account is deleted. ([#4663](https://github.com/XRPLF/rippled/pull/4663)) + +### New Features + +- Allow configuration of SQLite database page size. ([#5135](https://github.com/XRPLF/rippled/pull/5135), [#5140](https://github.com/XRPLF/rippled/pull/5140)) +- In the `libxrpl` C++ library, provide a list of known amendments. ([#5026](https://github.com/XRPLF/rippled/pull/5026)) + +### Deprecations + +- History Shards are removed. ([#5066](https://github.com/XRPLF/rippled/pull/5066)) +- Reporting mode is removed. ([#5092](https://github.com/XRPLF/rippled/pull/5092)) + +For users wanting to store more ledger history, it is recommended to run a Clio server instead. + +### Bug fixes + +- Fix a crash in debug builds when amm_info request contains an invalid AMM account ID. ([#5188](https://github.com/XRPLF/rippled/pull/5188)) +- Fix a crash caused by a race condition in peer-to-peer code. ([#5071](https://github.com/XRPLF/rippled/pull/5071)) +- Fix a crash in certain situations +- Fix several bugs in the book_changes API method. ([#5096](https://github.com/XRPLF/rippled/pull/5096)) +- Fix bug triggered by providing an invalid marker to the account_nfts API method. ([#5045](https://github.com/XRPLF/rippled/pull/5045)) +- Accept lower-case hexadecimal in compact transaction identifier (CTID) parameters in API methods. ([#5049](https://github.com/XRPLF/rippled/pull/5049)) +- Disallow filtering by types that an account can't own in the account_objects API method. ([#5056](https://github.com/XRPLF/rippled/pull/5056)) +- Fix error code returned by the feature API method when providing an invalid parameter. ([#5063](https://github.com/XRPLF/rippled/pull/5063)) +- (API v3) Fix error code returned by amm_info when providing invalid parameters. ([#4924](https://github.com/XRPLF/rippled/pull/4924)) + +### Other Improvements + +- Adds a new default hub, hubs.xrpkuwait.com, to the config file and bootstrapping code. ([#5169](https://github.com/XRPLF/rippled/pull/5169)) +- Improve error message when commandline interface fails with `rpcInternal` because there was no response from the server. ([#4959](https://github.com/XRPLF/rippled/pull/4959)) +- Add tools for debugging specific transactions via replay. ([#5027](https://github.com/XRPLF/rippled/pull/5027), [#5087](https://github.com/XRPLF/rippled/pull/5087)) +- Major reorganization of source code files. ([#4997](https://github.com/XRPLF/rippled/pull/4997)) +- Add new unit tests. ([#4886](https://github.com/XRPLF/rippled/pull/4886)) +- Various improvements to build tools and contributor documentation. ([#5001](https://github.com/XRPLF/rippled/pull/5001), [#5028](https://github.com/XRPLF/rippled/pull/5028), [#5052](https://github.com/XRPLF/rippled/pull/5052), [#5091](https://github.com/XRPLF/rippled/pull/5091), [#5084](https://github.com/XRPLF/rippled/pull/5084), [#5120](https://github.com/XRPLF/rippled/pull/5120), [#5010](https://github.com/XRPLF/rippled/pull/5010). [#5055](https://github.com/XRPLF/rippled/pull/5055), [#5067](https://github.com/XRPLF/rippled/pull/5067), [#5061](https://github.com/XRPLF/rippled/pull/5061), [#5072](https://github.com/XRPLF/rippled/pull/5072), [#5044](https://github.com/XRPLF/rippled/pull/5044) ) +- Various code cleanup and refactoring. ([#4509](https://github.com/XRPLF/rippled/pull/4509), [#4521](https://github.com/XRPLF/rippled/pull/4521), [#4856](https://github.com/XRPLF/rippled/pull/4856), [#5190](https://github.com/XRPLF/rippled/pull/5190), [#5081](https://github.com/XRPLF/rippled/pull/5081), [#5053](https://github.com/XRPLF/rippled/pull/5053), [#5058](https://github.com/XRPLF/rippled/pull/5058), [#5122](https://github.com/XRPLF/rippled/pull/5122), [#5059](https://github.com/XRPLF/rippled/pull/5059), [#5041](https://github.com/XRPLF/rippled/pull/5041)) + + +Bug Bounties and Responsible Disclosures: + +We welcome reviews of the `rippled` code and urge researchers to responsibly disclose any issues they may find. + +To report a bug, please send a detailed report to: + + # Version 2.2.3 Version 2.2.3 of `rippled`, the reference server implementation of the XRP Ledger protocol, is now available. This release fixes a problem that can cause full-history servers to run out of space in their SQLite databases, depending on configuration. There are no new amendments in this release. diff --git a/src/libxrpl/protocol/BuildInfo.cpp b/src/libxrpl/protocol/BuildInfo.cpp index c3d0bd1f92d..995df262885 100644 --- a/src/libxrpl/protocol/BuildInfo.cpp +++ b/src/libxrpl/protocol/BuildInfo.cpp @@ -33,7 +33,7 @@ namespace BuildInfo { // and follow the format described at http://semver.org/ //------------------------------------------------------------------------------ // clang-format off -char const* const versionString = "2.3.0-rc2" +char const* const versionString = "2.3.0" // clang-format on #if defined(DEBUG) || defined(SANITIZER)