22#include <xrpld/app/misc/AmendmentTable.h>
24#include <xrpl/protocol/Feature.h>
25#include <xrpl/protocol/jss.h>
40 supportedAmendments.size() ==
45 for (
auto const& [name, vote] : supportedAmendments)
59 fail(
"Unknown VoteBehavior", __FILE__, __LINE__);
80 std::size_t supported = 0, unsupported = 0, retired = 0;
87 BEAST_EXPECT(supportedAmendments.contains(name));
96 fail(
"Unknown AmendmentSupport", __FILE__, __LINE__);
100 BEAST_EXPECT(supported + retired == supportedAmendments.size());
103 supportedAmendments.size());
117 for (
auto const& [feature, vote] : supported)
121 if (BEAST_EXPECT(registered))
135 "0000000000000000000000000000000000000000000000000000000000000000");
142 BEAST_EXPECT(
featureToName(featureOwnerPaysFee) ==
"OwnerPaysFee");
144 BEAST_EXPECT(
featureToName(featureNegativeUNL) ==
"NegativeUNL");
148 "fixTakerDryOfferRemoval");
154 testcase(
"No Params, None Enabled");
156 using namespace test::jtx;
162 auto jrr = env.rpc(
"feature")[jss::result];
163 if (!BEAST_EXPECT(jrr.isMember(jss::features)))
165 for (
auto const& feature : jrr[jss::features])
167 if (!BEAST_EXPECT(feature.isMember(jss::name)))
172 (votes.
at(feature[jss::name].asString()) ==
174 bool expectObsolete =
175 (votes.
at(feature[jss::name].asString()) ==
178 feature.isMember(jss::enabled) &&
179 !feature[jss::enabled].asBool(),
180 feature[jss::name].asString() +
" enabled");
182 feature.isMember(jss::vetoed) &&
183 feature[jss::vetoed].isBool() == !expectObsolete &&
184 (!feature[jss::vetoed].isBool() ||
185 feature[jss::vetoed].asBool() == expectVeto) &&
186 (feature[jss::vetoed].isBool() ||
187 feature[jss::vetoed].asString() ==
"Obsolete"),
188 feature[jss::name].asString() +
" vetoed");
190 feature.isMember(jss::supported) &&
191 feature[jss::supported].asBool(),
192 feature[jss::name].asString() +
" supported");
201 using namespace test::jtx;
204 auto jrr = env.
rpc(
"feature",
"MultiSignReserve")[jss::result];
205 BEAST_EXPECTS(jrr[jss::status] == jss::success,
"status");
206 jrr.removeMember(jss::status);
207 BEAST_EXPECT(jrr.size() == 1);
209 jrr.isMember(
"586480873651E106F1D6339B0C4A8945BA705A777F3F4524626FF"
211 auto feature = *(jrr.begin());
213 BEAST_EXPECTS(feature[jss::name] ==
"MultiSignReserve",
"name");
214 BEAST_EXPECTS(!feature[jss::enabled].asBool(),
"enabled");
216 feature[jss::vetoed].isBool() && !feature[jss::vetoed].asBool(),
218 BEAST_EXPECTS(feature[jss::supported].asBool(),
"supported");
221 jrr = env.rpc(
"feature",
"multiSignReserve")[jss::result];
222 BEAST_EXPECT(jrr[jss::error] ==
"badFeature");
223 BEAST_EXPECT(jrr[jss::error_message] ==
"Feature unknown or invalid.");
231 using namespace test::jtx;
234 auto testInvalidParam = [&](
auto const& param) {
236 params[jss::feature] = param;
238 env.rpc(
"json",
"feature",
to_string(params))[jss::result];
239 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
240 BEAST_EXPECT(jrr[jss::error_message] ==
"Invalid parameters.");
244 testInvalidParam(1.1);
245 testInvalidParam(
true);
251 auto jrr = env.rpc(
"feature",
"AllTheThings")[jss::result];
252 BEAST_EXPECT(jrr[jss::error] ==
"badFeature");
254 jrr[jss::error_message] ==
"Feature unknown or invalid.");
263 using namespace test::jtx;
265 (*cfg)[
"port_rpc"].set(
"admin",
"");
266 (*cfg)[
"port_ws"].set(
"admin",
"");
271 auto result = env.rpc(
"feature")[jss::result];
272 BEAST_EXPECT(result.isMember(jss::features));
276 BEAST_EXPECT(result[jss::features].size() >= 50);
277 for (
auto it = result[jss::features].begin();
278 it != result[jss::features].end();
282 (void)
id.parseHex(it.key().asString().c_str());
283 if (!BEAST_EXPECT((*it).isMember(jss::name)))
286 env.app().getAmendmentTable().isEnabled(
id);
287 bool expectSupported =
288 env.app().getAmendmentTable().isSupported(
id);
290 (*it).isMember(jss::enabled) &&
291 (*it)[jss::enabled].asBool() == expectEnabled,
292 (*it)[jss::name].asString() +
" enabled");
294 (*it).isMember(jss::supported) &&
295 (*it)[jss::supported].asBool() == expectSupported,
296 (*it)[jss::name].asString() +
" supported");
297 BEAST_EXPECT(!(*it).isMember(jss::vetoed));
298 BEAST_EXPECT(!(*it).isMember(jss::majority));
299 BEAST_EXPECT(!(*it).isMember(jss::count));
300 BEAST_EXPECT(!(*it).isMember(jss::validations));
301 BEAST_EXPECT(!(*it).isMember(jss::threshold));
308 params[jss::feature] =
309 "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCD"
311 auto const result = env.rpc(
314 boost::lexical_cast<std::string>(params))[jss::result];
316 result[jss::error] ==
"badFeature", result.toStyledString());
318 result[jss::error_message] ==
"Feature unknown or invalid.");
323 params[jss::feature] =
324 "93E516234E35E08CA689FA33A6D38E103881F8DCB53023F728C307AA89D515"
327 params[jss::vetoed] =
true;
328 auto const result = env.rpc(
331 boost::lexical_cast<std::string>(params))[jss::result];
333 result[jss::error] ==
"noPermission",
334 result[jss::error].asString());
336 result[jss::error_message] ==
337 "You don't have permission for this command.");
342 "C4483A1896170C66C098DEA5B0E024309C60DC960DE5F01CD7AF986AA3D9AD"
345 params[jss::feature] = feature;
346 auto const result = env.rpc(
349 boost::lexical_cast<std::string>(params))[jss::result];
350 BEAST_EXPECT(result.isMember(feature));
351 auto const amendmentResult = result[feature];
352 BEAST_EXPECT(amendmentResult[jss::enabled].asBool() ==
false);
353 BEAST_EXPECT(amendmentResult[jss::supported].asBool() ==
true);
355 amendmentResult[jss::name].asString() ==
356 "fixMasterKeyAsRegularKey");
363 testcase(
"No Params, Some Enabled");
365 using namespace test::jtx;
367 *
this,
FeatureBitset(featureDepositAuth, featureDepositPreauth)};
372 auto jrr = env.rpc(
"feature")[jss::result];
373 if (!BEAST_EXPECT(jrr.isMember(jss::features)))
375 for (
auto it = jrr[jss::features].begin();
376 it != jrr[jss::features].end();
380 (void)
id.parseHex(it.key().asString().c_str());
381 if (!BEAST_EXPECT((*it).isMember(jss::name)))
383 bool expectEnabled = env.app().getAmendmentTable().isEnabled(
id);
384 bool expectSupported =
385 env.app().getAmendmentTable().isSupported(
id);
387 (votes.
at((*it)[jss::name].asString()) ==
389 bool expectObsolete =
390 (votes.
at((*it)[jss::name].asString()) ==
393 (*it).isMember(jss::enabled) &&
394 (*it)[jss::enabled].asBool() == expectEnabled,
395 (*it)[jss::name].asString() +
" enabled");
398 !(*it).isMember(jss::vetoed),
399 (*it)[jss::name].asString() +
" vetoed");
402 (*it).isMember(jss::vetoed) &&
403 (*it)[jss::vetoed].isBool() == !expectObsolete &&
404 (!(*it)[jss::vetoed].isBool() ||
405 (*it)[jss::vetoed].asBool() == expectVeto) &&
406 ((*it)[jss::vetoed].isBool() ||
407 (*it)[jss::vetoed].asString() ==
"Obsolete"),
408 (*it)[jss::name].asString() +
" vetoed");
410 (*it).isMember(jss::supported) &&
411 (*it)[jss::supported].asBool() == expectSupported,
412 (*it)[jss::name].asString() +
" supported");
421 using namespace test::jtx;
424 auto jrr = env.rpc(
"feature")[jss::result];
425 if (!BEAST_EXPECT(jrr.isMember(jss::features)))
430 for (
auto const& feature : jrr[jss::features])
432 if (!BEAST_EXPECT(feature.isMember(jss::name)))
435 !feature.isMember(jss::majority),
436 feature[jss::name].asString() +
" majority");
438 !feature.isMember(jss::count),
439 feature[jss::name].asString() +
" count");
441 !feature.isMember(jss::threshold),
442 feature[jss::name].asString() +
" threshold");
444 !feature.isMember(jss::validations),
445 feature[jss::name].asString() +
" validations");
447 !feature.isMember(jss::vote),
448 feature[jss::name].asString() +
" vote");
452 if (!BEAST_EXPECT(majorities.empty()))
456 for (
auto i = 0; i <= 256; ++i)
460 if (!majorities.empty())
466 BEAST_EXPECT(majorities.size() >= 5);
470 jrr = env.rpc(
"feature")[jss::result];
471 if (!BEAST_EXPECT(jrr.isMember(jss::features)))
473 for (
auto const& feature : jrr[jss::features])
475 if (!BEAST_EXPECT(feature.isMember(jss::name)))
478 (votes.
at(feature[jss::name].asString()) ==
480 bool expectObsolete =
481 (votes.
at(feature[jss::name].asString()) ==
484 (expectVeto || expectObsolete) ^
485 feature.isMember(jss::majority),
486 feature[jss::name].asString() +
" majority");
488 feature.isMember(jss::vetoed) &&
489 feature[jss::vetoed].isBool() == !expectObsolete &&
490 (!feature[jss::vetoed].isBool() ||
491 feature[jss::vetoed].asBool() == expectVeto) &&
492 (feature[jss::vetoed].isBool() ||
493 feature[jss::vetoed].asString() ==
"Obsolete"),
494 feature[jss::name].asString() +
" vetoed");
496 feature.isMember(jss::count),
497 feature[jss::name].asString() +
" count");
499 feature.isMember(jss::threshold),
500 feature[jss::name].asString() +
" threshold");
502 feature.isMember(jss::validations),
503 feature[jss::name].asString() +
" validations");
505 feature[jss::count] ==
506 ((expectVeto || expectObsolete) ? 0 : 1));
507 BEAST_EXPECT(feature[jss::threshold] == 1);
508 BEAST_EXPECT(feature[jss::validations] == 1);
510 expectVeto || expectObsolete || feature[jss::majority] == 2540,
511 "Majority: " + feature[jss::majority].asString());
520 using namespace test::jtx;
522 constexpr char const* featureName =
"MultiSignReserve";
524 auto jrr = env.rpc(
"feature", featureName)[jss::result];
525 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success,
"status"))
527 jrr.removeMember(jss::status);
528 if (!BEAST_EXPECT(jrr.size() == 1))
530 auto feature = *(jrr.begin());
531 BEAST_EXPECTS(feature[jss::name] == featureName,
"name");
533 feature[jss::vetoed].isBool() && !feature[jss::vetoed].asBool(),
536 jrr = env.rpc(
"feature", featureName,
"reject")[jss::result];
537 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success,
"status"))
539 jrr.removeMember(jss::status);
540 if (!BEAST_EXPECT(jrr.size() == 1))
542 feature = *(jrr.begin());
543 BEAST_EXPECTS(feature[jss::name] == featureName,
"name");
545 feature[jss::vetoed].isBool() && feature[jss::vetoed].asBool(),
548 jrr = env.rpc(
"feature", featureName,
"accept")[jss::result];
549 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success,
"status"))
551 jrr.removeMember(jss::status);
552 if (!BEAST_EXPECT(jrr.size() == 1))
554 feature = *(jrr.begin());
555 BEAST_EXPECTS(feature[jss::name] == featureName,
"name");
557 feature[jss::vetoed].isBool() && !feature[jss::vetoed].asBool(),
561 jrr = env.rpc(
"feature", featureName,
"maybe");
562 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
563 BEAST_EXPECT(jrr[jss::error_message] ==
"Invalid parameters.");
571 using namespace test::jtx;
573 constexpr char const* featureName =
"NonFungibleTokensV1";
575 auto jrr = env.
rpc(
"feature", featureName)[jss::result];
576 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success,
"status"))
579 if (!BEAST_EXPECT(jrr.size() == 1))
581 auto feature = *(jrr.begin());
582 BEAST_EXPECTS(feature[jss::name] == featureName,
"name");
584 feature[jss::vetoed].isString() &&
585 feature[jss::vetoed].asString() ==
"Obsolete",
588 jrr = env.rpc(
"feature", featureName,
"reject")[jss::result];
589 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success,
"status"))
591 jrr.removeMember(jss::status);
592 if (!BEAST_EXPECT(jrr.size() == 1))
594 feature = *(jrr.begin());
595 BEAST_EXPECTS(feature[jss::name] == featureName,
"name");
597 feature[jss::vetoed].isString() &&
598 feature[jss::vetoed].asString() ==
"Obsolete",
601 jrr = env.rpc(
"feature", featureName,
"accept")[jss::result];
602 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success,
"status"))
604 jrr.removeMember(jss::status);
605 if (!BEAST_EXPECT(jrr.size() == 1))
607 feature = *(jrr.begin());
608 BEAST_EXPECTS(feature[jss::name] == featureName,
"name");
610 feature[jss::vetoed].isString() &&
611 feature[jss::vetoed].asString() ==
"Obsolete",
615 jrr = env.rpc(
"feature", featureName,
"maybe");
616 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
617 BEAST_EXPECT(jrr[jss::error_message] ==
"Invalid parameters.");
Value removeMember(char const *key)
Remove and return the named member.
testcase_t testcase
Memberspace for declaring test cases.
void fail(String const &reason, char const *file, int line)
Record a failure.
void testInvalidFeature()
void testFeatureLookups()
void testWithMajorities()
void run() override
Runs the suite.
A transaction testing environment.
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Set the expected result code for a JTx The test will fail if the code doesn't match.
@ arrayValue
array value (ordered list)
@ objectValue
object value (collection of name/value pairs).
std::size_t numUpVotedAmendments()
Amendments that this server will vote for by default.
std::size_t numDownVotedAmendments()
Amendments that this server won't vote for by default.
std::map< std::string, VoteBehavior > const & supportedAmendments()
Amendments that this server supports and the default voting behavior.
std::unique_ptr< Config > validator(std::unique_ptr< Config >, std::string const &)
adjust configuration with params needed to be a validator
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
uint256 bitsetIndexToFeature(size_t i)
size_t featureToBitsetIndex(uint256 const &f)
std::map< std::string, AmendmentSupport > const & allAmendments()
All amendments libxrpl knows about.
std::string featureToName(uint256 const &f)
std::optional< uint256 > getRegisteredFeature(std::string const &name)
majorityAmendments_t getMajorityAmendments(ReadView const &view)
std::string to_string(base_uint< Bits, Tag > const &a)