rippled
Feature_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2017 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/app/misc/AmendmentTable.h>
21 #include <ripple/protocol/Feature.h>
22 #include <ripple/protocol/jss.h>
23 #include <test/jtx.h>
24 
25 namespace ripple {
26 
27 class Feature_test : public beast::unit_test::suite
28 {
29  void
31  {
32  testcase("No Params, None Enabled");
33 
34  using namespace test::jtx;
35  Env env{*this};
36 
37  auto jrr = env.rpc("feature")[jss::result];
38  if (!BEAST_EXPECT(jrr.isMember(jss::features)))
39  return;
40  for (auto const& feature : jrr[jss::features])
41  {
42  if (!BEAST_EXPECT(feature.isMember(jss::name)))
43  return;
44  // default config - so all should be disabled, not vetoed, and
45  // supported
46  BEAST_EXPECTS(
47  !feature[jss::enabled].asBool(),
48  feature[jss::name].asString() + " enabled");
49  BEAST_EXPECTS(
50  !feature[jss::vetoed].asBool(),
51  feature[jss::name].asString() + " vetoed");
52  BEAST_EXPECTS(
53  feature[jss::supported].asBool(),
54  feature[jss::name].asString() + " supported");
55  }
56  }
57 
58  void
60  {
61  testcase("Feature Param");
62 
63  using namespace test::jtx;
64  Env env{*this};
65 
66  auto jrr = env.rpc("feature", "MultiSignReserve")[jss::result];
67  BEAST_EXPECTS(jrr[jss::status] == jss::success, "status");
68  jrr.removeMember(jss::status);
69  BEAST_EXPECT(jrr.size() == 1);
70  auto feature = *(jrr.begin());
71 
72  BEAST_EXPECTS(feature[jss::name] == "MultiSignReserve", "name");
73  BEAST_EXPECTS(!feature[jss::enabled].asBool(), "enabled");
74  BEAST_EXPECTS(!feature[jss::vetoed].asBool(), "vetoed");
75  BEAST_EXPECTS(feature[jss::supported].asBool(), "supported");
76 
77  // feature names are case-sensitive - expect error here
78  jrr = env.rpc("feature", "multiSignReserve")[jss::result];
79  BEAST_EXPECT(jrr[jss::error] == "badFeature");
80  BEAST_EXPECT(jrr[jss::error_message] == "Feature unknown or invalid.");
81  }
82 
83  void
85  {
86  testcase("Invalid Feature");
87 
88  using namespace test::jtx;
89  Env env{*this};
90 
91  auto jrr = env.rpc("feature", "AllTheThings")[jss::result];
92  BEAST_EXPECT(jrr[jss::error] == "badFeature");
93  BEAST_EXPECT(jrr[jss::error_message] == "Feature unknown or invalid.");
94  }
95 
96  void
98  {
99  testcase("Feature Without Admin");
100 
101  using namespace test::jtx;
102  Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
103  (*cfg)["port_rpc"].set("admin", "");
104  (*cfg)["port_ws"].set("admin", "");
105  return cfg;
106  })};
107 
108  auto jrr = env.rpc("feature")[jss::result];
109  // The current HTTP/S ServerHandler returns an HTTP 403 error code here
110  // rather than a noPermission JSON error. The JSONRPCClient just eats
111  // that error and returns an null result.
112  BEAST_EXPECT(jrr.isNull());
113  }
114 
115  void
117  {
118  testcase("No Params, Some Enabled");
119 
120  using namespace test::jtx;
121  Env env{
123 
124  auto jrr = env.rpc("feature")[jss::result];
125  if (!BEAST_EXPECT(jrr.isMember(jss::features)))
126  return;
127  for (auto it = jrr[jss::features].begin();
128  it != jrr[jss::features].end();
129  ++it)
130  {
131  uint256 id;
132  (void)id.parseHex(it.key().asString().c_str());
133  if (!BEAST_EXPECT((*it).isMember(jss::name)))
134  return;
135  bool expectEnabled = env.app().getAmendmentTable().isEnabled(id);
136  bool expectSupported =
137  env.app().getAmendmentTable().isSupported(id);
138  BEAST_EXPECTS(
139  (*it)[jss::enabled].asBool() == expectEnabled,
140  (*it)[jss::name].asString() + " enabled");
141  BEAST_EXPECTS(
142  !(*it)[jss::vetoed].asBool(),
143  (*it)[jss::name].asString() + " vetoed");
144  BEAST_EXPECTS(
145  (*it)[jss::supported].asBool() == expectSupported,
146  (*it)[jss::name].asString() + " supported");
147  }
148  }
149 
150  void
152  {
153  testcase("With Majorities");
154 
155  using namespace test::jtx;
156  Env env{*this, envconfig(validator, "")};
157 
158  auto jrr = env.rpc("feature")[jss::result];
159  if (!BEAST_EXPECT(jrr.isMember(jss::features)))
160  return;
161 
162  // at this point, there are no majorities so no fields related to
163  // amendment voting
164  for (auto const& feature : jrr[jss::features])
165  {
166  if (!BEAST_EXPECT(feature.isMember(jss::name)))
167  return;
168  BEAST_EXPECTS(
169  !feature.isMember(jss::majority),
170  feature[jss::name].asString() + " majority");
171  BEAST_EXPECTS(
172  !feature.isMember(jss::count),
173  feature[jss::name].asString() + " count");
174  BEAST_EXPECTS(
175  !feature.isMember(jss::threshold),
176  feature[jss::name].asString() + " threshold");
177  BEAST_EXPECTS(
178  !feature.isMember(jss::validations),
179  feature[jss::name].asString() + " validations");
180  BEAST_EXPECTS(
181  !feature.isMember(jss::vote),
182  feature[jss::name].asString() + " vote");
183  }
184 
185  auto majorities = getMajorityAmendments(*env.closed());
186  if (!BEAST_EXPECT(majorities.empty()))
187  return;
188 
189  // close ledgers until the amendments show up.
190  for (auto i = 0; i <= 256; ++i)
191  {
192  env.close();
193  majorities = getMajorityAmendments(*env.closed());
194  if (!majorities.empty())
195  break;
196  }
197 
198  // There should be at least 5 amendments. Don't do exact comparison
199  // to avoid maintenance as more amendments are added in the future.
200  BEAST_EXPECT(majorities.size() >= 5);
201 
202  jrr = env.rpc("feature")[jss::result];
203  if (!BEAST_EXPECT(jrr.isMember(jss::features)))
204  return;
205  for (auto const& feature : jrr[jss::features])
206  {
207  if (!BEAST_EXPECT(feature.isMember(jss::name)))
208  return;
209  BEAST_EXPECTS(
210  feature.isMember(jss::majority),
211  feature[jss::name].asString() + " majority");
212  BEAST_EXPECTS(
213  feature.isMember(jss::count),
214  feature[jss::name].asString() + " count");
215  BEAST_EXPECTS(
216  feature.isMember(jss::threshold),
217  feature[jss::name].asString() + " threshold");
218  BEAST_EXPECTS(
219  feature.isMember(jss::validations),
220  feature[jss::name].asString() + " validations");
221  BEAST_EXPECT(feature[jss::count] == 1);
222  BEAST_EXPECT(feature[jss::threshold] == 1);
223  BEAST_EXPECT(feature[jss::validations] == 1);
224  BEAST_EXPECT(feature[jss::majority] == 2540);
225  }
226  }
227 
228  void
230  {
231  testcase("Veto");
232 
233  using namespace test::jtx;
234  Env env{*this, FeatureBitset(featureMultiSignReserve)};
235 
236  auto jrr = env.rpc("feature", "MultiSignReserve")[jss::result];
237  if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status"))
238  return;
239  jrr.removeMember(jss::status);
240  if (!BEAST_EXPECT(jrr.size() == 1))
241  return;
242  auto feature = *(jrr.begin());
243  BEAST_EXPECTS(feature[jss::name] == "MultiSignReserve", "name");
244  BEAST_EXPECTS(!feature[jss::vetoed].asBool(), "vetoed");
245 
246  jrr = env.rpc("feature", "MultiSignReserve", "reject")[jss::result];
247  if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status"))
248  return;
249  jrr.removeMember(jss::status);
250  if (!BEAST_EXPECT(jrr.size() == 1))
251  return;
252  feature = *(jrr.begin());
253  BEAST_EXPECTS(feature[jss::name] == "MultiSignReserve", "name");
254  BEAST_EXPECTS(feature[jss::vetoed].asBool(), "vetoed");
255 
256  jrr = env.rpc("feature", "MultiSignReserve", "accept")[jss::result];
257  if (!BEAST_EXPECTS(jrr[jss::status] == jss::success, "status"))
258  return;
259  jrr.removeMember(jss::status);
260  if (!BEAST_EXPECT(jrr.size() == 1))
261  return;
262  feature = *(jrr.begin());
263  BEAST_EXPECTS(feature[jss::name] == "MultiSignReserve", "name");
264  BEAST_EXPECTS(!feature[jss::vetoed].asBool(), "vetoed");
265 
266  // anything other than accept or reject is an error
267  jrr = env.rpc("feature", "MultiSignReserve", "maybe");
268  BEAST_EXPECT(jrr[jss::error] == "invalidParams");
269  BEAST_EXPECT(jrr[jss::error_message] == "Invalid parameters.");
270  }
271 
272 public:
273  void
274  run() override
275  {
276  testNoParams();
279  testNonAdmin();
280  testSomeEnabled();
282  testVeto();
283  }
284 };
285 
286 BEAST_DEFINE_TESTSUITE(Feature, rpc, ripple);
287 
288 } // namespace ripple
ripple::getMajorityAmendments
majorityAmendments_t getMajorityAmendments(ReadView const &view)
Definition: View.cpp:554
ripple::Feature_test::testSingleFeature
void testSingleFeature()
Definition: Feature_test.cpp:59
ripple::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
ripple::Feature_test::testVeto
void testVeto()
Definition: Feature_test.cpp:229
ripple::featureDepositPreauth
const uint256 featureDepositPreauth
Definition: Feature.cpp:178
ripple::Feature_test::run
void run() override
Definition: Feature_test.cpp:274
ripple::featureDepositAuth
const uint256 featureDepositAuth
Definition: Feature.cpp:173
ripple::featureMultiSignReserve
const uint256 featureMultiSignReserve
Definition: Feature.cpp:181
ripple::base_uint< 256 >
ripple::Feature_test::testSomeEnabled
void testSomeEnabled()
Definition: Feature_test.cpp:116
ripple::Feature_test
Definition: Feature_test.cpp:27
ripple::Feature_test::testWithMajorities
void testWithMajorities()
Definition: Feature_test.cpp:151
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::FeatureBitset
Definition: Feature.h:161
ripple::Feature_test::testNoParams
void testNoParams()
Definition: Feature_test.cpp:30
ripple::Feature_test::testNonAdmin
void testNonAdmin()
Definition: Feature_test.cpp:97
ripple::Feature_test::testInvalidFeature
void testInvalidFeature()
Definition: Feature_test.cpp:84
std::unique_ptr
STL class.