21#include <xrpld/app/misc/AmendmentTable.h>
22#include <xrpl/protocol/Feature.h>
23#include <xrpl/protocol/jss.h>
38 supportedAmendments.size() ==
43 for (
auto const& [name, vote] : supportedAmendments)
57 fail(
"Unknown VoteBehavior", __FILE__, __LINE__);
78 std::size_t supported = 0, unsupported = 0, retired = 0;
85 BEAST_EXPECT(supportedAmendments.contains(name));
94 fail(
"Unknown AmendmentSupport", __FILE__, __LINE__);
98 BEAST_EXPECT(supported + retired == supportedAmendments.size());
101 supportedAmendments.size());
115 for (
auto const& [feature, vote] : supported)
119 if (BEAST_EXPECT(registered))
133 "0000000000000000000000000000000000000000000000000000000000000000");
140 BEAST_EXPECT(
featureToName(featureOwnerPaysFee) ==
"OwnerPaysFee");
142 BEAST_EXPECT(
featureToName(featureNegativeUNL) ==
"NegativeUNL");
146 "fixTakerDryOfferRemoval");
152 testcase(
"No Params, None Enabled");
154 using namespace test::jtx;
160 auto jrr = env.rpc(
"feature")[jss::result];
161 if (!BEAST_EXPECT(jrr.isMember(jss::features)))
163 for (
auto const& feature : jrr[jss::features])
165 if (!BEAST_EXPECT(feature.isMember(jss::name)))
170 (votes.
at(feature[jss::name].asString()) ==
172 bool expectObsolete =
173 (votes.
at(feature[jss::name].asString()) ==
176 feature.isMember(jss::enabled) &&
177 !feature[jss::enabled].asBool(),
178 feature[jss::name].asString() +
" enabled");
180 feature.isMember(jss::vetoed) &&
181 feature[jss::vetoed].isBool() == !expectObsolete &&
182 (!feature[jss::vetoed].isBool() ||
183 feature[jss::vetoed].asBool() == expectVeto) &&
184 (feature[jss::vetoed].isBool() ||
185 feature[jss::vetoed].asString() ==
"Obsolete"),
186 feature[jss::name].asString() +
" vetoed");
188 feature.isMember(jss::supported) &&
189 feature[jss::supported].asBool(),
190 feature[jss::name].asString() +
" supported");
199 using namespace test::jtx;
202 auto jrr = env.rpc(
"feature",
"MultiSignReserve")[jss::result];
203 BEAST_EXPECTS(jrr[jss::status] == jss::success,
"status");
204 jrr.removeMember(jss::status);
205 BEAST_EXPECT(jrr.size() == 1);
207 jrr.isMember(
"586480873651E106F1D6339B0C4A8945BA705A777F3F4524626FF"
209 auto feature = *(jrr.begin());
211 BEAST_EXPECTS(feature[jss::name] ==
"MultiSignReserve",
"name");
212 BEAST_EXPECTS(!feature[jss::enabled].asBool(),
"enabled");
214 feature[jss::vetoed].isBool() && !feature[jss::vetoed].asBool(),
216 BEAST_EXPECTS(feature[jss::supported].asBool(),
"supported");
219 jrr = env.rpc(
"feature",
"multiSignReserve")[jss::result];
220 BEAST_EXPECT(jrr[jss::error] ==
"badFeature");
221 BEAST_EXPECT(jrr[jss::error_message] ==
"Feature unknown or invalid.");
229 using namespace test::jtx;
232 auto testInvalidParam = [&](
auto const& param) {
234 params[jss::feature] = param;
236 env.rpc(
"json",
"feature",
to_string(params))[jss::result];
237 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
238 BEAST_EXPECT(jrr[jss::error_message] ==
"Invalid parameters.");
242 testInvalidParam(1.1);
243 testInvalidParam(
true);
249 auto jrr = env.rpc(
"feature",
"AllTheThings")[jss::result];
250 BEAST_EXPECT(jrr[jss::error] ==
"badFeature");
252 jrr[jss::error_message] ==
"Feature unknown or invalid.");
261 using namespace test::jtx;
263 (*cfg)[
"port_rpc"].set(
"admin",
"");
264 (*cfg)[
"port_ws"].set(
"admin",
"");
269 auto result = env.rpc(
"feature")[jss::result];
270 BEAST_EXPECT(result.isMember(jss::features));
274 BEAST_EXPECT(result[jss::features].size() >= 50);
275 for (
auto it = result[jss::features].begin();
276 it != result[jss::features].end();
280 (void)
id.parseHex(it.key().asString().c_str());
281 if (!BEAST_EXPECT((*it).isMember(jss::name)))
284 env.app().getAmendmentTable().isEnabled(
id);
285 bool expectSupported =
286 env.app().getAmendmentTable().isSupported(
id);
288 (*it).isMember(jss::enabled) &&
289 (*it)[jss::enabled].asBool() == expectEnabled,
290 (*it)[jss::name].asString() +
" enabled");
292 (*it).isMember(jss::supported) &&
293 (*it)[jss::supported].asBool() == expectSupported,
294 (*it)[jss::name].asString() +
" supported");
295 BEAST_EXPECT(!(*it).isMember(jss::vetoed));
296 BEAST_EXPECT(!(*it).isMember(jss::majority));
297 BEAST_EXPECT(!(*it).isMember(jss::count));
298 BEAST_EXPECT(!(*it).isMember(jss::validations));
299 BEAST_EXPECT(!(*it).isMember(jss::threshold));
306 params[jss::feature] =
307 "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCD"
309 auto const result = env.rpc(
312 boost::lexical_cast<std::string>(params))[jss::result];
314 result[jss::error] ==
"badFeature", result.toStyledString());
316 result[jss::error_message] ==
"Feature unknown or invalid.");
321 params[jss::feature] =
322 "93E516234E35E08CA689FA33A6D38E103881F8DCB53023F728C307AA89D515"
325 params[jss::vetoed] =
true;
326 auto const result = env.rpc(
329 boost::lexical_cast<std::string>(params))[jss::result];
331 result[jss::error] ==
"noPermission",
332 result[jss::error].asString());
334 result[jss::error_message] ==
335 "You don't have permission for this command.");
340 "C4483A1896170C66C098DEA5B0E024309C60DC960DE5F01CD7AF986AA3D9AD"
343 params[jss::feature] = feature;
344 auto const result = env.rpc(
347 boost::lexical_cast<std::string>(params))[jss::result];
348 BEAST_EXPECT(result.isMember(feature));
349 auto const amendmentResult = result[feature];
350 BEAST_EXPECT(amendmentResult[jss::enabled].asBool() ==
false);
351 BEAST_EXPECT(amendmentResult[jss::supported].asBool() ==
true);
353 amendmentResult[jss::name].asString() ==
354 "fixMasterKeyAsRegularKey");
361 testcase(
"No Params, Some Enabled");
363 using namespace test::jtx;
365 *
this,
FeatureBitset(featureDepositAuth, featureDepositPreauth)};
370 auto jrr = env.rpc(
"feature")[jss::result];
371 if (!BEAST_EXPECT(jrr.isMember(jss::features)))
373 for (
auto it = jrr[jss::features].begin();
374 it != jrr[jss::features].end();
378 (void)
id.parseHex(it.key().asString().c_str());
379 if (!BEAST_EXPECT((*it).isMember(jss::name)))
381 bool expectEnabled = env.app().getAmendmentTable().isEnabled(
id);
382 bool expectSupported =
383 env.app().getAmendmentTable().isSupported(
id);
385 (votes.
at((*it)[jss::name].asString()) ==
387 bool expectObsolete =
388 (votes.
at((*it)[jss::name].asString()) ==
391 (*it).isMember(jss::enabled) &&
392 (*it)[jss::enabled].asBool() == expectEnabled,
393 (*it)[jss::name].asString() +
" enabled");
396 !(*it).isMember(jss::vetoed),
397 (*it)[jss::name].asString() +
" vetoed");
400 (*it).isMember(jss::vetoed) &&
401 (*it)[jss::vetoed].isBool() == !expectObsolete &&
402 (!(*it)[jss::vetoed].isBool() ||
403 (*it)[jss::vetoed].asBool() == expectVeto) &&
404 ((*it)[jss::vetoed].isBool() ||
405 (*it)[jss::vetoed].asString() ==
"Obsolete"),
406 (*it)[jss::name].asString() +
" vetoed");
408 (*it).isMember(jss::supported) &&
409 (*it)[jss::supported].asBool() == expectSupported,
410 (*it)[jss::name].asString() +
" supported");
419 using namespace test::jtx;
420 Env env{*
this, envconfig(validator,
"")};
422 auto jrr = env.rpc(
"feature")[jss::result];
423 if (!BEAST_EXPECT(jrr.isMember(jss::features)))
428 for (
auto const& feature : jrr[jss::features])
430 if (!BEAST_EXPECT(feature.isMember(jss::name)))
433 !feature.isMember(jss::majority),
434 feature[jss::name].asString() +
" majority");
436 !feature.isMember(jss::count),
437 feature[jss::name].asString() +
" count");
439 !feature.isMember(jss::threshold),
440 feature[jss::name].asString() +
" threshold");
442 !feature.isMember(jss::validations),
443 feature[jss::name].asString() +
" validations");
445 !feature.isMember(jss::vote),
446 feature[jss::name].asString() +
" vote");
450 if (!BEAST_EXPECT(majorities.empty()))
454 for (
auto i = 0; i <= 256; ++i)
458 if (!majorities.empty())
464 BEAST_EXPECT(majorities.size() >= 5);
468 jrr = env.rpc(
"feature")[jss::result];
469 if (!BEAST_EXPECT(jrr.isMember(jss::features)))
471 for (
auto const& feature : jrr[jss::features])
473 if (!BEAST_EXPECT(feature.isMember(jss::name)))
476 (votes.
at(feature[jss::name].asString()) ==
478 bool expectObsolete =
479 (votes.
at(feature[jss::name].asString()) ==
482 (expectVeto || expectObsolete) ^
483 feature.isMember(jss::majority),
484 feature[jss::name].asString() +
" majority");
486 feature.isMember(jss::vetoed) &&
487 feature[jss::vetoed].isBool() == !expectObsolete &&
488 (!feature[jss::vetoed].isBool() ||
489 feature[jss::vetoed].asBool() == expectVeto) &&
490 (feature[jss::vetoed].isBool() ||
491 feature[jss::vetoed].asString() ==
"Obsolete"),
492 feature[jss::name].asString() +
" vetoed");
494 feature.isMember(jss::count),
495 feature[jss::name].asString() +
" count");
497 feature.isMember(jss::threshold),
498 feature[jss::name].asString() +
" threshold");
500 feature.isMember(jss::validations),
501 feature[jss::name].asString() +
" validations");
503 feature[jss::count] ==
504 ((expectVeto || expectObsolete) ? 0 : 1));
505 BEAST_EXPECT(feature[jss::threshold] == 1);
506 BEAST_EXPECT(feature[jss::validations] == 1);
508 expectVeto || expectObsolete || feature[jss::majority] == 2540,
509 "Majority: " + feature[jss::majority].asString());
518 using namespace test::jtx;
520 constexpr const char* featureName =
"MultiSignReserve";
522 auto jrr = env.rpc(
"feature", featureName)[jss::result];
523 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success,
"status"))
525 jrr.removeMember(jss::status);
526 if (!BEAST_EXPECT(jrr.size() == 1))
528 auto feature = *(jrr.begin());
529 BEAST_EXPECTS(feature[jss::name] == featureName,
"name");
531 feature[jss::vetoed].isBool() && !feature[jss::vetoed].asBool(),
534 jrr = env.rpc(
"feature", featureName,
"reject")[jss::result];
535 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success,
"status"))
537 jrr.removeMember(jss::status);
538 if (!BEAST_EXPECT(jrr.size() == 1))
540 feature = *(jrr.begin());
541 BEAST_EXPECTS(feature[jss::name] == featureName,
"name");
543 feature[jss::vetoed].isBool() && feature[jss::vetoed].asBool(),
546 jrr = env.rpc(
"feature", featureName,
"accept")[jss::result];
547 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success,
"status"))
549 jrr.removeMember(jss::status);
550 if (!BEAST_EXPECT(jrr.size() == 1))
552 feature = *(jrr.begin());
553 BEAST_EXPECTS(feature[jss::name] == featureName,
"name");
555 feature[jss::vetoed].isBool() && !feature[jss::vetoed].asBool(),
559 jrr = env.rpc(
"feature", featureName,
"maybe");
560 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
561 BEAST_EXPECT(jrr[jss::error_message] ==
"Invalid parameters.");
569 using namespace test::jtx;
571 constexpr const char* featureName =
"NonFungibleTokensV1";
573 auto jrr = env.rpc(
"feature", featureName)[jss::result];
574 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success,
"status"))
576 jrr.removeMember(jss::status);
577 if (!BEAST_EXPECT(jrr.size() == 1))
579 auto feature = *(jrr.begin());
580 BEAST_EXPECTS(feature[jss::name] == featureName,
"name");
582 feature[jss::vetoed].isString() &&
583 feature[jss::vetoed].asString() ==
"Obsolete",
586 jrr = env.rpc(
"feature", featureName,
"reject")[jss::result];
587 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success,
"status"))
589 jrr.removeMember(jss::status);
590 if (!BEAST_EXPECT(jrr.size() == 1))
592 feature = *(jrr.begin());
593 BEAST_EXPECTS(feature[jss::name] == featureName,
"name");
595 feature[jss::vetoed].isString() &&
596 feature[jss::vetoed].asString() ==
"Obsolete",
599 jrr = env.rpc(
"feature", featureName,
"accept")[jss::result];
600 if (!BEAST_EXPECTS(jrr[jss::status] == jss::success,
"status"))
602 jrr.removeMember(jss::status);
603 if (!BEAST_EXPECT(jrr.size() == 1))
605 feature = *(jrr.begin());
606 BEAST_EXPECTS(feature[jss::name] == featureName,
"name");
608 feature[jss::vetoed].isString() &&
609 feature[jss::vetoed].asString() ==
"Obsolete",
613 jrr = env.rpc(
"feature", featureName,
"maybe");
614 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
615 BEAST_EXPECT(jrr[jss::error_message] ==
"Invalid parameters.");
635BEAST_DEFINE_TESTSUITE(Feature, rpc,
ripple);
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.
@ 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.
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)