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