rippled
Regression_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5  Permission to use, copy, modify, and/or distribute this software for any
6  purpose with or without fee is hereby granted, provided that the above
7  copyright notice and this permission notice appear in all copies.
8  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16 //==============================================================================
17 
18 #include <ripple/app/tx/apply.h>
19 #include <ripple/basics/StringUtilities.h>
20 #include <ripple/json/json_reader.h>
21 #include <ripple/protocol/Feature.h>
22 #include <ripple/protocol/jss.h>
23 #include <test/jtx.h>
24 #include <test/jtx/envconfig.h>
25 
26 namespace ripple {
27 namespace test {
28 
29 struct Regression_test : public beast::unit_test::suite
30 {
31  // OfferCreate, then OfferCreate with cancel
32  void
34  {
35  using namespace jtx;
36  Env env(*this);
37  auto const gw = Account("gw");
38  auto const USD = gw["USD"];
39  env.fund(XRP(10000), "alice", gw);
40  env(offer("alice", USD(10), XRP(10)), require(owners("alice", 1)));
41  env(offer("alice", USD(20), XRP(10)),
42  json(R"raw(
43  { "OfferSequence" : 4 }
44  )raw"),
45  require(owners("alice", 1)));
46  }
47 
48  void
50  {
51  testcase("Account balance < fee destroys correct amount of XRP");
52  using namespace jtx;
53  Env env(*this);
54  env.memoize("alice");
55 
56  // The low balance scenario can not deterministically
57  // be reproduced against an open ledger. Make a local
58  // closed ledger and work with it directly.
59  auto closed = std::make_shared<Ledger>(
61  env.app().config(),
63  env.app().getNodeFamily());
64  auto expectedDrops = INITIAL_XRP;
65  BEAST_EXPECT(closed->info().drops == expectedDrops);
66 
67  auto const aliceXRP = 400;
68  auto const aliceAmount = XRP(aliceXRP);
69 
70  auto next = std::make_shared<Ledger>(
71  *closed, env.app().timeKeeper().closeTime());
72  {
73  // Fund alice
74  auto const jt = env.jt(pay(env.master, "alice", aliceAmount));
75  OpenView accum(&*next);
76 
77  auto const result =
78  ripple::apply(env.app(), accum, *jt.stx, tapNONE, env.journal);
79  BEAST_EXPECT(result.first == tesSUCCESS);
80  BEAST_EXPECT(result.second);
81 
82  accum.apply(*next);
83  }
84  expectedDrops -= next->fees().base;
85  BEAST_EXPECT(next->info().drops == expectedDrops);
86  {
87  auto const sle = next->read(keylet::account(Account("alice").id()));
88  BEAST_EXPECT(sle);
89  auto balance = sle->getFieldAmount(sfBalance);
90 
91  BEAST_EXPECT(balance == aliceAmount);
92  }
93 
94  {
95  // Specify the seq manually since the env's open ledger
96  // doesn't know about this account.
97  auto const jt = env.jt(noop("alice"), fee(expectedDrops), seq(2));
98 
99  OpenView accum(&*next);
100 
101  auto const result =
102  ripple::apply(env.app(), accum, *jt.stx, tapNONE, env.journal);
103  BEAST_EXPECT(result.first == tecINSUFF_FEE);
104  BEAST_EXPECT(result.second);
105 
106  accum.apply(*next);
107  }
108  {
109  auto const sle = next->read(keylet::account(Account("alice").id()));
110  BEAST_EXPECT(sle);
111  auto balance = sle->getFieldAmount(sfBalance);
112 
113  BEAST_EXPECT(balance == XRP(0));
114  }
115  expectedDrops -= aliceXRP * dropsPerXRP;
116  BEAST_EXPECT(next->info().drops == expectedDrops);
117  }
118 
119  void
121  {
122  testcase("Signing with a secp256r1 key should fail gracefully");
123  using namespace jtx;
124  Env env(*this);
125 
126  // Test case we'll use.
127  auto test256r1key = [&env](Account const& acct) {
128  auto const baseFee = env.current()->fees().base;
129  std::uint32_t const acctSeq = env.seq(acct);
130  Json::Value jsonNoop =
131  env.json(noop(acct), fee(baseFee), seq(acctSeq), sig(acct));
132  JTx jt = env.jt(jsonNoop);
133  jt.fill_sig = false;
134 
135  // Random secp256r1 public key generated by
136  // https://kjur.github.io/jsrsasign/sample-ecdsa.html
137  std::string const secp256r1PubKey =
138  "045d02995ec24988d9a2ae06a3733aa35ba0741e87527"
139  "ed12909b60bd458052c944b24cbf5893c3e5be321774e"
140  "5082e11c034b765861d0effbde87423f8476bb2c";
141 
142  // Set the key in the JSON.
143  jt.jv["SigningPubKey"] = secp256r1PubKey;
144 
145  // Set the same key in the STTx.
146  auto secp256r1Sig = std::make_unique<STTx>(*(jt.stx));
147  auto pubKeyBlob = strUnHex(secp256r1PubKey);
148  assert(pubKeyBlob); // Hex for public key must be valid
149  secp256r1Sig->setFieldVL(sfSigningPubKey, *pubKeyBlob);
150  jt.stx.reset(secp256r1Sig.release());
151 
152  env(jt, ter(temINVALID));
153  };
154 
155  Account const alice{"alice", KeyType::secp256k1};
156  Account const becky{"becky", KeyType::ed25519};
157 
158  env.fund(XRP(10000), alice, becky);
159 
160  test256r1key(alice);
161  test256r1key(becky);
162  }
163 
164  void
166  {
167  testcase("Autofilled fee should use the escalated fee");
168  using namespace jtx;
169  Env env(*this, envconfig([](std::unique_ptr<Config> cfg) {
170  cfg->section("transaction_queue")
171  .set("minimum_txn_in_ledger_standalone", "3");
172  return cfg;
173  }));
174  Env_ss envs(env);
175 
176  auto const alice = Account("alice");
177  env.fund(XRP(100000), alice);
178 
179  auto params = Json::Value(Json::objectValue);
180  // Max fee = 50k drops
181  params[jss::fee_mult_max] = 5000;
182  std::vector<int> const expectedFees({10, 10, 8889, 13889, 20000});
183 
184  // We should be able to submit 5 transactions within
185  // our fee limit.
186  for (int i = 0; i < 5; ++i)
187  {
188  envs(noop(alice), fee(none), seq(none))(params);
189 
190  auto tx = env.tx();
191  if (BEAST_EXPECT(tx))
192  {
193  BEAST_EXPECT(tx->getAccountID(sfAccount) == alice.id());
194  BEAST_EXPECT(tx->getTxnType() == ttACCOUNT_SET);
195  auto const fee = tx->getFieldAmount(sfFee);
196  BEAST_EXPECT(fee == drops(expectedFees[i]));
197  }
198  }
199  }
200 
201  void
203  {
204  testcase("Fee escalation shouldn't allocate extreme memory");
205  using clock_type = std::chrono::steady_clock;
206  using namespace jtx;
207  using namespace std::chrono_literals;
208 
209  Env env(*this, envconfig([](std::unique_ptr<Config> cfg) {
210  auto& s = cfg->section("transaction_queue");
211  s.set("minimum_txn_in_ledger_standalone", "4294967295");
212  s.set("minimum_txn_in_ledger", "4294967295");
213  s.set("target_txn_in_ledger", "4294967295");
214  s.set("normal_consensus_increase_percent", "4294967295");
215 
216  return cfg;
217  }));
218 
219  env(noop(env.master));
220  // This test will probably fail if any breakpoints are encountered,
221  // but should pass on even the slowest machines.
222  auto const start = clock_type::now();
223  env.close();
224  BEAST_EXPECT(clock_type::now() - start < 1s);
225  }
226 
227  void
229  {
230  using namespace jtx;
231  using boost::asio::buffer;
232  testcase("jsonInvalid");
233 
234  std::string const request =
235  R"json({"command":"path_find","id":19,"subcommand":"create","source_account":"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh","destination_account":"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh","destination_amount":"1000000","source_currencies":[{"currency":"0000000000000000000000000000000000000000"},{"currency":"0000000000000000000000005553440000000000"},{"currency":"0000000000000000000000004254430000000000"},{"issuer":"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh","currency":"0000000000000000000000004254430000000000"},{"issuer":"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh","currency":"0000000000000000000000004254430000000000"},{"issuer":"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh","currency":"0000000000000000000000004555520000000000"},{"currency":"0000000000000000000000004554480000000000"},{"currency":"0000000000000000000000004A50590000000000"},{"issuer":"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh","currency":"000000000000000000000000434E590000000000"},{"currency":"0000000000000000000000004742490000000000"},{"issuer":"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh","currency":"0000000000000000000000004341440000000000"}]})json";
236 
237  Json::Value jvRequest;
238  Json::Reader jrReader;
239 
241  buffers.emplace_back(buffer(request, 1024));
242  buffers.emplace_back(
243  buffer(request.data() + 1024, request.length() - 1024));
244  BEAST_EXPECT(
245  jrReader.parse(jvRequest, buffers) && jvRequest.isObject());
246  }
247 
248  void
249  run() override
250  {
251  testOffer1();
256  testJsonInvalid();
257  }
258 };
259 
260 BEAST_DEFINE_TESTSUITE(Regression, app, ripple);
261 
262 } // namespace test
263 } // namespace ripple
ripple::test::jtx::json
Inject raw JSON.
Definition: jtx_json.h:31
ripple::test::jtx::noop
Json::Value noop(Account const &account)
The null transaction.
Definition: noop.h:31
ripple::Application::getNodeFamily
virtual Family & getNodeFamily()=0
std::chrono::steady_clock
ripple::test::jtx::XRP
const XRP_t XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
ripple::test::jtx::dropsPerXRP
constexpr XRPAmount dropsPerXRP
Definition: amount.h:67
Json::Value::isObject
bool isObject() const
Definition: json_value.cpp:1027
std::string
STL class.
ripple::test::jtx::drops
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Definition: amount.h:241
ripple::test::jtx::Env::tx
std::shared_ptr< STTx const > tx() const
Return the tx data for the last JTx.
Definition: Env.cpp:382
ripple::apply
std::pair< TER, bool > apply(Application &app, OpenView &view, STTx const &tx, ApplyFlags flags, beast::Journal journal)
Apply a transaction to an OpenView.
Definition: apply.cpp:109
ripple::test::jtx::ter
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: ter.h:33
ripple::OpenView::apply
void apply(TxsRawView &to) const
Apply changes.
Definition: OpenView.cpp:130
ripple::test::jtx::owners
Match the number of items in the account's owner directory.
Definition: owners.h:69
ripple::test::jtx::balance
A balance matches.
Definition: balance.h:38
ripple::OpenView
Writable ledger view that accumulates state and tx changes.
Definition: OpenView.h:55
std::vector
STL class.
std::string::length
T length(T... args)
ripple::sfSigningPubKey
const SF_VL sfSigningPubKey
ripple::test::jtx::JTx::stx
std::shared_ptr< STTx const > stx
Definition: JTx.h:50
ripple::test::jtx::Env::jt
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
Definition: Env.h:439
ripple::test::jtx::require
Check a set of conditions.
Definition: require.h:63
ripple::test::jtx::Env::journal
const beast::Journal journal
Definition: Env.h:144
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:241
ripple::Application::timeKeeper
virtual TimeKeeper & timeKeeper()=0
Json::Reader
Unserialize a JSON document into a Value.
Definition: json_reader.h:36
ripple::test::jtx::envconfig
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:49
ripple::tapNONE
@ tapNONE
Definition: ApplyView.h:30
ripple::INITIAL_XRP
constexpr XRPAmount INITIAL_XRP
Configure the native currency.
Definition: SystemParameters.h:43
ripple::test::Regression_test::testFeeEscalationExtremeConfig
void testFeeEscalationExtremeConfig()
Definition: Regression_test.cpp:202
ripple::KeyType::ed25519
@ ed25519
ripple::test::Regression_test::run
void run() override
Definition: Regression_test.cpp:249
ripple::test::Regression_test::testOffer1
void testOffer1()
Definition: Regression_test.cpp:33
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:133
ripple::JsonOptions::none
@ none
ripple::Application::config
virtual Config & config()=0
ripple::test::jtx::JTx
Execution context for applying a JSON transaction.
Definition: JTx.h:42
ripple::test::jtx::JTx::jv
Json::Value jv
Definition: JTx.h:44
ripple::set
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Definition: BasicConfig.h:313
ripple::test::jtx::Env::close
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:121
ripple::TimeKeeper::closeTime
virtual time_point closeTime() const =0
Returns the close time, in network time.
ripple::tecINSUFF_FEE
@ tecINSUFF_FEE
Definition: TER.h:269
std::uint32_t
ripple::test::jtx::sig
Set the regular signature on a JTx.
Definition: sig.h:34
ripple::test::jtx::Env::seq
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition: Env.cpp:207
ripple::test::jtx::Env_ss
A transaction testing environment wrapper.
Definition: Env_ss.h:33
ripple::test::jtx::fee
Set the fee on a JTx.
Definition: fee.h:35
ripple::KeyType::secp256k1
@ secp256k1
ripple::ttACCOUNT_SET
@ ttACCOUNT_SET
This transaction type adjusts various account settings.
Definition: TxFormats.h:68
ripple::test::jtx::seq
Set the sequence number on a JTx.
Definition: seq.h:33
ripple::test::Regression_test::testFeeEscalationAutofill
void testFeeEscalationAutofill()
Definition: Regression_test.cpp:165
ripple::test::Regression_test::testSecp256r1key
void testSecp256r1key()
Definition: Regression_test.cpp:120
std::vector::emplace_back
T emplace_back(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::jtx::pay
Json::Value pay(Account const &account, Account const &to, AnyAmount amount)
Create a payment.
Definition: pay.cpp:29
ripple::test::jtx::JTx::fill_sig
bool fill_sig
Definition: JTx.h:49
ripple::test::jtx::Env::fund
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:228
ripple::create_genesis
const create_genesis_t create_genesis
Definition: Ledger.cpp:62
ripple::test::jtx::Env::master
Account const & master
Definition: Env.h:121
Json::Reader::parse
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Definition: json_reader.cpp:74
ripple::test::Regression_test::testLowBalanceDestroy
void testLowBalanceDestroy()
Definition: Regression_test.cpp:49
ripple::sfBalance
const SF_AMOUNT sfBalance
ripple::sfFee
const SF_AMOUNT sfFee
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::sfAccount
const SF_ACCOUNT sfAccount
ripple::test::jtx::Env::memoize
void memoize(Account const &account)
Associate AccountID with account.
Definition: Env.cpp:156
std::unique_ptr
STL class.
ripple::strUnHex
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
Definition: StringUtilities.h:50
ripple::test::Regression_test
Definition: Regression_test.cpp:29
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:222
std::string::data
T data(T... args)
ripple::test::Regression_test::testJsonInvalid
void testJsonInvalid()
Definition: Regression_test.cpp:228
ripple::test::jtx::Env::current
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:300
ripple::test::jtx::Env::json
Json::Value json(JsonValue &&jv, FN const &... fN)
Create JSON from parameters.
Definition: Env.h:453
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
ripple::temINVALID
@ temINVALID
Definition: TER.h:108
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)