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