mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-05 17:56:49 +00:00
Merge branch 'develop' into sponsor
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
#include <xrpld/core/ConfigSections.h>
|
||||
|
||||
#include <xrpl/beast/unit_test/suite.h>
|
||||
#include <xrpl/beast/utility/temp_dir.h>
|
||||
#include <xrpl/server/Port.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
@@ -18,7 +19,7 @@ namespace detail {
|
||||
std::string
|
||||
configContents(std::string const& dbPath, std::string const& validatorsFile)
|
||||
{
|
||||
static boost::format configContentsTemplate(R"rippleConfig(
|
||||
static boost::format configContentsTemplate(R"xrpldConfig(
|
||||
[server]
|
||||
port_rpc
|
||||
port_peer
|
||||
@@ -51,14 +52,14 @@ protocol = wss
|
||||
[node_size]
|
||||
medium
|
||||
|
||||
# This is primary persistent datastore for rippled. This includes transaction
|
||||
# This is primary persistent datastore for xrpld. This includes transaction
|
||||
# metadata, account states, and ledger headers. Helpful information can be
|
||||
# found on https://xrpl.org/capacity-planning.html#node-db-type
|
||||
# delete old ledgers while maintaining at least 2000. Do not require an
|
||||
# external administrative command to initiate deletion.
|
||||
[node_db]
|
||||
type=memory
|
||||
path=/Users/dummy/ripple/config/db/rocksdb
|
||||
path=/Users/dummy/xrpld/config/db/rocksdb
|
||||
open_files=2000
|
||||
filter_bits=12
|
||||
cache_mb=256
|
||||
@@ -72,7 +73,7 @@ file_size_mult=2
|
||||
# This needs to be an absolute directory reference, not a relative one.
|
||||
# Modify this value as required.
|
||||
[debug_logfile]
|
||||
/Users/dummy/ripple/config/log/debug.log
|
||||
/Users/dummy/xrpld/config/log/debug.log
|
||||
|
||||
[sntp_servers]
|
||||
time.windows.com
|
||||
@@ -97,7 +98,7 @@ r.ripple.com 51235
|
||||
|
||||
[sqdb]
|
||||
backend=sqlite
|
||||
)rippleConfig");
|
||||
)xrpldConfig");
|
||||
|
||||
std::string dbPathSection =
|
||||
dbPath.empty() ? "" : "[database_path]\n" + dbPath;
|
||||
@@ -107,9 +108,9 @@ backend=sqlite
|
||||
}
|
||||
|
||||
/**
|
||||
Write a rippled config file and remove when done.
|
||||
Write a xrpld config file and remove when done.
|
||||
*/
|
||||
class RippledCfgGuard : public xrpl::detail::FileDirGuard
|
||||
class FileCfgGuard : public xrpl::detail::FileDirGuard
|
||||
{
|
||||
private:
|
||||
path dataDir_;
|
||||
@@ -119,17 +120,18 @@ private:
|
||||
Config config_;
|
||||
|
||||
public:
|
||||
RippledCfgGuard(
|
||||
FileCfgGuard(
|
||||
beast::unit_test::suite& test,
|
||||
path subDir,
|
||||
path const& dbPath,
|
||||
path const& configFile,
|
||||
path const& validatorsFile,
|
||||
bool useCounter = true,
|
||||
std::string confContents = "")
|
||||
: FileDirGuard(
|
||||
test,
|
||||
std::move(subDir),
|
||||
path(Config::configFileName),
|
||||
configFile,
|
||||
confContents.empty()
|
||||
? configContents(dbPath.string(), validatorsFile.string())
|
||||
: confContents,
|
||||
@@ -171,7 +173,7 @@ public:
|
||||
return fileExists();
|
||||
}
|
||||
|
||||
~RippledCfgGuard()
|
||||
~FileCfgGuard()
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -182,7 +184,7 @@ public:
|
||||
catch (std::exception& e)
|
||||
{
|
||||
// if we throw here, just let it die.
|
||||
test_.log << "Error in ~RippledCfgGuard: " << e.what() << std::endl;
|
||||
test_.log << "Error in ~FileCfgGuard: " << e.what() << std::endl;
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -190,7 +192,7 @@ public:
|
||||
std::string
|
||||
valFileContents()
|
||||
{
|
||||
std::string configContents(R"rippleConfig(
|
||||
std::string configContents(R"xrpldConfig(
|
||||
[validators]
|
||||
n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
|
||||
n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
|
||||
@@ -204,8 +206,8 @@ nHBu9PTL9dn2GuZtdW4U2WzBwffyX9qsQCd9CNU4Z5YG3PQfViM8
|
||||
nHUPDdcdb2Y5DZAJne4c2iabFuAP3F34xZUgYQT2NH7qfkdapgnz
|
||||
|
||||
[validator_list_sites]
|
||||
recommendedripplevalidators.com
|
||||
moreripplevalidators.net
|
||||
recommendedxrplvalidators.com
|
||||
morexrplvalidators.net
|
||||
|
||||
[validator_list_keys]
|
||||
03E74EE14CB525AFBB9F1B7D86CD58ECC4B91452294B42AB4E78F260BD905C091D
|
||||
@@ -213,7 +215,7 @@ moreripplevalidators.net
|
||||
|
||||
[validator_list_threshold]
|
||||
2
|
||||
)rippleConfig");
|
||||
)xrpldConfig");
|
||||
return configContents;
|
||||
}
|
||||
|
||||
@@ -270,7 +272,7 @@ public:
|
||||
|
||||
Config c;
|
||||
|
||||
std::string toLoad(R"rippleConfig(
|
||||
std::string toLoad(R"xrpldConfig(
|
||||
[server]
|
||||
port_rpc
|
||||
port_peer
|
||||
@@ -278,7 +280,7 @@ port_wss_admin
|
||||
|
||||
[ssl_verify]
|
||||
0
|
||||
)rippleConfig");
|
||||
)xrpldConfig");
|
||||
|
||||
c.loadFromString(toLoad);
|
||||
|
||||
@@ -291,6 +293,126 @@ port_wss_admin
|
||||
BEAST_EXPECT(c.legacy("not_in_file") == "new_value");
|
||||
}
|
||||
void
|
||||
testConfigFile()
|
||||
{
|
||||
testcase("config_file");
|
||||
|
||||
using namespace boost::filesystem;
|
||||
auto const cwd = current_path();
|
||||
|
||||
// Test both config file names.
|
||||
char const* configFiles[] = {
|
||||
Config::configFileName, Config::configLegacyName};
|
||||
|
||||
// Config file in current directory.
|
||||
for (auto const& configFile : configFiles)
|
||||
{
|
||||
// Use a temporary directory for testing.
|
||||
beast::temp_dir td;
|
||||
current_path(td.path());
|
||||
path const f = td.file(configFile);
|
||||
std::ofstream o(f.string());
|
||||
o << detail::configContents("", "");
|
||||
o.close();
|
||||
|
||||
// Load the config file from the current directory and verify it.
|
||||
Config c;
|
||||
c.setup("", true, false, true);
|
||||
BEAST_EXPECT(c.section(SECTION_DEBUG_LOGFILE).values().size() == 1);
|
||||
BEAST_EXPECT(
|
||||
c.section(SECTION_DEBUG_LOGFILE).values()[0] ==
|
||||
"/Users/dummy/xrpld/config/log/debug.log");
|
||||
}
|
||||
|
||||
// Config file in HOME or XDG_CONFIG_HOME directory.
|
||||
#if BOOST_OS_LINUX || BOOST_OS_MACOS
|
||||
for (auto const& configFile : configFiles)
|
||||
{
|
||||
// Point the current working directory to a temporary directory, so
|
||||
// we don't pick up an actual config file from the repository root.
|
||||
beast::temp_dir td;
|
||||
current_path(td.path());
|
||||
|
||||
// The XDG config directory is set: the config file must be in a
|
||||
// subdirectory named after the system.
|
||||
{
|
||||
beast::temp_dir tc;
|
||||
|
||||
// Set the HOME and XDG_CONFIG_HOME environment variables. The
|
||||
// HOME variable is not used when XDG_CONFIG_HOME is set, but
|
||||
// must be set.
|
||||
char const* h = getenv("HOME");
|
||||
setenv("HOME", tc.path().c_str(), 1);
|
||||
char const* x = getenv("XDG_CONFIG_HOME");
|
||||
setenv("XDG_CONFIG_HOME", tc.path().c_str(), 1);
|
||||
|
||||
// Create the config file in '${XDG_CONFIG_HOME}/[systemName]'.
|
||||
path p = tc.file(systemName());
|
||||
create_directory(p);
|
||||
p = tc.file(systemName() + "/" + configFile);
|
||||
std::ofstream o(p.string());
|
||||
o << detail::configContents("", "");
|
||||
o.close();
|
||||
|
||||
// Load the config file from the config directory and verify it.
|
||||
Config c;
|
||||
c.setup("", true, false, true);
|
||||
BEAST_EXPECT(
|
||||
c.section(SECTION_DEBUG_LOGFILE).values().size() == 1);
|
||||
BEAST_EXPECT(
|
||||
c.section(SECTION_DEBUG_LOGFILE).values()[0] ==
|
||||
"/Users/dummy/xrpld/config/log/debug.log");
|
||||
|
||||
// Restore the environment variables.
|
||||
h ? setenv("HOME", h, 1) : unsetenv("HOME");
|
||||
x ? setenv("XDG_CONFIG_HOME", x, 1)
|
||||
: unsetenv("XDG_CONFIG_HOME");
|
||||
}
|
||||
|
||||
// The XDG config directory is not set: the config file must be in a
|
||||
// subdirectory named .config followed by the system name.
|
||||
{
|
||||
beast::temp_dir tc;
|
||||
|
||||
// Set only the HOME environment variable.
|
||||
char const* h = getenv("HOME");
|
||||
setenv("HOME", tc.path().c_str(), 1);
|
||||
char const* x = getenv("XDG_CONFIG_HOME");
|
||||
unsetenv("XDG_CONFIG_HOME");
|
||||
|
||||
// Create the config file in '${HOME}/.config/[systemName]'.
|
||||
std::string s = ".config";
|
||||
path p = tc.file(s);
|
||||
create_directory(p);
|
||||
s += "/" + systemName();
|
||||
p = tc.file(s);
|
||||
create_directory(p);
|
||||
p = tc.file(s + "/" + configFile);
|
||||
std::ofstream o(p.string());
|
||||
o << detail::configContents("", "");
|
||||
o.close();
|
||||
|
||||
// Load the config file from the config directory and verify it.
|
||||
Config c;
|
||||
c.setup("", true, false, true);
|
||||
BEAST_EXPECT(
|
||||
c.section(SECTION_DEBUG_LOGFILE).values().size() == 1);
|
||||
BEAST_EXPECT(
|
||||
c.section(SECTION_DEBUG_LOGFILE).values()[0] ==
|
||||
"/Users/dummy/xrpld/config/log/debug.log");
|
||||
|
||||
// Restore the environment variables.
|
||||
h ? setenv("HOME", h, 1) : unsetenv("HOME");
|
||||
if (x)
|
||||
setenv("XDG_CONFIG_HOME", x, 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Restore the current working directory.
|
||||
current_path(cwd);
|
||||
}
|
||||
void
|
||||
testDbPath()
|
||||
{
|
||||
testcase("database_path");
|
||||
@@ -326,11 +448,16 @@ port_wss_admin
|
||||
{
|
||||
// read from file absolute path
|
||||
auto const cwd = current_path();
|
||||
xrpl::detail::DirGuard const g0(*this, "test_db");
|
||||
detail::DirGuard const g0(*this, "test_db");
|
||||
path const dataDirRel("test_data_dir");
|
||||
path const dataDirAbs(cwd / g0.subdir() / dataDirRel);
|
||||
detail::RippledCfgGuard const g(
|
||||
*this, g0.subdir(), dataDirAbs, "", false);
|
||||
detail::FileCfgGuard const g(
|
||||
*this,
|
||||
g0.subdir(),
|
||||
dataDirAbs,
|
||||
Config::configFileName,
|
||||
"",
|
||||
false);
|
||||
auto const& c(g.config());
|
||||
BEAST_EXPECT(g.dataDirExists());
|
||||
BEAST_EXPECT(g.configFileExists());
|
||||
@@ -339,7 +466,8 @@ port_wss_admin
|
||||
{
|
||||
// read from file relative path
|
||||
std::string const dbPath("my_db");
|
||||
detail::RippledCfgGuard const g(*this, "test_db", dbPath, "");
|
||||
detail::FileCfgGuard const g(
|
||||
*this, "test_db", dbPath, Config::configFileName, "");
|
||||
auto const& c(g.config());
|
||||
std::string const nativeDbPath = absolute(path(dbPath)).string();
|
||||
BEAST_EXPECT(g.dataDirExists());
|
||||
@@ -348,7 +476,8 @@ port_wss_admin
|
||||
}
|
||||
{
|
||||
// read from file no path
|
||||
detail::RippledCfgGuard const g(*this, "test_db", "", "");
|
||||
detail::FileCfgGuard const g(
|
||||
*this, "test_db", "", Config::configFileName, "");
|
||||
auto const& c(g.config());
|
||||
std::string const nativeDbPath =
|
||||
absolute(g.subdir() / path(Config::databaseDirName)).string();
|
||||
@@ -378,13 +507,13 @@ port_wss_admin
|
||||
|
||||
{
|
||||
Config c;
|
||||
static boost::format configTemplate(R"rippleConfig(
|
||||
static boost::format configTemplate(R"xrpldConfig(
|
||||
[validation_seed]
|
||||
%1%
|
||||
|
||||
[validator_token]
|
||||
%2%
|
||||
)rippleConfig");
|
||||
)xrpldConfig");
|
||||
std::string error;
|
||||
auto const expectedError =
|
||||
"Cannot have both [validation_seed] "
|
||||
@@ -410,10 +539,10 @@ port_wss_admin
|
||||
Config c;
|
||||
try
|
||||
{
|
||||
c.loadFromString(R"rippleConfig(
|
||||
c.loadFromString(R"xrpldConfig(
|
||||
[network_id]
|
||||
main
|
||||
)rippleConfig");
|
||||
)xrpldConfig");
|
||||
}
|
||||
catch (std::runtime_error& e)
|
||||
{
|
||||
@@ -425,8 +554,8 @@ main
|
||||
|
||||
try
|
||||
{
|
||||
c.loadFromString(R"rippleConfig(
|
||||
)rippleConfig");
|
||||
c.loadFromString(R"xrpldConfig(
|
||||
)xrpldConfig");
|
||||
}
|
||||
catch (std::runtime_error& e)
|
||||
{
|
||||
@@ -438,10 +567,10 @@ main
|
||||
|
||||
try
|
||||
{
|
||||
c.loadFromString(R"rippleConfig(
|
||||
c.loadFromString(R"xrpldConfig(
|
||||
[network_id]
|
||||
255
|
||||
)rippleConfig");
|
||||
)xrpldConfig");
|
||||
}
|
||||
catch (std::runtime_error& e)
|
||||
{
|
||||
@@ -453,10 +582,10 @@ main
|
||||
|
||||
try
|
||||
{
|
||||
c.loadFromString(R"rippleConfig(
|
||||
c.loadFromString(R"xrpldConfig(
|
||||
[network_id]
|
||||
10000
|
||||
)rippleConfig");
|
||||
)xrpldConfig");
|
||||
}
|
||||
catch (std::runtime_error& e)
|
||||
{
|
||||
@@ -516,7 +645,7 @@ main
|
||||
{
|
||||
// load validators from config into single section
|
||||
Config c;
|
||||
std::string toLoad(R"rippleConfig(
|
||||
std::string toLoad(R"xrpldConfig(
|
||||
[validators]
|
||||
n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7
|
||||
n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj
|
||||
@@ -525,7 +654,7 @@ n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C
|
||||
[validator_keys]
|
||||
nHUhG1PgAG8H8myUENypM35JgfqXAKNQvRVVAFDRzJrny5eZN8d5
|
||||
nHBu9PTL9dn2GuZtdW4U2WzBwffyX9qsQCd9CNU4Z5YG3PQfViM8
|
||||
)rippleConfig");
|
||||
)xrpldConfig");
|
||||
c.loadFromString(toLoad);
|
||||
BEAST_EXPECT(c.legacy("validators_file").empty());
|
||||
BEAST_EXPECT(c.section(SECTION_VALIDATORS).values().size() == 5);
|
||||
@@ -534,9 +663,9 @@ nHBu9PTL9dn2GuZtdW4U2WzBwffyX9qsQCd9CNU4Z5YG3PQfViM8
|
||||
{
|
||||
// load validator list sites and keys from config
|
||||
Config c;
|
||||
std::string toLoad(R"rippleConfig(
|
||||
std::string toLoad(R"xrpldConfig(
|
||||
[validator_list_sites]
|
||||
ripplevalidators.com
|
||||
xrplvalidators.com
|
||||
trustthesevalidators.gov
|
||||
|
||||
[validator_list_keys]
|
||||
@@ -544,13 +673,13 @@ trustthesevalidators.gov
|
||||
|
||||
[validator_list_threshold]
|
||||
1
|
||||
)rippleConfig");
|
||||
)xrpldConfig");
|
||||
c.loadFromString(toLoad);
|
||||
BEAST_EXPECT(
|
||||
c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
|
||||
BEAST_EXPECT(
|
||||
c.section(SECTION_VALIDATOR_LIST_SITES).values()[0] ==
|
||||
"ripplevalidators.com");
|
||||
"xrplvalidators.com");
|
||||
BEAST_EXPECT(
|
||||
c.section(SECTION_VALIDATOR_LIST_SITES).values()[1] ==
|
||||
"trustthesevalidators.gov");
|
||||
@@ -570,9 +699,9 @@ trustthesevalidators.gov
|
||||
{
|
||||
// load validator list sites and keys from config
|
||||
Config c;
|
||||
std::string toLoad(R"rippleConfig(
|
||||
std::string toLoad(R"xrpldConfig(
|
||||
[validator_list_sites]
|
||||
ripplevalidators.com
|
||||
xrplvalidators.com
|
||||
trustthesevalidators.gov
|
||||
|
||||
[validator_list_keys]
|
||||
@@ -580,13 +709,13 @@ trustthesevalidators.gov
|
||||
|
||||
[validator_list_threshold]
|
||||
0
|
||||
)rippleConfig");
|
||||
)xrpldConfig");
|
||||
c.loadFromString(toLoad);
|
||||
BEAST_EXPECT(
|
||||
c.section(SECTION_VALIDATOR_LIST_SITES).values().size() == 2);
|
||||
BEAST_EXPECT(
|
||||
c.section(SECTION_VALIDATOR_LIST_SITES).values()[0] ==
|
||||
"ripplevalidators.com");
|
||||
"xrplvalidators.com");
|
||||
BEAST_EXPECT(
|
||||
c.section(SECTION_VALIDATOR_LIST_SITES).values()[1] ==
|
||||
"trustthesevalidators.gov");
|
||||
@@ -607,9 +736,9 @@ trustthesevalidators.gov
|
||||
// load should throw if [validator_list_threshold] is greater than
|
||||
// the number of [validator_list_keys]
|
||||
Config c;
|
||||
std::string toLoad(R"rippleConfig(
|
||||
std::string toLoad(R"xrpldConfig(
|
||||
[validator_list_sites]
|
||||
ripplevalidators.com
|
||||
xrplvalidators.com
|
||||
trustthesevalidators.gov
|
||||
|
||||
[validator_list_keys]
|
||||
@@ -617,7 +746,7 @@ trustthesevalidators.gov
|
||||
|
||||
[validator_list_threshold]
|
||||
2
|
||||
)rippleConfig");
|
||||
)xrpldConfig");
|
||||
std::string error;
|
||||
auto const expectedError =
|
||||
"Value in config section [validator_list_threshold] exceeds "
|
||||
@@ -636,9 +765,9 @@ trustthesevalidators.gov
|
||||
{
|
||||
// load should throw if [validator_list_threshold] is malformed
|
||||
Config c;
|
||||
std::string toLoad(R"rippleConfig(
|
||||
std::string toLoad(R"xrpldConfig(
|
||||
[validator_list_sites]
|
||||
ripplevalidators.com
|
||||
xrplvalidators.com
|
||||
trustthesevalidators.gov
|
||||
|
||||
[validator_list_keys]
|
||||
@@ -646,7 +775,7 @@ trustthesevalidators.gov
|
||||
|
||||
[validator_list_threshold]
|
||||
value = 2
|
||||
)rippleConfig");
|
||||
)xrpldConfig");
|
||||
std::string error;
|
||||
auto const expectedError =
|
||||
"Config section [validator_list_threshold] should contain "
|
||||
@@ -665,9 +794,9 @@ value = 2
|
||||
{
|
||||
// load should throw if [validator_list_threshold] is negative
|
||||
Config c;
|
||||
std::string toLoad(R"rippleConfig(
|
||||
std::string toLoad(R"xrpldConfig(
|
||||
[validator_list_sites]
|
||||
ripplevalidators.com
|
||||
xrplvalidators.com
|
||||
trustthesevalidators.gov
|
||||
|
||||
[validator_list_keys]
|
||||
@@ -675,7 +804,7 @@ trustthesevalidators.gov
|
||||
|
||||
[validator_list_threshold]
|
||||
-1
|
||||
)rippleConfig");
|
||||
)xrpldConfig");
|
||||
bool error = false;
|
||||
try
|
||||
{
|
||||
@@ -692,11 +821,11 @@ trustthesevalidators.gov
|
||||
// load should throw if [validator_list_sites] is configured but
|
||||
// [validator_list_keys] is not
|
||||
Config c;
|
||||
std::string toLoad(R"rippleConfig(
|
||||
std::string toLoad(R"xrpldConfig(
|
||||
[validator_list_sites]
|
||||
ripplevalidators.com
|
||||
xrplvalidators.com
|
||||
trustthesevalidators.gov
|
||||
)rippleConfig");
|
||||
)xrpldConfig");
|
||||
std::string error;
|
||||
auto const expectedError =
|
||||
"[validator_list_keys] config section is missing";
|
||||
@@ -736,8 +865,13 @@ trustthesevalidators.gov
|
||||
std::string const valFileName = "validators.txt";
|
||||
detail::ValidatorsTxtGuard const vtg(
|
||||
*this, "test_cfg", valFileName);
|
||||
detail::RippledCfgGuard const rcg(
|
||||
*this, vtg.subdir(), "", valFileName, false);
|
||||
detail::FileCfgGuard const rcg(
|
||||
*this,
|
||||
vtg.subdir(),
|
||||
"",
|
||||
Config::configFileName,
|
||||
valFileName,
|
||||
false);
|
||||
BEAST_EXPECT(vtg.validatorsFileExists());
|
||||
BEAST_EXPECT(rcg.configFileExists());
|
||||
auto const& c(rcg.config());
|
||||
@@ -758,8 +892,13 @@ trustthesevalidators.gov
|
||||
detail::ValidatorsTxtGuard const vtg(
|
||||
*this, "test_cfg", "validators.txt");
|
||||
auto const valFilePath = ".." / vtg.subdir() / "validators.txt";
|
||||
detail::RippledCfgGuard const rcg(
|
||||
*this, vtg.subdir(), "", valFilePath, false);
|
||||
detail::FileCfgGuard const rcg(
|
||||
*this,
|
||||
vtg.subdir(),
|
||||
"",
|
||||
Config::configFileName,
|
||||
valFilePath,
|
||||
false);
|
||||
BEAST_EXPECT(vtg.validatorsFileExists());
|
||||
BEAST_EXPECT(rcg.configFileExists());
|
||||
auto const& c(rcg.config());
|
||||
@@ -778,8 +917,8 @@ trustthesevalidators.gov
|
||||
// load from validators file in default location
|
||||
detail::ValidatorsTxtGuard const vtg(
|
||||
*this, "test_cfg", "validators.txt");
|
||||
detail::RippledCfgGuard const rcg(
|
||||
*this, vtg.subdir(), "", "", false);
|
||||
detail::FileCfgGuard const rcg(
|
||||
*this, vtg.subdir(), "", Config::configFileName, "", false);
|
||||
BEAST_EXPECT(vtg.validatorsFileExists());
|
||||
BEAST_EXPECT(rcg.configFileExists());
|
||||
auto const& c(rcg.config());
|
||||
@@ -803,8 +942,13 @@ trustthesevalidators.gov
|
||||
detail::ValidatorsTxtGuard const vtgDefault(
|
||||
*this, vtg.subdir(), "validators.txt", false);
|
||||
BEAST_EXPECT(vtgDefault.validatorsFileExists());
|
||||
detail::RippledCfgGuard const rcg(
|
||||
*this, vtg.subdir(), "", vtg.validatorsFile(), false);
|
||||
detail::FileCfgGuard const rcg(
|
||||
*this,
|
||||
vtg.subdir(),
|
||||
"",
|
||||
Config::configFileName,
|
||||
vtg.validatorsFile(),
|
||||
false);
|
||||
BEAST_EXPECT(rcg.configFileExists());
|
||||
auto const& c(rcg.config());
|
||||
BEAST_EXPECT(c.legacy("validators_file") == vtg.validatorsFile());
|
||||
@@ -821,7 +965,7 @@ trustthesevalidators.gov
|
||||
|
||||
{
|
||||
// load validators from both config and validators file
|
||||
boost::format cc(R"rippleConfig(
|
||||
boost::format cc(R"xrpldConfig(
|
||||
[validators_file]
|
||||
%1%
|
||||
|
||||
@@ -837,12 +981,12 @@ nHB1X37qrniVugfQcuBTAjswphC1drx7QjFFojJPZwKHHnt8kU7v
|
||||
nHUkAWDR4cB8AgPg7VXMX6et8xRTQb2KJfgv1aBEXozwrawRKgMB
|
||||
|
||||
[validator_list_sites]
|
||||
ripplevalidators.com
|
||||
xrplvalidators.com
|
||||
trustthesevalidators.gov
|
||||
|
||||
[validator_list_keys]
|
||||
021A99A537FDEBC34E4FCA03B39BEADD04299BB19E85097EC92B15A3518801E566
|
||||
)rippleConfig");
|
||||
)xrpldConfig");
|
||||
detail::ValidatorsTxtGuard const vtg(
|
||||
*this, "test_cfg", "validators.cfg");
|
||||
BEAST_EXPECT(vtg.validatorsFileExists());
|
||||
@@ -861,14 +1005,14 @@ trustthesevalidators.gov
|
||||
}
|
||||
{
|
||||
// load should throw if [validator_list_threshold] is present both
|
||||
// in rippled cfg and validators file
|
||||
boost::format cc(R"rippleConfig(
|
||||
// in xrpld.cfg and validators file
|
||||
boost::format cc(R"xrpldConfig(
|
||||
[validators_file]
|
||||
%1%
|
||||
|
||||
[validator_list_threshold]
|
||||
1
|
||||
)rippleConfig");
|
||||
)xrpldConfig");
|
||||
std::string error;
|
||||
detail::ValidatorsTxtGuard const vtg(
|
||||
*this, "test_cfg", "validators.cfg");
|
||||
@@ -890,7 +1034,7 @@ trustthesevalidators.gov
|
||||
}
|
||||
{
|
||||
// load should throw if [validators], [validator_keys] and
|
||||
// [validator_list_keys] are missing from rippled cfg and
|
||||
// [validator_list_keys] are missing from xrpld.cfg and
|
||||
// validators file
|
||||
Config c;
|
||||
boost::format cc("[validators_file]\n%1%\n");
|
||||
@@ -920,9 +1064,13 @@ trustthesevalidators.gov
|
||||
void
|
||||
testSetup(bool explicitPath)
|
||||
{
|
||||
detail::RippledCfgGuard const cfg(
|
||||
*this, "testSetup", explicitPath ? "test_db" : "", "");
|
||||
/* RippledCfgGuard has a Config object that gets loaded on
|
||||
detail::FileCfgGuard const cfg(
|
||||
*this,
|
||||
"testSetup",
|
||||
explicitPath ? "test_db" : "",
|
||||
Config::configFileName,
|
||||
"");
|
||||
/* FileCfgGuard has a Config object that gets loaded on
|
||||
construction, but Config::setup is not reentrant, so we
|
||||
need a fresh config for every test case, so ignore it.
|
||||
*/
|
||||
@@ -1039,7 +1187,8 @@ trustthesevalidators.gov
|
||||
void
|
||||
testPort()
|
||||
{
|
||||
detail::RippledCfgGuard const cfg(*this, "testPort", "", "");
|
||||
detail::FileCfgGuard const cfg(
|
||||
*this, "testPort", "", Config::configFileName, "");
|
||||
auto const& conf = cfg.config();
|
||||
if (!BEAST_EXPECT(conf.exists("port_rpc")))
|
||||
return;
|
||||
@@ -1065,8 +1214,14 @@ trustthesevalidators.gov
|
||||
|
||||
try
|
||||
{
|
||||
detail::RippledCfgGuard const cfg(
|
||||
*this, "testPort", "", "", true, contents);
|
||||
detail::FileCfgGuard const cfg(
|
||||
*this,
|
||||
"testPort",
|
||||
"",
|
||||
Config::configFileName,
|
||||
"",
|
||||
true,
|
||||
contents);
|
||||
BEAST_EXPECT(false);
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
@@ -1377,9 +1532,9 @@ r.ripple.com:51235
|
||||
for (auto& [unit, sec, val, shouldPass] : units)
|
||||
{
|
||||
Config c;
|
||||
std::string toLoad(R"rippleConfig(
|
||||
std::string toLoad(R"xrpldConfig(
|
||||
[amendment_majority_time]
|
||||
)rippleConfig");
|
||||
)xrpldConfig");
|
||||
toLoad += std::to_string(val) + space + unit;
|
||||
space = space == "" ? " " : "";
|
||||
|
||||
@@ -1480,6 +1635,7 @@ r.ripple.com:51235
|
||||
run() override
|
||||
{
|
||||
testLegacy();
|
||||
testConfigFile();
|
||||
testDbPath();
|
||||
testValidatorKeys();
|
||||
testValidatorsFile();
|
||||
|
||||
@@ -30,6 +30,7 @@ enum class FieldType {
|
||||
CurrencyField,
|
||||
HashField,
|
||||
HashOrObjectField,
|
||||
IssueField,
|
||||
ObjectField,
|
||||
StringField,
|
||||
TwoAccountArrayField,
|
||||
@@ -40,6 +41,8 @@ enum class FieldType {
|
||||
std::vector<std::pair<Json::StaticString, FieldType>> mappings{
|
||||
{jss::account, FieldType::AccountField},
|
||||
{jss::accounts, FieldType::TwoAccountArrayField},
|
||||
{jss::asset, FieldType::IssueField},
|
||||
{jss::asset2, FieldType::IssueField},
|
||||
{jss::authorize, FieldType::AccountField},
|
||||
{jss::authorized, FieldType::AccountField},
|
||||
{jss::credential_type, FieldType::BlobField},
|
||||
@@ -74,24 +77,26 @@ getTypeName(FieldType typeID)
|
||||
{
|
||||
switch (typeID)
|
||||
{
|
||||
case FieldType::UInt32Field:
|
||||
return "number";
|
||||
case FieldType::UInt64Field:
|
||||
return "number";
|
||||
case FieldType::HashField:
|
||||
return "hex string";
|
||||
case FieldType::AccountField:
|
||||
return "AccountID";
|
||||
case FieldType::ArrayField:
|
||||
return "array";
|
||||
case FieldType::BlobField:
|
||||
return "hex string";
|
||||
case FieldType::CurrencyField:
|
||||
return "Currency";
|
||||
case FieldType::ArrayField:
|
||||
return "array";
|
||||
case FieldType::HashField:
|
||||
return "hex string";
|
||||
case FieldType::HashOrObjectField:
|
||||
return "hex string or object";
|
||||
case FieldType::IssueField:
|
||||
return "Issue";
|
||||
case FieldType::TwoAccountArrayField:
|
||||
return "length-2 array of Accounts";
|
||||
case FieldType::UInt32Field:
|
||||
return "number";
|
||||
case FieldType::UInt64Field:
|
||||
return "number";
|
||||
default:
|
||||
Throw<std::runtime_error>(
|
||||
"unknown type " + std::to_string(static_cast<uint8_t>(typeID)));
|
||||
@@ -192,34 +197,37 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
return values;
|
||||
};
|
||||
|
||||
static auto const& badUInt32Values = remove({2, 3});
|
||||
static auto const& badUInt64Values = remove({2, 3});
|
||||
static auto const& badHashValues = remove({2, 3, 7, 8, 16});
|
||||
static auto const& badAccountValues = remove({12});
|
||||
static auto const& badArrayValues = remove({17, 20});
|
||||
static auto const& badBlobValues = remove({3, 7, 8, 16});
|
||||
static auto const& badCurrencyValues = remove({14});
|
||||
static auto const& badArrayValues = remove({17, 20});
|
||||
static auto const& badHashValues = remove({2, 3, 7, 8, 16});
|
||||
static auto const& badIndexValues = remove({12, 16, 18, 19});
|
||||
static auto const& badUInt32Values = remove({2, 3});
|
||||
static auto const& badUInt64Values = remove({2, 3});
|
||||
static auto const& badIssueValues = remove({});
|
||||
|
||||
switch (fieldType)
|
||||
{
|
||||
case FieldType::UInt32Field:
|
||||
return badUInt32Values;
|
||||
case FieldType::UInt64Field:
|
||||
return badUInt64Values;
|
||||
case FieldType::HashField:
|
||||
return badHashValues;
|
||||
case FieldType::AccountField:
|
||||
return badAccountValues;
|
||||
case FieldType::ArrayField:
|
||||
case FieldType::TwoAccountArrayField:
|
||||
return badArrayValues;
|
||||
case FieldType::BlobField:
|
||||
return badBlobValues;
|
||||
case FieldType::CurrencyField:
|
||||
return badCurrencyValues;
|
||||
case FieldType::ArrayField:
|
||||
case FieldType::TwoAccountArrayField:
|
||||
return badArrayValues;
|
||||
case FieldType::HashField:
|
||||
return badHashValues;
|
||||
case FieldType::HashOrObjectField:
|
||||
return badIndexValues;
|
||||
case FieldType::IssueField:
|
||||
return badIssueValues;
|
||||
case FieldType::UInt32Field:
|
||||
return badUInt32Values;
|
||||
case FieldType::UInt64Field:
|
||||
return badUInt64Values;
|
||||
default:
|
||||
Throw<std::runtime_error>(
|
||||
"unknown type " +
|
||||
@@ -236,30 +244,37 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
arr[1u] = "r4MrUGTdB57duTnRs6KbsRGQXgkseGb1b5";
|
||||
return arr;
|
||||
}();
|
||||
static Json::Value const issueObject = []() {
|
||||
Json::Value arr(Json::objectValue);
|
||||
arr[jss::currency] = "XRP";
|
||||
return arr;
|
||||
}();
|
||||
|
||||
auto const typeID = getFieldType(fieldName);
|
||||
switch (typeID)
|
||||
{
|
||||
case FieldType::UInt32Field:
|
||||
return 1;
|
||||
case FieldType::UInt64Field:
|
||||
return 1;
|
||||
case FieldType::HashField:
|
||||
return "5233D68B4D44388F98559DE42903767803EFA7C1F8D01413FC16EE6"
|
||||
"B01403D6D";
|
||||
case FieldType::AccountField:
|
||||
return "r4MrUGTdB57duTnRs6KbsRGQXgkseGb1b5";
|
||||
case FieldType::ArrayField:
|
||||
return Json::arrayValue;
|
||||
case FieldType::BlobField:
|
||||
return "ABCDEF";
|
||||
case FieldType::CurrencyField:
|
||||
return "USD";
|
||||
case FieldType::ArrayField:
|
||||
return Json::arrayValue;
|
||||
case FieldType::HashField:
|
||||
return "5233D68B4D44388F98559DE42903767803EFA7C1F8D01413FC16EE6"
|
||||
"B01403D6D";
|
||||
case FieldType::IssueField:
|
||||
return issueObject;
|
||||
case FieldType::HashOrObjectField:
|
||||
return "5233D68B4D44388F98559DE42903767803EFA7C1F8D01413FC16EE6"
|
||||
"B01403D6D";
|
||||
case FieldType::TwoAccountArrayField:
|
||||
return twoAccountArray;
|
||||
case FieldType::UInt32Field:
|
||||
return 1;
|
||||
case FieldType::UInt64Field:
|
||||
return 1;
|
||||
default:
|
||||
Throw<std::runtime_error>(
|
||||
"unknown type " +
|
||||
@@ -444,7 +459,7 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryInvalid()
|
||||
testInvalid()
|
||||
{
|
||||
testcase("Invalid requests");
|
||||
using namespace test::jtx;
|
||||
@@ -526,7 +541,7 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryAccountRoot()
|
||||
testAccountRoot()
|
||||
{
|
||||
testcase("AccountRoot");
|
||||
using namespace test::jtx;
|
||||
@@ -632,7 +647,147 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryCheck()
|
||||
testAmendments()
|
||||
{
|
||||
testcase("Amendments");
|
||||
using namespace test::jtx;
|
||||
Env env{*this};
|
||||
|
||||
// positive test
|
||||
{
|
||||
Keylet const keylet = keylet::amendments();
|
||||
|
||||
// easier to hack an object into the ledger than generate it
|
||||
// legitimately
|
||||
{
|
||||
auto const amendments = [&](OpenView& view,
|
||||
beast::Journal) -> bool {
|
||||
auto const sle = std::make_shared<SLE>(keylet);
|
||||
|
||||
// Create Amendments vector (enabled amendments)
|
||||
std::vector<uint256> enabledAmendments;
|
||||
enabledAmendments.push_back(
|
||||
uint256::fromVoid("42426C4D4F1009EE67080A9B7965B44656D7"
|
||||
"714D104A72F9B4369F97ABF044EE"));
|
||||
enabledAmendments.push_back(
|
||||
uint256::fromVoid("4C97EBA926031A7CF7D7B36FDE3ED66DDA54"
|
||||
"21192D63DE53FFB46E43B9DC8373"));
|
||||
enabledAmendments.push_back(
|
||||
uint256::fromVoid("03BDC0099C4E14163ADA272C1B6F6FABB448"
|
||||
"CC3E51F522F978041E4B57D9158C"));
|
||||
enabledAmendments.push_back(
|
||||
uint256::fromVoid("35291ADD2D79EB6991343BDA0912269C817D"
|
||||
"0F094B02226C1C14AD2858962ED4"));
|
||||
sle->setFieldV256(
|
||||
sfAmendments, STVector256(enabledAmendments));
|
||||
|
||||
// Create Majorities array
|
||||
STArray majorities;
|
||||
|
||||
auto majority1 = STObject::makeInnerObject(sfMajority);
|
||||
majority1.setFieldH256(
|
||||
sfAmendment,
|
||||
uint256::fromVoid("7BB62DC13EC72B775091E9C71BF8CF97E122"
|
||||
"647693B50C5E87A80DFD6FCFAC50"));
|
||||
majority1.setFieldU32(sfCloseTime, 779561310);
|
||||
majorities.push_back(std::move(majority1));
|
||||
|
||||
auto majority2 = STObject::makeInnerObject(sfMajority);
|
||||
majority2.setFieldH256(
|
||||
sfAmendment,
|
||||
uint256::fromVoid("755C971C29971C9F20C6F080F2ED96F87884"
|
||||
"E40AD19554A5EBECDCEC8A1F77FE"));
|
||||
majority2.setFieldU32(sfCloseTime, 779561310);
|
||||
majorities.push_back(std::move(majority2));
|
||||
|
||||
sle->setFieldArray(sfMajorities, majorities);
|
||||
|
||||
view.rawInsert(sle);
|
||||
return true;
|
||||
};
|
||||
env.app().openLedger().modify(amendments);
|
||||
}
|
||||
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::amendments] = to_string(keylet.key);
|
||||
Json::Value const jrr = env.rpc(
|
||||
"json", "ledger_entry", to_string(jvParams))[jss::result];
|
||||
BEAST_EXPECT(
|
||||
jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Amendments);
|
||||
}
|
||||
|
||||
// negative tests
|
||||
runLedgerEntryTest(env, jss::amendments);
|
||||
}
|
||||
|
||||
void
|
||||
testAMM()
|
||||
{
|
||||
testcase("AMM");
|
||||
using namespace test::jtx;
|
||||
Env env{*this};
|
||||
|
||||
// positive test
|
||||
Account const alice{"alice"};
|
||||
env.fund(XRP(10000), alice);
|
||||
env.close();
|
||||
AMM amm(env, alice, XRP(10), alice["USD"](1000));
|
||||
env.close();
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::amm] = to_string(amm.ammID());
|
||||
auto const result =
|
||||
env.rpc("json", "ledger_entry", to_string(jvParams));
|
||||
BEAST_EXPECT(
|
||||
result.isObject() && result.isMember(jss::result) &&
|
||||
!result[jss::result].isMember(jss::error) &&
|
||||
result[jss::result].isMember(jss::node) &&
|
||||
result[jss::result][jss::node].isMember(
|
||||
sfLedgerEntryType.jsonName) &&
|
||||
result[jss::result][jss::node][sfLedgerEntryType.jsonName] ==
|
||||
jss::AMM);
|
||||
}
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
Json::Value ammParams(Json::objectValue);
|
||||
{
|
||||
Json::Value obj(Json::objectValue);
|
||||
obj[jss::currency] = "XRP";
|
||||
ammParams[jss::asset] = obj;
|
||||
}
|
||||
{
|
||||
Json::Value obj(Json::objectValue);
|
||||
obj[jss::currency] = "USD";
|
||||
obj[jss::issuer] = alice.human();
|
||||
ammParams[jss::asset2] = obj;
|
||||
}
|
||||
jvParams[jss::amm] = ammParams;
|
||||
auto const result =
|
||||
env.rpc("json", "ledger_entry", to_string(jvParams));
|
||||
BEAST_EXPECT(
|
||||
result.isObject() && result.isMember(jss::result) &&
|
||||
!result[jss::result].isMember(jss::error) &&
|
||||
result[jss::result].isMember(jss::node) &&
|
||||
result[jss::result][jss::node].isMember(
|
||||
sfLedgerEntryType.jsonName) &&
|
||||
result[jss::result][jss::node][sfLedgerEntryType.jsonName] ==
|
||||
jss::AMM);
|
||||
}
|
||||
|
||||
// negative tests
|
||||
runLedgerEntryTest(
|
||||
env,
|
||||
jss::amm,
|
||||
{
|
||||
{jss::asset, "malformedRequest"},
|
||||
{jss::asset2, "malformedRequest"},
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
testCheck()
|
||||
{
|
||||
testcase("Check");
|
||||
using namespace test::jtx;
|
||||
@@ -684,7 +839,7 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryCredentials()
|
||||
testCredentials()
|
||||
{
|
||||
testcase("Credentials");
|
||||
|
||||
@@ -752,7 +907,7 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryDelegate()
|
||||
testDelegate()
|
||||
{
|
||||
testcase("Delegate");
|
||||
|
||||
@@ -807,7 +962,7 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryDepositPreauth()
|
||||
testDepositPreauth()
|
||||
{
|
||||
testcase("Deposit Preauth");
|
||||
|
||||
@@ -868,7 +1023,7 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryDepositPreauthCred()
|
||||
testDepositPreauthCred()
|
||||
{
|
||||
testcase("Deposit Preauth with credentials");
|
||||
|
||||
@@ -1149,7 +1304,7 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryDirectory()
|
||||
testDirectory()
|
||||
{
|
||||
testcase("Directory");
|
||||
using namespace test::jtx;
|
||||
@@ -1303,7 +1458,7 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryEscrow()
|
||||
testEscrow()
|
||||
{
|
||||
testcase("Escrow");
|
||||
using namespace test::jtx;
|
||||
@@ -1365,7 +1520,177 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryOffer()
|
||||
testFeeSettings()
|
||||
{
|
||||
testcase("Fee Settings");
|
||||
using namespace test::jtx;
|
||||
Env env{*this};
|
||||
|
||||
// positive test
|
||||
{
|
||||
Keylet const keylet = keylet::fees();
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::fee] = to_string(keylet.key);
|
||||
Json::Value const jrr = env.rpc(
|
||||
"json", "ledger_entry", to_string(jvParams))[jss::result];
|
||||
BEAST_EXPECT(
|
||||
jrr[jss::node][sfLedgerEntryType.jsonName] == jss::FeeSettings);
|
||||
}
|
||||
|
||||
// negative tests
|
||||
runLedgerEntryTest(env, jss::fee);
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerHashes()
|
||||
{
|
||||
testcase("Ledger Hashes");
|
||||
using namespace test::jtx;
|
||||
Env env{*this};
|
||||
|
||||
// positive test
|
||||
{
|
||||
Keylet const keylet = keylet::skip();
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::hashes] = to_string(keylet.key);
|
||||
Json::Value const jrr = env.rpc(
|
||||
"json", "ledger_entry", to_string(jvParams))[jss::result];
|
||||
BEAST_EXPECT(
|
||||
jrr[jss::node][sfLedgerEntryType.jsonName] ==
|
||||
jss::LedgerHashes);
|
||||
}
|
||||
|
||||
// negative tests
|
||||
runLedgerEntryTest(env, jss::hashes);
|
||||
}
|
||||
|
||||
void
|
||||
testNFTokenOffer()
|
||||
{
|
||||
testcase("NFT Offer");
|
||||
using namespace test::jtx;
|
||||
Env env{*this};
|
||||
|
||||
// positive test
|
||||
Account const issuer{"issuer"};
|
||||
Account const buyer{"buyer"};
|
||||
env.fund(XRP(1000), issuer, buyer);
|
||||
|
||||
uint256 const nftokenID0 =
|
||||
token::getNextID(env, issuer, 0, tfTransferable);
|
||||
env(token::mint(issuer, 0), txflags(tfTransferable));
|
||||
env.close();
|
||||
uint256 const offerID = keylet::nftoffer(issuer, env.seq(issuer)).key;
|
||||
env(token::createOffer(issuer, nftokenID0, drops(1)),
|
||||
token::destination(buyer),
|
||||
txflags(tfSellNFToken));
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::nft_offer] = to_string(offerID);
|
||||
Json::Value const jrr = env.rpc(
|
||||
"json", "ledger_entry", to_string(jvParams))[jss::result];
|
||||
BEAST_EXPECT(
|
||||
jrr[jss::node][sfLedgerEntryType.jsonName] ==
|
||||
jss::NFTokenOffer);
|
||||
BEAST_EXPECT(jrr[jss::node][sfOwner.jsonName] == issuer.human());
|
||||
BEAST_EXPECT(
|
||||
jrr[jss::node][sfNFTokenID.jsonName] == to_string(nftokenID0));
|
||||
BEAST_EXPECT(jrr[jss::node][sfAmount.jsonName] == "1");
|
||||
}
|
||||
|
||||
// negative tests
|
||||
runLedgerEntryTest(env, jss::nft_offer);
|
||||
}
|
||||
|
||||
void
|
||||
testNFTokenPage()
|
||||
{
|
||||
testcase("NFT Page");
|
||||
using namespace test::jtx;
|
||||
Env env{*this};
|
||||
|
||||
// positive test
|
||||
Account const issuer{"issuer"};
|
||||
env.fund(XRP(1000), issuer);
|
||||
|
||||
env(token::mint(issuer, 0), txflags(tfTransferable));
|
||||
env.close();
|
||||
|
||||
auto const nftpage = keylet::nftpage_max(issuer);
|
||||
BEAST_EXPECT(env.le(nftpage) != nullptr);
|
||||
|
||||
{
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::nft_page] = to_string(nftpage.key);
|
||||
Json::Value const jrr = env.rpc(
|
||||
"json", "ledger_entry", to_string(jvParams))[jss::result];
|
||||
BEAST_EXPECT(
|
||||
jrr[jss::node][sfLedgerEntryType.jsonName] == jss::NFTokenPage);
|
||||
}
|
||||
|
||||
// negative tests
|
||||
runLedgerEntryTest(env, jss::nft_page);
|
||||
}
|
||||
|
||||
void
|
||||
testNegativeUNL()
|
||||
{
|
||||
testcase("Negative UNL");
|
||||
using namespace test::jtx;
|
||||
Env env{*this};
|
||||
|
||||
// positive test
|
||||
{
|
||||
Keylet const keylet = keylet::negativeUNL();
|
||||
|
||||
// easier to hack an object into the ledger than generate it
|
||||
// legitimately
|
||||
{
|
||||
auto const nUNL = [&](OpenView& view, beast::Journal) -> bool {
|
||||
auto const sle = std::make_shared<SLE>(keylet);
|
||||
|
||||
// Create DisabledValidators array
|
||||
STArray disabledValidators;
|
||||
auto disabledValidator =
|
||||
STObject::makeInnerObject(sfDisabledValidator);
|
||||
auto pubKeyBlob = strUnHex(
|
||||
"ED58F6770DB5DD77E59D28CB650EC3816E2FC95021BB56E720C9A1"
|
||||
"2DA79C58A3AB");
|
||||
disabledValidator.setFieldVL(sfPublicKey, *pubKeyBlob);
|
||||
disabledValidator.setFieldU32(
|
||||
sfFirstLedgerSequence, 91371264);
|
||||
disabledValidators.push_back(std::move(disabledValidator));
|
||||
|
||||
sle->setFieldArray(
|
||||
sfDisabledValidators, disabledValidators);
|
||||
sle->setFieldH256(
|
||||
sfPreviousTxnID,
|
||||
uint256::fromVoid("8D47FFE664BE6C335108DF689537625855A6"
|
||||
"A95160CC6D351341B9"
|
||||
"2624D9C5E3"));
|
||||
sle->setFieldU32(sfPreviousTxnLgrSeq, 91442944);
|
||||
|
||||
view.rawInsert(sle);
|
||||
return true;
|
||||
};
|
||||
env.app().openLedger().modify(nUNL);
|
||||
}
|
||||
|
||||
Json::Value jvParams;
|
||||
jvParams[jss::nunl] = to_string(keylet.key);
|
||||
Json::Value const jrr = env.rpc(
|
||||
"json", "ledger_entry", to_string(jvParams))[jss::result];
|
||||
BEAST_EXPECT(
|
||||
jrr[jss::node][sfLedgerEntryType.jsonName] == jss::NegativeUNL);
|
||||
}
|
||||
|
||||
// negative tests
|
||||
runLedgerEntryTest(env, jss::nunl);
|
||||
}
|
||||
|
||||
void
|
||||
testOffer()
|
||||
{
|
||||
testcase("Offer");
|
||||
using namespace test::jtx;
|
||||
@@ -1413,7 +1738,7 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryPayChan()
|
||||
testPayChan()
|
||||
{
|
||||
testcase("Pay Chan");
|
||||
using namespace test::jtx;
|
||||
@@ -1475,7 +1800,7 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryRippleState()
|
||||
testRippleState()
|
||||
{
|
||||
testcase("RippleState");
|
||||
using namespace test::jtx;
|
||||
@@ -1626,7 +1951,16 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryTicket()
|
||||
testSignerList()
|
||||
{
|
||||
testcase("Signer List");
|
||||
using namespace test::jtx;
|
||||
Env env{*this};
|
||||
runLedgerEntryTest(env, jss::signer_list);
|
||||
}
|
||||
|
||||
void
|
||||
testTicket()
|
||||
{
|
||||
testcase("Ticket");
|
||||
using namespace test::jtx;
|
||||
@@ -1711,7 +2045,7 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryDID()
|
||||
testDID()
|
||||
{
|
||||
testcase("DID");
|
||||
using namespace test::jtx;
|
||||
@@ -1848,7 +2182,7 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryMPT()
|
||||
testMPT()
|
||||
{
|
||||
testcase("MPT");
|
||||
using namespace test::jtx;
|
||||
@@ -1931,7 +2265,7 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryPermissionedDomain()
|
||||
testPermissionedDomain()
|
||||
{
|
||||
testcase("PermissionedDomain");
|
||||
|
||||
@@ -2010,7 +2344,7 @@ class LedgerEntry_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryCLI()
|
||||
testCLI()
|
||||
{
|
||||
testcase("command-line");
|
||||
using namespace test::jtx;
|
||||
@@ -2040,25 +2374,33 @@ public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testLedgerEntryInvalid();
|
||||
testLedgerEntryAccountRoot();
|
||||
testLedgerEntryCheck();
|
||||
testLedgerEntryCredentials();
|
||||
testLedgerEntryDelegate();
|
||||
testLedgerEntryDepositPreauth();
|
||||
testLedgerEntryDepositPreauthCred();
|
||||
testLedgerEntryDirectory();
|
||||
testLedgerEntryEscrow();
|
||||
testLedgerEntryOffer();
|
||||
testLedgerEntryPayChan();
|
||||
testLedgerEntryRippleState();
|
||||
testLedgerEntryTicket();
|
||||
testLedgerEntryDID();
|
||||
testInvalid();
|
||||
testAccountRoot();
|
||||
testAmendments();
|
||||
testAMM();
|
||||
testCheck();
|
||||
testCredentials();
|
||||
testDelegate();
|
||||
testDepositPreauth();
|
||||
testDepositPreauthCred();
|
||||
testDirectory();
|
||||
testEscrow();
|
||||
testFeeSettings();
|
||||
testLedgerHashes();
|
||||
testNFTokenOffer();
|
||||
testNFTokenPage();
|
||||
testNegativeUNL();
|
||||
testOffer();
|
||||
testPayChan();
|
||||
testRippleState();
|
||||
testSignerList();
|
||||
testTicket();
|
||||
testDID();
|
||||
testInvalidOracleLedgerEntry();
|
||||
testOracleLedgerEntry();
|
||||
testLedgerEntryMPT();
|
||||
testLedgerEntryPermissionedDomain();
|
||||
testLedgerEntryCLI();
|
||||
testMPT();
|
||||
testPermissionedDomain();
|
||||
testCLI();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2086,7 +2428,7 @@ class LedgerEntry_XChain_test : public beast::unit_test::suite,
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryBridge()
|
||||
testBridge()
|
||||
{
|
||||
testcase("ledger_entry: bridge");
|
||||
using namespace test::jtx;
|
||||
@@ -2177,7 +2519,7 @@ class LedgerEntry_XChain_test : public beast::unit_test::suite,
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryClaimID()
|
||||
testClaimID()
|
||||
{
|
||||
testcase("ledger_entry: xchain_claim_id");
|
||||
using namespace test::jtx;
|
||||
@@ -2235,7 +2577,7 @@ class LedgerEntry_XChain_test : public beast::unit_test::suite,
|
||||
}
|
||||
|
||||
void
|
||||
testLedgerEntryCreateAccountClaimID()
|
||||
testCreateAccountClaimID()
|
||||
{
|
||||
testcase("ledger_entry: xchain_create_account_claim_id");
|
||||
using namespace test::jtx;
|
||||
@@ -2362,9 +2704,9 @@ public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testLedgerEntryBridge();
|
||||
testLedgerEntryClaimID();
|
||||
testLedgerEntryCreateAccountClaimID();
|
||||
testBridge();
|
||||
testClaimID();
|
||||
testCreateAccountClaimID();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user