rippled
Loading...
Searching...
No Matches
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 <test/jtx.h>
19#include <test/jtx/check.h>
20#include <test/jtx/envconfig.h>
21
22#include <xrpld/app/ledger/LedgerMaster.h>
23#include <xrpld/app/tx/apply.h>
24
25#include <xrpl/basics/CountedObject.h>
26#include <xrpl/basics/StringUtilities.h>
27#include <xrpl/json/json_reader.h>
28#include <xrpl/protocol/Indexes.h>
29#include <xrpl/protocol/jss.h>
30
31namespace ripple {
32namespace test {
33
35{
36 // OfferCreate, then OfferCreate with cancel
37 void
39 {
40 using namespace jtx;
41 Env env(*this);
42 auto const gw = Account("gw");
43 auto const USD = gw["USD"];
44 env.fund(XRP(10000), "alice", gw);
45 env(offer("alice", USD(10), XRP(10)), require(owners("alice", 1)));
46 env(offer("alice", USD(20), XRP(10)),
47 json(R"raw(
48 { "OfferSequence" : 4 }
49 )raw"),
50 require(owners("alice", 1)));
51 }
52
53 void
55 {
56 testcase("Account balance < fee destroys correct amount of XRP");
57 using namespace jtx;
58 Env env(*this);
59 env.memoize("alice");
60
61 // The low balance scenario can not deterministically
62 // be reproduced against an open ledger. Make a local
63 // closed ledger and work with it directly.
64 auto closed = std::make_shared<Ledger>(
66 env.app().config(),
68 env.app().getNodeFamily());
69 auto expectedDrops = INITIAL_XRP;
70 BEAST_EXPECT(closed->info().drops == expectedDrops);
71
72 auto const aliceXRP = 400;
73 auto const aliceAmount = XRP(aliceXRP);
74
75 auto next = std::make_shared<Ledger>(
76 *closed, env.app().timeKeeper().closeTime());
77 {
78 // Fund alice
79 auto const jt = env.jt(pay(env.master, "alice", aliceAmount));
80 OpenView accum(&*next);
81
82 auto const result =
83 ripple::apply(env.app(), accum, *jt.stx, tapNONE, env.journal);
84 BEAST_EXPECT(result.ter == tesSUCCESS);
85 BEAST_EXPECT(result.applied);
86
87 accum.apply(*next);
88 }
89 expectedDrops -= next->fees().base;
90 BEAST_EXPECT(next->info().drops == expectedDrops);
91 {
92 auto const sle = next->read(keylet::account(Account("alice").id()));
93 BEAST_EXPECT(sle);
94 auto balance = sle->getFieldAmount(sfBalance);
95
96 BEAST_EXPECT(balance == aliceAmount);
97 }
98
99 {
100 // Specify the seq manually since the env's open ledger
101 // doesn't know about this account.
102 auto const jt = env.jt(noop("alice"), fee(expectedDrops), seq(2));
103
104 OpenView accum(&*next);
105
106 auto const result =
107 ripple::apply(env.app(), accum, *jt.stx, tapNONE, env.journal);
108 BEAST_EXPECT(result.ter == tecINSUFF_FEE);
109 BEAST_EXPECT(result.applied);
110
111 accum.apply(*next);
112 }
113 {
114 auto const sle = next->read(keylet::account(Account("alice").id()));
115 BEAST_EXPECT(sle);
116 auto balance = sle->getFieldAmount(sfBalance);
117
118 BEAST_EXPECT(balance == XRP(0));
119 }
120 expectedDrops -= aliceXRP * dropsPerXRP;
121 BEAST_EXPECT(next->info().drops == expectedDrops);
122 }
123
124 void
126 {
127 testcase("Signing with a secp256r1 key should fail gracefully");
128 using namespace jtx;
129 Env env(*this);
130
131 // Test case we'll use.
132 auto test256r1key = [&env](Account const& acct) {
133 auto const baseFee = env.current()->fees().base;
134 std::uint32_t const acctSeq = env.seq(acct);
135 Json::Value jsonNoop =
136 env.json(noop(acct), fee(baseFee), seq(acctSeq), sig(acct));
137 JTx jt = env.jt(jsonNoop);
138 jt.fill_sig = false;
139
140 // Random secp256r1 public key generated by
141 // https://kjur.github.io/jsrsasign/sample-ecdsa.html
142 std::string const secp256r1PubKey =
143 "045d02995ec24988d9a2ae06a3733aa35ba0741e87527"
144 "ed12909b60bd458052c944b24cbf5893c3e5be321774e"
145 "5082e11c034b765861d0effbde87423f8476bb2c";
146
147 // Set the key in the JSON.
148 jt.jv["SigningPubKey"] = secp256r1PubKey;
149
150 // Set the same key in the STTx.
151 auto secp256r1Sig = std::make_unique<STTx>(*(jt.stx));
152 auto pubKeyBlob = strUnHex(secp256r1PubKey);
153 assert(pubKeyBlob); // Hex for public key must be valid
154 secp256r1Sig->setFieldVL(sfSigningPubKey, *pubKeyBlob);
155 jt.stx.reset(secp256r1Sig.release());
156
157 env(jt,
158 rpc("invalidTransaction",
159 "fails local checks: Invalid signature."));
160 };
161
162 Account const alice{"alice", KeyType::secp256k1};
163 Account const becky{"becky", KeyType::ed25519};
164
165 env.fund(XRP(10000), alice, becky);
166
167 test256r1key(alice);
168 test256r1key(becky);
169 }
170
171 void
173 {
174 testcase("Autofilled fee should use the escalated fee");
175 using namespace jtx;
176 Env env(*this, envconfig([](std::unique_ptr<Config> cfg) {
177 cfg->section("transaction_queue")
178 .set("minimum_txn_in_ledger_standalone", "3");
179 cfg->FEES.reference_fee = 10;
180 return cfg;
181 }));
182 Env_ss envs(env);
183
184 auto const alice = Account("alice");
185 env.fund(XRP(100000), alice);
186
187 auto params = Json::Value(Json::objectValue);
188 // Max fee = 50k drops
189 params[jss::fee_mult_max] = 5000;
190 std::vector<int> const expectedFees({10, 10, 8889, 13889, 20000});
191
192 // We should be able to submit 5 transactions within
193 // our fee limit.
194 for (int i = 0; i < 5; ++i)
195 {
196 envs(noop(alice), fee(none), seq(none))(params);
197
198 auto tx = env.tx();
199 if (BEAST_EXPECT(tx))
200 {
201 BEAST_EXPECT(tx->getAccountID(sfAccount) == alice.id());
202 BEAST_EXPECT(tx->getTxnType() == ttACCOUNT_SET);
203 auto const fee = tx->getFieldAmount(sfFee);
204 BEAST_EXPECT(fee == drops(expectedFees[i]));
205 }
206 }
207 }
208
209 void
211 {
212 testcase("Fee escalation shouldn't allocate extreme memory");
213 using clock_type = std::chrono::steady_clock;
214 using namespace jtx;
215 using namespace std::chrono_literals;
216
217 Env env(*this, envconfig([](std::unique_ptr<Config> cfg) {
218 auto& s = cfg->section("transaction_queue");
219 s.set("minimum_txn_in_ledger_standalone", "4294967295");
220 s.set("minimum_txn_in_ledger", "4294967295");
221 s.set("target_txn_in_ledger", "4294967295");
222 s.set("normal_consensus_increase_percent", "4294967295");
223
224 return cfg;
225 }));
226
227 env(noop(env.master));
228 // This test will probably fail if any breakpoints are encountered,
229 // but should pass on even the slowest machines.
230 auto const start = clock_type::now();
231 env.close();
232 BEAST_EXPECT(clock_type::now() - start < 1s);
233 }
234
235 void
237 {
238 using namespace jtx;
239 using boost::asio::buffer;
240 testcase("jsonInvalid");
241
242 std::string const request =
243 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";
244
245 Json::Value jvRequest;
246 Json::Reader jrReader;
247
249 buffers.emplace_back(buffer(request, 1024));
250 buffers.emplace_back(
251 buffer(request.data() + 1024, request.length() - 1024));
252 BEAST_EXPECT(
253 jrReader.parse(jvRequest, buffers) && jvRequest.isObject());
254 }
255
256 void
258 {
259 testcase("Invalid Transaction Object ID Type");
260 // Crasher bug introduced in 2.0.1. Fixed in 2.3.0.
261
262 using namespace jtx;
263 Env env(*this);
264
265 Account alice("alice");
266 Account bob("bob");
267 env.fund(XRP(10'000), alice, bob);
268 env.close();
269
270 {
271 auto const alice_index = keylet::account(alice).key;
272 if (BEAST_EXPECT(alice_index.isNonZero()))
273 {
274 env(check::cash(
275 alice, alice_index, check::DeliverMin(XRP(100))),
277 }
278 }
279
280 {
281 auto const bob_index = keylet::account(bob).key;
282
283 auto const digest = [&]() -> std::optional<uint256> {
284 auto const& state =
285 env.app().getLedgerMaster().getClosedLedger()->stateMap();
287 if (!state.peekItem(bob_index, digest))
288 return std::nullopt;
289 return digest.as_uint256();
290 }();
291
292 auto const mapCounts = [&](CountedObjects::List const& list) {
294 for (auto const& e : list)
295 {
296 result[e.first] = e.second;
297 }
298
299 return result;
300 };
301
302 if (BEAST_EXPECT(bob_index.isNonZero()) &&
303 BEAST_EXPECT(digest.has_value()))
304 {
305 auto& cache = env.app().cachedSLEs();
306 cache.del(*digest, false);
307 auto const beforeCounts =
308 mapCounts(CountedObjects::getInstance().getCounts(0));
309
310 env(check::cash(alice, bob_index, check::DeliverMin(XRP(100))),
312
313 auto const afterCounts =
314 mapCounts(CountedObjects::getInstance().getCounts(0));
315
316 using namespace std::string_literals;
317 BEAST_EXPECT(
318 beforeCounts.at("CachedView::hit"s) ==
319 afterCounts.at("CachedView::hit"s));
320 BEAST_EXPECT(
321 beforeCounts.at("CachedView::hitExpired"s) + 1 ==
322 afterCounts.at("CachedView::hitExpired"s));
323 BEAST_EXPECT(
324 beforeCounts.at("CachedView::miss"s) ==
325 afterCounts.at("CachedView::miss"s));
326 }
327 }
328 }
329
330 void
331 run() override
332 {
333 testOffer1();
340 }
341};
342
343BEAST_DEFINE_TESTSUITE(Regression, app, ripple);
344
345} // namespace test
346} // namespace ripple
Unserialize a JSON document into a Value.
Definition: json_reader.h:39
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Definition: json_reader.cpp:78
Represents a JSON value.
Definition: json_value.h:150
bool isObject() const
A testsuite class.
Definition: suite.h:55
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:155
virtual CachedSLEs & cachedSLEs()=0
virtual Config & config()=0
virtual TimeKeeper & timeKeeper()=0
virtual Family & getNodeFamily()=0
virtual LedgerMaster & getLedgerMaster()=0
static CountedObjects & getInstance() noexcept
std::shared_ptr< Ledger const > getClosedLedger()
Definition: LedgerMaster.h:79
Writable ledger view that accumulates state and tx changes.
Definition: OpenView.h:57
void apply(TxsRawView &to) const
Apply changes.
Definition: OpenView.cpp:131
bool del(key_type const &key, bool valid)
time_point closeTime() const
Returns the predicted close time, in network time.
Definition: TimeKeeper.h:76
Immutable cryptographic account descriptor.
Definition: Account.h:39
A transaction testing environment wrapper.
Definition: Env_ss.h:34
A transaction testing environment.
Definition: Env.h:121
Json::Value json(JsonValue &&jv, FN const &... fN)
Create JSON from parameters.
Definition: Env.h:522
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition: Env.cpp:212
std::shared_ptr< STTx const > tx() const
Return the tx data for the last JTx.
Definition: Env.cpp:455
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:331
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:117
Account const & master
Definition: Env.h:125
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
Definition: Env.h:496
Application & app()
Definition: Env.h:261
beast::Journal const journal
Definition: Env.h:162
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:233
void memoize(Account const &account)
Associate AccountID with account.
Definition: Env.cpp:152
A balance matches.
Definition: balance.h:39
Set the fee on a JTx.
Definition: fee.h:37
Inject raw JSON.
Definition: jtx_json.h:33
Match the number of items in the account's owner directory.
Definition: owners.h:73
Check a set of conditions.
Definition: require.h:65
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: rpc.h:35
Set the regular signature on a JTx.
Definition: sig.h:35
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: ter.h:35
T data(T... args)
T emplace_back(T... args)
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:46
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:177
Json::Value cash(jtx::Account const &dest, uint256 const &checkId, STAmount const &amount)
Cash a check requiring that a specific amount be delivered.
Definition: check.cpp:33
static none_t const none
Definition: tags.h:34
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
constexpr XRPAmount dropsPerXRP
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition: pay.cpp:30
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:54
Json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
Definition: offer.cpp:29
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
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:315
constexpr XRPAmount INITIAL_XRP
Configure the native currency.
static Hasher::result_type digest(void const *data, std::size_t size) noexcept
Definition: tokens.cpp:156
@ tecNO_ENTRY
Definition: TER.h:306
@ tecINSUFF_FEE
Definition: TER.h:302
@ tesSUCCESS
Definition: TER.h:244
ApplyResult apply(Application &app, OpenView &view, STTx const &tx, ApplyFlags flags, beast::Journal journal)
Apply a transaction to an OpenView.
Definition: apply.cpp:110
create_genesis_t const create_genesis
Definition: Ledger.cpp:51
@ tapNONE
Definition: ApplyView.h:32
T length(T... args)
uint256 key
Definition: Keylet.h:40
void run() override
Runs the suite.
Execution context for applying a JSON transaction.
Definition: JTx.h:45
std::shared_ptr< STTx const > stx
Definition: JTx.h:56
Json::Value jv
Definition: JTx.h:46
Type used to specify DeliverMin for cashing a check.
Definition: check.h:40
Set the sequence number on a JTx.
Definition: seq.h:34