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