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 return cfg;
180 }));
181 Env_ss envs(env);
182
183 auto const alice = Account("alice");
184 env.fund(XRP(100000), alice);
185
186 auto params = Json::Value(Json::objectValue);
187 // Max fee = 50k drops
188 params[jss::fee_mult_max] = 5000;
189 std::vector<int> const expectedFees({10, 10, 8889, 13889, 20000});
190
191 // We should be able to submit 5 transactions within
192 // our fee limit.
193 for (int i = 0; i < 5; ++i)
194 {
195 envs(noop(alice), fee(none), seq(none))(params);
196
197 auto tx = env.tx();
198 if (BEAST_EXPECT(tx))
199 {
200 BEAST_EXPECT(tx->getAccountID(sfAccount) == alice.id());
201 BEAST_EXPECT(tx->getTxnType() == ttACCOUNT_SET);
202 auto const fee = tx->getFieldAmount(sfFee);
203 BEAST_EXPECT(fee == drops(expectedFees[i]));
204 }
205 }
206 }
207
208 void
210 {
211 testcase("Fee escalation shouldn't allocate extreme memory");
212 using clock_type = std::chrono::steady_clock;
213 using namespace jtx;
214 using namespace std::chrono_literals;
215
216 Env env(*this, envconfig([](std::unique_ptr<Config> cfg) {
217 auto& s = cfg->section("transaction_queue");
218 s.set("minimum_txn_in_ledger_standalone", "4294967295");
219 s.set("minimum_txn_in_ledger", "4294967295");
220 s.set("target_txn_in_ledger", "4294967295");
221 s.set("normal_consensus_increase_percent", "4294967295");
222
223 return cfg;
224 }));
225
226 env(noop(env.master));
227 // This test will probably fail if any breakpoints are encountered,
228 // but should pass on even the slowest machines.
229 auto const start = clock_type::now();
230 env.close();
231 BEAST_EXPECT(clock_type::now() - start < 1s);
232 }
233
234 void
236 {
237 using namespace jtx;
238 using boost::asio::buffer;
239 testcase("jsonInvalid");
240
241 std::string const request =
242 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";
243
244 Json::Value jvRequest;
245 Json::Reader jrReader;
246
248 buffers.emplace_back(buffer(request, 1024));
249 buffers.emplace_back(
250 buffer(request.data() + 1024, request.length() - 1024));
251 BEAST_EXPECT(
252 jrReader.parse(jvRequest, buffers) && jvRequest.isObject());
253 }
254
255 void
257 {
258 testcase("Invalid Transaction Object ID Type");
259 // Crasher bug introduced in 2.0.1. Fixed in 2.3.0.
260
261 using namespace jtx;
262 Env env(*this);
263
264 Account alice("alice");
265 Account bob("bob");
266 env.fund(XRP(10'000), alice, bob);
267 env.close();
268
269 {
270 auto const alice_index = keylet::account(alice).key;
271 if (BEAST_EXPECT(alice_index.isNonZero()))
272 {
273 env(check::cash(
274 alice, alice_index, check::DeliverMin(XRP(100))),
276 }
277 }
278
279 {
280 auto const bob_index = keylet::account(bob).key;
281
282 auto const digest = [&]() -> std::optional<uint256> {
283 auto const& state =
284 env.app().getLedgerMaster().getClosedLedger()->stateMap();
286 if (!state.peekItem(bob_index, digest))
287 return std::nullopt;
288 return digest.as_uint256();
289 }();
290
291 auto const mapCounts = [&](CountedObjects::List const& list) {
293 for (auto const& e : list)
294 {
295 result[e.first] = e.second;
296 }
297
298 return result;
299 };
300
301 if (BEAST_EXPECT(bob_index.isNonZero()) &&
302 BEAST_EXPECT(digest.has_value()))
303 {
304 auto& cache = env.app().cachedSLEs();
305 cache.del(*digest, false);
306 auto const beforeCounts =
307 mapCounts(CountedObjects::getInstance().getCounts(0));
308
309 env(check::cash(alice, bob_index, check::DeliverMin(XRP(100))),
311
312 auto const afterCounts =
313 mapCounts(CountedObjects::getInstance().getCounts(0));
314
315 using namespace std::string_literals;
316 BEAST_EXPECT(
317 beforeCounts.at("CachedView::hit"s) ==
318 afterCounts.at("CachedView::hit"s));
319 BEAST_EXPECT(
320 beforeCounts.at("CachedView::hitExpired"s) + 1 ==
321 afterCounts.at("CachedView::hitExpired"s));
322 BEAST_EXPECT(
323 beforeCounts.at("CachedView::miss"s) ==
324 afterCounts.at("CachedView::miss"s));
325 }
326 }
327 }
328
329 void
330 run() override
331 {
332 testOffer1();
339 }
340};
341
342BEAST_DEFINE_TESTSUITE(Regression, app, ripple);
343
344} // namespace test
345} // 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:148
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(const key_type &key, bool valid)
Definition: TaggedCache.h:270
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:120
Json::Value json(JsonValue &&jv, FN const &... fN)
Create JSON from parameters.
Definition: Env.h:519
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:328
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:124
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
Definition: Env.h:493
Application & app()
Definition: Env.h:258
beast::Journal const journal
Definition: Env.h:161
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:44
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:175
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 noop(Account const &account)
The null transaction.
Definition: noop.h:31
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:293
@ tecINSUFF_FEE
Definition: TER.h:289
@ tesSUCCESS
Definition: TER.h:242
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