From b9814dc4cdc038a8e2b9d9bbf0b09d4e15ebbe2c Mon Sep 17 00:00:00 2001 From: bthomee Date: Tue, 29 Jul 2025 17:33:31 +0000 Subject: [PATCH] deploy: baf4b8381f32d00e05d4e5bc0598d14ab80c00ac --- DeliveredAmount__test_8cpp_source.html | 768 ++-- Payment_8cpp_source.html | 207 +- ...ipple_1_1test_1_1CheckDeliveredAmount.html | 24 +- ...test_1_1DeliveredAmount__test-members.html | 15 +- ...pple_1_1test_1_1DeliveredAmount__test.html | 38 +- functions_a.html | 18 +- functions_c.html | 28 +- functions_d.html | 2 +- functions_e.html | 8 +- functions_f.html | 2 +- functions_func.html | 4 +- functions_func_b.html | 2 +- functions_func_c.html | 4 +- functions_func_d.html | 2 +- functions_func_e.html | 12 +- functions_func_j.html | 2 +- functions_func_l.html | 8 +- functions_func_m.html | 2 +- functions_func_p.html | 14 +- functions_func_r.html | 2 +- functions_func_s.html | 12 +- functions_func_t.html | 9 +- functions_func_v.html | 12 +- functions_g.html | 3 +- functions_h.html | 2 +- functions_i.html | 4 +- functions_l.html | 12 +- functions_n.html | 6 +- functions_p.html | 9 +- functions_q.html | 3 +- functions_r.html | 2 +- functions_s.html | 17 +- functions_t.html | 31 +- functions_u.html | 2 +- functions_v.html | 9 +- functions_w.html | 8 +- search/all_10.js | 841 ++-- search/all_11.js | 1058 +++-- search/all_12.js | 17 +- search/all_13.js | 938 ++--- search/all_14.js | 2298 +++++----- search/all_15.js | 3745 +++++++++-------- search/all_16.js | 639 ++- search/all_17.js | 539 ++- search/all_18.js | 184 +- search/all_1c.js | 4 +- search/all_2.js | 1602 +++---- search/all_3.js | 747 ++-- search/all_4.js | 1238 +++--- search/all_5.js | 901 ++-- search/all_6.js | 258 +- search/all_7.js | 791 ++-- search/all_8.js | 4 +- search/all_9.js | 407 +- search/all_a.js | 184 +- search/all_b.js | 40 +- search/all_c.js | 59 +- search/all_d.js | 903 ++-- search/all_e.js | 1419 +++---- search/all_f.js | 353 +- search/enums_2.js | 4 +- search/enumvalues_e.js | 4 +- search/functions_1.js | 923 ++-- search/functions_10.js | 14 +- search/functions_12.js | 20 +- search/functions_13.js | 299 +- search/functions_14.js | 1490 +++---- search/functions_15.js | 201 +- search/functions_16.js | 60 +- search/functions_17.js | 4 +- search/functions_1b.js | 4 +- search/functions_2.js | 301 +- search/functions_3.js | 521 +-- search/functions_4.js | 4 +- search/functions_5.js | 12 +- search/functions_8.js | 4 +- search/functions_9.js | 4 +- search/functions_a.js | 10 +- search/functions_c.js | 8 +- search/functions_d.js | 4 +- search/functions_f.js | 57 +- search/typedefs_2.js | 53 +- search/typedefs_c.js | 4 +- search/variables_13.js | 4 +- search/variables_16.js | 6 +- search/variables_3.js | 47 +- search/variables_c.js | 4 +- search/variables_d.js | 8 +- 88 files changed, 12343 insertions(+), 12203 deletions(-) diff --git a/DeliveredAmount__test_8cpp_source.html b/DeliveredAmount__test_8cpp_source.html index 95d948b055..e01c218db1 100644 --- a/DeliveredAmount__test_8cpp_source.html +++ b/DeliveredAmount__test_8cpp_source.html @@ -99,349 +99,437 @@ $(function() {
21#include <test/jtx/WSClient.h>
22
23#include <xrpl/beast/unit_test.h>
-
24#include <xrpl/protocol/jss.h>
-
25
-
26namespace ripple {
-
27namespace test {
-
28
-
29// Helper class to track the expected number `delivered_amount` results.
-
30class CheckDeliveredAmount
-
31{
-
32 // If the test occurs before or after the switch time
-
33 bool afterSwitchTime_;
-
34 // number of payments expected 'delivered_amount' available
-
35 int numExpectedAvailable_ = 0;
-
36 // Number of payments with field with `delivered_amount` set to the
-
37 // string "unavailable"
-
38 int numExpectedSetUnavailable_ = 0;
-
39 // Number of payments with no `delivered_amount` field
-
40 int numExpectedNotSet_ = 0;
-
41
-
42 // Increment one of the expected numExpected{Available_, Unavailable_,
-
43 // NotSet_} values. Which value to increment depends on: 1) If the ledger is
-
44 // before or after the switch time 2) If the tx is a partial payment 3) If
-
45 // the payment is successful or not
-
46 void
-
47 adjCounters(bool success, bool partial)
-
48 {
-
49 if (!success)
-
50 {
-
51 ++numExpectedNotSet_;
-
52 return;
-
53 }
-
54 if (!afterSwitchTime_)
-
55 {
-
56 if (partial)
-
57 ++numExpectedAvailable_;
-
58 else
-
59 ++numExpectedSetUnavailable_;
-
60 return;
-
61 }
-
62 // normal case: after switch time & successful transaction
-
63 ++numExpectedAvailable_;
-
64 }
-
65
-
66public:
-
67 explicit CheckDeliveredAmount(bool afterSwitchTime)
-
68 : afterSwitchTime_(afterSwitchTime)
-
69 {
-
70 }
-
71
-
72 void
-
73 adjCountersSuccess()
-
74 {
-
75 adjCounters(true, false);
-
76 }
-
77
-
78 void
-
79 adjCountersFail()
-
80 {
-
81 adjCounters(false, false);
-
82 }
-
83 void
-
84 adjCountersPartialPayment()
-
85 {
-
86 adjCounters(true, true);
-
87 }
-
88
-
89 // After all the txns are checked, all the `numExpected` variables should be
-
90 // zero. The `checkTxn` function decrements these variables.
-
91 bool
-
92 checkExpectedCounters() const
-
93 {
-
94 return !numExpectedAvailable_ && !numExpectedNotSet_ &&
-
95 !numExpectedSetUnavailable_;
-
96 }
-
97
-
98 // Check if the transaction has `delivered_amount` in the metaData as
-
99 // expected from our rules. Decrements the appropriate `numExpected`
-
100 // variable. After all the txns are checked, all the `numExpected` variables
-
101 // should be zero.
-
102 bool
-
103 checkTxn(Json::Value const& t, Json::Value const& metaData)
-
104 {
-
105 if (t[jss::TransactionType].asString() != jss::Payment)
-
106 return true;
-
107
-
108 bool isSet = metaData.isMember(jss::delivered_amount);
-
109 bool isSetUnavailable = false;
-
110 bool isSetAvailable = false;
-
111 if (isSet)
-
112 {
-
113 if (metaData[jss::delivered_amount] != "unavailable")
-
114 isSetAvailable = true;
-
115 else
-
116 isSetUnavailable = true;
-
117 }
-
118 if (isSetAvailable)
-
119 --numExpectedAvailable_;
-
120 else if (isSetUnavailable)
-
121 --numExpectedSetUnavailable_;
-
122 else if (!isSet)
-
123 --numExpectedNotSet_;
-
124
-
125 if (isSet)
-
126 {
-
127 if (metaData.isMember(sfDeliveredAmount.jsonName))
-
128 {
-
129 if (metaData[jss::delivered_amount] !=
-
130 metaData[sfDeliveredAmount.jsonName])
-
131 return false;
-
132 }
-
133 else
-
134 {
-
135 if (afterSwitchTime_)
-
136 {
-
137 if (metaData[jss::delivered_amount] != t[jss::Amount])
-
138 return false;
-
139 }
-
140 else
-
141 {
-
142 if (metaData[jss::delivered_amount] != "unavailable")
-
143 return false;
-
144 }
-
145 }
-
146 }
-
147
-
148 if (metaData[sfTransactionResult.jsonName] != "tesSUCCESS")
-
149 {
-
150 if (isSet)
-
151 return false;
-
152 }
-
153 else
-
154 {
-
155 if (afterSwitchTime_)
-
156 {
-
157 if (!isSetAvailable)
-
158 return false;
-
159 }
-
160 else
-
161 {
-
162 if (metaData.isMember(sfDeliveredAmount.jsonName))
-
163 {
-
164 if (!isSetAvailable)
-
165 return false;
-
166 }
-
167 else
-
168 {
-
169 if (!isSetUnavailable)
-
170 return false;
-
171 }
-
172 }
-
173 }
-
174 return true;
-
175 }
-
176};
-
177
-
178class DeliveredAmount_test : public beast::unit_test::suite
-
179{
-
180 void
-
181 testAccountDeliveredAmountSubscribe()
-
182 {
-
183 testcase("Ledger Request Subscribe DeliveredAmount");
-
184
-
185 using namespace test::jtx;
-
186 using namespace std::chrono_literals;
-
187
-
188 Account const alice("alice");
-
189 Account const bob("bob");
-
190 Account const carol("carol");
-
191 auto const gw = Account("gateway");
-
192 auto const USD = gw["USD"];
-
193
-
194 for (bool const afterSwitchTime : {true, false})
-
195 {
-
196 auto cfg = envconfig();
-
197 cfg->FEES.reference_fee = 10;
-
198 Env env(*this, std::move(cfg));
-
199 env.fund(XRP(10000), alice, bob, carol, gw);
-
200 env.trust(USD(1000), alice, bob, carol);
-
201 if (afterSwitchTime)
-
202 env.close(NetClock::time_point{446000000s});
-
203 else
-
204 env.close();
-
205
-
206 CheckDeliveredAmount checkDeliveredAmount{afterSwitchTime};
-
207 {
-
208 // add payments, but do no close until subscribed
-
209
-
210 // normal payments
-
211 env(pay(gw, alice, USD(50)));
-
212 checkDeliveredAmount.adjCountersSuccess();
-
213 env(pay(gw, alice, XRP(50)));
-
214 checkDeliveredAmount.adjCountersSuccess();
-
215
-
216 // partial payment
-
217 env(pay(gw, bob, USD(9999999)), txflags(tfPartialPayment));
-
218 checkDeliveredAmount.adjCountersPartialPayment();
-
219 env.require(balance(bob, USD(1000)));
-
220
-
221 // failed payment
-
222 env(pay(bob, carol, USD(9999999)), ter(tecPATH_PARTIAL));
-
223 checkDeliveredAmount.adjCountersFail();
-
224 env.require(balance(carol, USD(0)));
-
225 }
-
226
-
227 auto wsc = makeWSClient(env.app().config());
-
228
-
229 {
-
230 Json::Value stream;
-
231 // RPC subscribe to ledger stream
-
232 stream[jss::streams] = Json::arrayValue;
-
233 stream[jss::streams].append("ledger");
-
234 stream[jss::accounts] = Json::arrayValue;
-
235 stream[jss::accounts].append(toBase58(alice.id()));
-
236 stream[jss::accounts].append(toBase58(bob.id()));
-
237 stream[jss::accounts].append(toBase58(carol.id()));
-
238 auto jv = wsc->invoke("subscribe", stream);
-
239 if (wsc->version() == 2)
-
240 {
-
241 BEAST_EXPECT(
-
242 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
-
243 BEAST_EXPECT(
-
244 jv.isMember(jss::ripplerpc) &&
-
245 jv[jss::ripplerpc] == "2.0");
-
246 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
-
247 }
-
248 BEAST_EXPECT(jv[jss::result][jss::ledger_index] == 3);
-
249 }
-
250 {
-
251 env.close();
-
252 // Check stream update
-
253 while (true)
-
254 {
-
255 auto const r = wsc->findMsg(1s, [&](auto const& jv) {
-
256 return jv[jss::ledger_index] == 4;
-
257 });
-
258 if (!r)
-
259 break;
-
260
-
261 if (!r->isMember(jss::transaction))
-
262 continue;
-
263
-
264 BEAST_EXPECT(checkDeliveredAmount.checkTxn(
-
265 (*r)[jss::transaction], (*r)[jss::meta]));
-
266 }
-
267 }
-
268 BEAST_EXPECT(checkDeliveredAmount.checkExpectedCounters());
-
269 }
-
270 }
-
271 void
-
272 testTxDeliveredAmountRPC()
-
273 {
-
274 testcase("Ledger Request RPC DeliveredAmount");
-
275
-
276 using namespace test::jtx;
-
277 using namespace std::chrono_literals;
-
278
-
279 Account const alice("alice");
-
280 Account const bob("bob");
-
281 Account const carol("carol");
-
282 auto const gw = Account("gateway");
-
283 auto const USD = gw["USD"];
-
284
-
285 for (bool const afterSwitchTime : {true, false})
-
286 {
-
287 auto cfg = envconfig();
-
288 cfg->FEES.reference_fee = 10;
-
289 Env env(*this, std::move(cfg));
-
290 env.fund(XRP(10000), alice, bob, carol, gw);
-
291 env.trust(USD(1000), alice, bob, carol);
-
292 if (afterSwitchTime)
-
293 env.close(NetClock::time_point{446000000s});
-
294 else
-
295 env.close();
-
296
-
297 CheckDeliveredAmount checkDeliveredAmount{afterSwitchTime};
-
298 // normal payments
-
299 env(pay(gw, alice, USD(50)));
-
300 checkDeliveredAmount.adjCountersSuccess();
-
301 env(pay(gw, alice, XRP(50)));
-
302 checkDeliveredAmount.adjCountersSuccess();
-
303
-
304 // partial payment
-
305 env(pay(gw, bob, USD(9999999)), txflags(tfPartialPayment));
-
306 checkDeliveredAmount.adjCountersPartialPayment();
-
307 env.require(balance(bob, USD(1000)));
-
308
-
309 // failed payment
-
310 env(pay(gw, carol, USD(9999999)), ter(tecPATH_PARTIAL));
-
311 checkDeliveredAmount.adjCountersFail();
-
312 env.require(balance(carol, USD(0)));
-
313
-
314 env.close();
-
315 std::string index;
-
316 Json::Value jvParams;
-
317 jvParams[jss::ledger_index] = 4u;
-
318 jvParams[jss::transactions] = true;
-
319 jvParams[jss::expand] = true;
-
320 auto const jtxn = env.rpc(
-
321 "json",
-
322 "ledger",
-
323 to_string(
-
324 jvParams))[jss::result][jss::ledger][jss::transactions];
-
325 for (auto const& t : jtxn)
-
326 BEAST_EXPECT(
-
327 checkDeliveredAmount.checkTxn(t, t[jss::metaData]));
-
328 BEAST_EXPECT(checkDeliveredAmount.checkExpectedCounters());
-
329 }
-
330 }
-
331
-
332public:
+
24#include <xrpl/beast/unit_test/suite.h>
+
25#include <xrpl/protocol/jss.h>
+
26
+
27namespace ripple {
+
28namespace test {
+
29
+
30// Helper class to track the expected number `delivered_amount` results.
+
31class CheckDeliveredAmount
+
32{
+
33 // If the test occurs before or after the switch time
+
34 bool afterSwitchTime_;
+
35 // number of payments expected 'delivered_amount' available
+
36 int numExpectedAvailable_ = 0;
+
37 // Number of payments with field with `delivered_amount` set to the
+
38 // string "unavailable"
+
39 int numExpectedSetUnavailable_ = 0;
+
40 // Number of payments with no `delivered_amount` field
+
41 int numExpectedNotSet_ = 0;
+
42
+
43 // Increment one of the expected numExpected{Available_, Unavailable_,
+
44 // NotSet_} values. Which value to increment depends on: 1) If the ledger is
+
45 // before or after the switch time 2) If the tx is a partial payment 3) If
+
46 // the payment is successful or not
+
47 void
+
48 adjCounters(bool success, bool partial)
+
49 {
+
50 if (!success)
+
51 {
+
52 ++numExpectedNotSet_;
+
53 return;
+
54 }
+
55 if (!afterSwitchTime_)
+
56 {
+
57 if (partial)
+
58 ++numExpectedAvailable_;
+
59 else
+
60 ++numExpectedSetUnavailable_;
+
61 return;
+
62 }
+
63 // normal case: after switch time & successful transaction
+
64 ++numExpectedAvailable_;
+
65 }
+
66
+
67public:
+
68 explicit CheckDeliveredAmount(bool afterSwitchTime)
+
69 : afterSwitchTime_(afterSwitchTime)
+
70 {
+
71 }
+
72
+
73 void
+
74 adjCountersSuccess()
+
75 {
+
76 adjCounters(true, false);
+
77 }
+
78
+
79 void
+
80 adjCountersFail()
+
81 {
+
82 adjCounters(false, false);
+
83 }
+
84 void
+
85 adjCountersPartialPayment()
+
86 {
+
87 adjCounters(true, true);
+
88 }
+
89
+
90 // After all the txns are checked, all the `numExpected` variables should be
+
91 // zero. The `checkTxn` function decrements these variables.
+
92 bool
+
93 checkExpectedCounters() const
+
94 {
+
95 return !numExpectedAvailable_ && !numExpectedNotSet_ &&
+
96 !numExpectedSetUnavailable_;
+
97 }
+
98
+
99 // Check if the transaction has `delivered_amount` in the metaData as
+
100 // expected from our rules. Decrements the appropriate `numExpected`
+
101 // variable. After all the txns are checked, all the `numExpected` variables
+
102 // should be zero.
+
103 bool
+
104 checkTxn(Json::Value const& t, Json::Value const& metaData)
+
105 {
+
106 if (t[jss::TransactionType].asString() != jss::Payment)
+
107 return true;
+
108
+
109 bool isSet = metaData.isMember(jss::delivered_amount);
+
110 bool isSetUnavailable = false;
+
111 bool isSetAvailable = false;
+
112 if (isSet)
+
113 {
+
114 if (metaData[jss::delivered_amount] != "unavailable")
+
115 isSetAvailable = true;
+
116 else
+
117 isSetUnavailable = true;
+
118 }
+
119 if (isSetAvailable)
+
120 --numExpectedAvailable_;
+
121 else if (isSetUnavailable)
+
122 --numExpectedSetUnavailable_;
+
123 else if (!isSet)
+
124 --numExpectedNotSet_;
+
125
+
126 if (isSet)
+
127 {
+
128 if (metaData.isMember(sfDeliveredAmount.jsonName))
+
129 {
+
130 if (metaData[jss::delivered_amount] !=
+
131 metaData[sfDeliveredAmount.jsonName])
+
132 return false;
+
133 }
+
134 else
+
135 {
+
136 if (afterSwitchTime_)
+
137 {
+
138 if (metaData[jss::delivered_amount] != t[jss::Amount])
+
139 return false;
+
140 }
+
141 else
+
142 {
+
143 if (metaData[jss::delivered_amount] != "unavailable")
+
144 return false;
+
145 }
+
146 }
+
147 }
+
148
+
149 if (metaData[sfTransactionResult.jsonName] != "tesSUCCESS")
+
150 {
+
151 if (isSet)
+
152 return false;
+
153 }
+
154 else
+
155 {
+
156 if (afterSwitchTime_)
+
157 {
+
158 if (!isSetAvailable)
+
159 return false;
+
160 }
+
161 else
+
162 {
+
163 if (metaData.isMember(sfDeliveredAmount.jsonName))
+
164 {
+
165 if (!isSetAvailable)
+
166 return false;
+
167 }
+
168 else
+
169 {
+
170 if (!isSetUnavailable)
+
171 return false;
+
172 }
+
173 }
+
174 }
+
175 return true;
+
176 }
+
177};
+
178
+
179class DeliveredAmount_test : public beast::unit_test::suite
+
180{
+
181 void
+
182 testAccountDeliveredAmountSubscribe()
+
183 {
+
184 testcase("Ledger Request Subscribe DeliveredAmount");
+
185
+
186 using namespace test::jtx;
+
187 using namespace std::chrono_literals;
+
188
+
189 Account const alice("alice");
+
190 Account const bob("bob");
+
191 Account const carol("carol");
+
192 auto const gw = Account("gateway");
+
193 auto const USD = gw["USD"];
+
194
+
195 for (bool const afterSwitchTime : {true, false})
+
196 {
+
197 auto cfg = envconfig();
+
198 cfg->FEES.reference_fee = 10;
+
199 Env env(*this, std::move(cfg));
+
200 env.fund(XRP(10000), alice, bob, carol, gw);
+
201 env.trust(USD(1000), alice, bob, carol);
+
202 if (afterSwitchTime)
+
203 env.close(NetClock::time_point{446000000s});
+
204 else
+
205 env.close();
+
206
+
207 CheckDeliveredAmount checkDeliveredAmount{afterSwitchTime};
+
208 {
+
209 // add payments, but do no close until subscribed
+
210
+
211 // normal payments
+
212 env(pay(gw, alice, USD(50)));
+
213 checkDeliveredAmount.adjCountersSuccess();
+
214 env(pay(gw, alice, XRP(50)));
+
215 checkDeliveredAmount.adjCountersSuccess();
+
216
+
217 // partial payment
+
218 env(pay(gw, bob, USD(9999999)), txflags(tfPartialPayment));
+
219 checkDeliveredAmount.adjCountersPartialPayment();
+
220 env.require(balance(bob, USD(1000)));
+
221
+
222 // failed payment
+
223 env(pay(bob, carol, USD(9999999)), ter(tecPATH_PARTIAL));
+
224 checkDeliveredAmount.adjCountersFail();
+
225 env.require(balance(carol, USD(0)));
+
226 }
+
227
+
228 auto wsc = makeWSClient(env.app().config());
+
229
+
230 {
+
231 Json::Value stream;
+
232 // RPC subscribe to ledger stream
+
233 stream[jss::streams] = Json::arrayValue;
+
234 stream[jss::streams].append("ledger");
+
235 stream[jss::accounts] = Json::arrayValue;
+
236 stream[jss::accounts].append(toBase58(alice.id()));
+
237 stream[jss::accounts].append(toBase58(bob.id()));
+
238 stream[jss::accounts].append(toBase58(carol.id()));
+
239 auto jv = wsc->invoke("subscribe", stream);
+
240 if (wsc->version() == 2)
+
241 {
+
242 BEAST_EXPECT(
+
243 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == "2.0");
+
244 BEAST_EXPECT(
+
245 jv.isMember(jss::ripplerpc) &&
+
246 jv[jss::ripplerpc] == "2.0");
+
247 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
+
248 }
+
249 BEAST_EXPECT(jv[jss::result][jss::ledger_index] == 3);
+
250 }
+
251 {
+
252 env.close();
+
253 // Check stream update
+
254 while (true)
+
255 {
+
256 auto const r = wsc->findMsg(1s, [&](auto const& jv) {
+
257 return jv[jss::ledger_index] == 4;
+
258 });
+
259 if (!r)
+
260 break;
+
261
+
262 if (!r->isMember(jss::transaction))
+
263 continue;
+
264
+
265 BEAST_EXPECT(checkDeliveredAmount.checkTxn(
+
266 (*r)[jss::transaction], (*r)[jss::meta]));
+
267 }
+
268 }
+
269 BEAST_EXPECT(checkDeliveredAmount.checkExpectedCounters());
+
270 }
+
271 }
+
272 void
+
273 testTxDeliveredAmountRPC()
+
274 {
+
275 testcase("Ledger Request RPC DeliveredAmount");
+
276
+
277 using namespace test::jtx;
+
278 using namespace std::chrono_literals;
+
279
+
280 Account const alice("alice");
+
281 Account const bob("bob");
+
282 Account const carol("carol");
+
283 auto const gw = Account("gateway");
+
284 auto const USD = gw["USD"];
+
285
+
286 for (bool const afterSwitchTime : {true, false})
+
287 {
+
288 auto cfg = envconfig();
+
289 cfg->FEES.reference_fee = 10;
+
290 Env env(*this, std::move(cfg));
+
291 env.fund(XRP(10000), alice, bob, carol, gw);
+
292 env.trust(USD(1000), alice, bob, carol);
+
293 if (afterSwitchTime)
+
294 env.close(NetClock::time_point{446000000s});
+
295 else
+
296 env.close();
+
297
+
298 CheckDeliveredAmount checkDeliveredAmount{afterSwitchTime};
+
299 // normal payments
+
300 env(pay(gw, alice, USD(50)));
+
301 checkDeliveredAmount.adjCountersSuccess();
+
302 env(pay(gw, alice, XRP(50)));
+
303 checkDeliveredAmount.adjCountersSuccess();
+
304
+
305 // partial payment
+
306 env(pay(gw, bob, USD(9999999)), txflags(tfPartialPayment));
+
307 checkDeliveredAmount.adjCountersPartialPayment();
+
308 env.require(balance(bob, USD(1000)));
+
309
+
310 // failed payment
+
311 env(pay(gw, carol, USD(9999999)), ter(tecPATH_PARTIAL));
+
312 checkDeliveredAmount.adjCountersFail();
+
313 env.require(balance(carol, USD(0)));
+
314
+
315 env.close();
+
316 std::string index;
+
317 Json::Value jvParams;
+
318 jvParams[jss::ledger_index] = 4u;
+
319 jvParams[jss::transactions] = true;
+
320 jvParams[jss::expand] = true;
+
321 auto const jtxn = env.rpc(
+
322 "json",
+
323 "ledger",
+
324 to_string(
+
325 jvParams))[jss::result][jss::ledger][jss::transactions];
+
326 for (auto const& t : jtxn)
+
327 BEAST_EXPECT(
+
328 checkDeliveredAmount.checkTxn(t, t[jss::metaData]));
+
329 BEAST_EXPECT(checkDeliveredAmount.checkExpectedCounters());
+
330 }
+
331 }
+
332
333 void
-
334 run() override
-
335 {
-
336 testTxDeliveredAmountRPC();
-
337 testAccountDeliveredAmountSubscribe();
-
338 }
-
339};
-
340
-
341BEAST_DEFINE_TESTSUITE(DeliveredAmount, app, ripple);
-
342
-
343} // namespace test
-
344} // namespace ripple
+
334 testMPTDeliveredAmountRPC(FeatureBitset features)
+
335 {
+
336 testcase("MPT DeliveredAmount");
+
337
+
338 using namespace jtx;
+
339 Account const alice("alice");
+
340 Account const carol("carol");
+
341 Account const bob("bob");
+
342 Env env{*this, features};
+
343
+
344 MPTTester mptAlice(
+
345 env, alice, {.holders = {bob, carol}, .close = false});
+
346
+
347 mptAlice.create(
+
348 {.transferFee = 25000,
+
349 .ownerCount = 1,
+
350 .holderCount = 0,
+
351 .flags = tfMPTCanTransfer});
+
352 auto const MPT = mptAlice["MPT"];
+
353
+
354 mptAlice.authorize({.account = bob});
+
355 mptAlice.authorize({.account = carol});
+
356
+
357 // issuer to holder
+
358 mptAlice.pay(alice, bob, 10000);
+
359
+
360 // holder to holder
+
361 env(pay(bob, carol, mptAlice.mpt(1000)), txflags(tfPartialPayment));
+
362 env.close();
+
363
+
364 // Get the hash for the most recent transaction.
+
365 std::string txHash{
+
366 env.tx()->getJson(JsonOptions::none)[jss::hash].asString()};
+
367 Json::Value meta = env.rpc("tx", txHash)[jss::result][jss::meta];
+
368
+
369 if (features[fixMPTDeliveredAmount])
+
370 {
+
371 BEAST_EXPECT(
+
372 meta[sfDeliveredAmount.jsonName] ==
+
373 STAmount{MPT(800)}.getJson(JsonOptions::none));
+
374 BEAST_EXPECT(
+
375 meta[jss::delivered_amount] ==
+
376 STAmount{MPT(800)}.getJson(JsonOptions::none));
+
377 }
+
378 else
+
379 {
+
380 BEAST_EXPECT(!meta.isMember(sfDeliveredAmount.jsonName));
+
381 BEAST_EXPECT(
+
382 meta[jss::delivered_amount] = Json::Value("unavailable"));
+
383 }
+
384
+
385 env(pay(bob, carol, MPT(1000)),
+
386 sendmax(MPT(1200)),
+
387 txflags(tfPartialPayment));
+
388 env.close();
+
389
+
390 txHash = env.tx()->getJson(JsonOptions::none)[jss::hash].asString();
+
391 meta = env.rpc("tx", txHash)[jss::result][jss::meta];
+
392
+
393 if (features[fixMPTDeliveredAmount])
+
394 {
+
395 BEAST_EXPECT(
+
396 meta[sfDeliveredAmount.jsonName] ==
+
397 STAmount{MPT(960)}.getJson(JsonOptions::none));
+
398 BEAST_EXPECT(
+
399 meta[jss::delivered_amount] ==
+
400 STAmount{MPT(960)}.getJson(JsonOptions::none));
+
401 }
+
402 else
+
403 {
+
404 BEAST_EXPECT(!meta.isMember(sfDeliveredAmount.jsonName));
+
405 BEAST_EXPECT(
+
406 meta[jss::delivered_amount] = Json::Value("unavailable"));
+
407 }
+
408 }
+
409
+
410public:
+
411 void
+
412 run() override
+
413 {
+
414 using namespace test::jtx;
+
415 FeatureBitset const all{testable_amendments()};
+
416
+
417 testTxDeliveredAmountRPC();
+
418 testAccountDeliveredAmountSubscribe();
+
419
+
420 testMPTDeliveredAmountRPC(all - fixMPTDeliveredAmount);
+
421 testMPTDeliveredAmountRPC(all);
+
422 }
+
423};
+
424
+
425BEAST_DEFINE_TESTSUITE(DeliveredAmount, app, ripple);
+
426
+
427} // namespace test
+
428} // namespace ripple
Represents a JSON value.
Definition: json_value.h:149
bool isMember(char const *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:962
A testsuite class.
Definition: suite.h:55
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:155
virtual Config & config()=0
-
-
void adjCountersFail()
-
CheckDeliveredAmount(bool afterSwitchTime)
-
int numExpectedNotSet_
-
void adjCountersSuccess()
-
void adjCounters(bool success, bool partial)
-
int numExpectedSetUnavailable_
-
int numExpectedAvailable_
-
void adjCountersPartialPayment()
-
bool checkExpectedCounters() const
-
bool afterSwitchTime_
-
bool checkTxn(Json::Value const &t, Json::Value const &metaData)
-
-
void testAccountDeliveredAmountSubscribe()
-
void testTxDeliveredAmountRPC()
-
void run() override
Runs the suite.
+
Definition: Feature.h:158
+
Definition: STAmount.h:50
+
Json::Value getJson(JsonOptions=JsonOptions::none) const override
Definition: STAmount.cpp:795
+
+
void adjCountersFail()
+
CheckDeliveredAmount(bool afterSwitchTime)
+
int numExpectedNotSet_
+
void adjCountersSuccess()
+
void adjCounters(bool success, bool partial)
+
int numExpectedSetUnavailable_
+
int numExpectedAvailable_
+
void adjCountersPartialPayment()
+
bool checkExpectedCounters() const
+
bool afterSwitchTime_
+
bool checkTxn(Json::Value const &t, Json::Value const &metaData)
+
+
void testAccountDeliveredAmountSubscribe()
+
void testTxDeliveredAmountRPC()
+
void testMPTDeliveredAmountRPC(FeatureBitset features)
+
void run() override
Runs the suite.
Immutable cryptographic account descriptor.
Definition: Account.h:39
AccountID id() const
Returns the Account ID.
Definition: Account.h:107
A transaction testing environment.
Definition: Env.h:121
@@ -451,20 +539,28 @@ $(function() {
Application & app()
Definition: Env.h:261
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition: Env.h:788
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:275
+
Definition: mpt.h:148
+
void create(MPTCreate const &arg=MPTCreate{})
Definition: mpt.cpp:87
+
Converts to MPT Issue or STAmount.
A balance matches.
Definition: balance.h:39
+
Sets the SendMax on a JTx.
Definition: sendmax.h:33
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: ter.h:35
Set the flags on a JTx.
Definition: txflags.h:31
@ arrayValue
array value (ordered list)
Definition: json_value.h:44
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
+
FeatureBitset testable_amendments()
Definition: Env.h:74
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
std::unique_ptr< WSClient > makeWSClient(Config const &cfg, bool v2, unsigned rpc_version, std::unordered_map< std::string, std::string > const &headers)
Returns a client operating through WebSockets/S.
Definition: WSClient.cpp:302
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:25
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:114
+
constexpr std::uint32_t const tfMPTCanTransfer
Definition: TxFlags.h:149
constexpr std::uint32_t tfPartialPayment
Definition: TxFlags.h:108
+
@ all
@ success
@ tecPATH_PARTIAL
Definition: TER.h:282
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
+
@ none
Definition: STBase.h:43
diff --git a/Payment_8cpp_source.html b/Payment_8cpp_source.html index 1ff3cffe2a..01a344ef2a 100644 --- a/Payment_8cpp_source.html +++ b/Payment_8cpp_source.html @@ -658,107 +658,116 @@ $(function() {
580 auto res = accountSend(
581 pv, account_, dstAccountID, amountDeliver, ctx_.journal);
582 if (res == tesSUCCESS)
-
583 pv.apply(ctx_.rawView());
-
584 else if (res == tecINSUFFICIENT_FUNDS || res == tecPATH_DRY)
-
585 res = tecPATH_PARTIAL;
-
586
-
587 return res;
-
588 }
-
589
-
590 XRPL_ASSERT(dstAmount.native(), "ripple::Payment::doApply : amount is XRP");
-
591
-
592 // Direct XRP payment.
-
593
-
594 auto const sleSrc = view().peek(keylet::account(account_));
-
595 if (!sleSrc)
-
596 return tefINTERNAL;
-
597
-
598 // ownerCount is the number of entries in this ledger for this
-
599 // account that require a reserve.
-
600 auto const ownerCount = sleSrc->getFieldU32(sfOwnerCount);
-
601
-
602 // This is the total reserve in drops.
-
603 auto const reserve = view().fees().accountReserve(ownerCount);
-
604
-
605 // mPriorBalance is the balance on the sending account BEFORE the
-
606 // fees were charged. We want to make sure we have enough reserve
-
607 // to send. Allow final spend to use reserve for fee.
-
608 auto const mmm = std::max(reserve, ctx_.tx.getFieldAmount(sfFee).xrp());
-
609
-
610 if (mPriorBalance < dstAmount.xrp() + mmm)
-
611 {
-
612 // Vote no. However the transaction might succeed, if applied in
-
613 // a different order.
-
614 JLOG(j_.trace()) << "Delay transaction: Insufficient funds: "
-
615 << to_string(mPriorBalance) << " / "
-
616 << to_string(dstAmount.xrp() + mmm) << " ("
-
617 << to_string(reserve) << ")";
+
583 {
+
584 pv.apply(ctx_.rawView());
+
585
+
586 // If the actual amount delivered is different from the original
+
587 // amount due to partial payment or transfer fee, we need to update
+
588 // DelieveredAmount using the actual delivered amount
+
589 if (view().rules().enabled(fixMPTDeliveredAmount) &&
+
590 amountDeliver != dstAmount)
+
591 ctx_.deliver(amountDeliver);
+
592 }
+
593 else if (res == tecINSUFFICIENT_FUNDS || res == tecPATH_DRY)
+
594 res = tecPATH_PARTIAL;
+
595
+
596 return res;
+
597 }
+
598
+
599 XRPL_ASSERT(dstAmount.native(), "ripple::Payment::doApply : amount is XRP");
+
600
+
601 // Direct XRP payment.
+
602
+
603 auto const sleSrc = view().peek(keylet::account(account_));
+
604 if (!sleSrc)
+
605 return tefINTERNAL;
+
606
+
607 // ownerCount is the number of entries in this ledger for this
+
608 // account that require a reserve.
+
609 auto const ownerCount = sleSrc->getFieldU32(sfOwnerCount);
+
610
+
611 // This is the total reserve in drops.
+
612 auto const reserve = view().fees().accountReserve(ownerCount);
+
613
+
614 // mPriorBalance is the balance on the sending account BEFORE the
+
615 // fees were charged. We want to make sure we have enough reserve
+
616 // to send. Allow final spend to use reserve for fee.
+
617 auto const mmm = std::max(reserve, ctx_.tx.getFieldAmount(sfFee).xrp());
618
-
619 return tecUNFUNDED_PAYMENT;
-
620 }
-
621
-
622 // Pseudo-accounts cannot receive payments, other than these native to
-
623 // their underlying ledger object - implemented in their respective
-
624 // transaction types. Note, this is not amendment-gated because all writes
-
625 // to pseudo-account discriminator fields **are** amendment gated, hence the
-
626 // behaviour of this check will always match the active amendments.
-
627 if (isPseudoAccount(sleDst))
-
628 return tecNO_PERMISSION;
-
629
-
630 // The source account does have enough money. Make sure the
-
631 // source account has authority to deposit to the destination.
-
632 if (depositAuth)
-
633 {
-
634 // If depositPreauth is enabled, then an account that requires
-
635 // authorization has three ways to get an XRP Payment in:
-
636 // 1. If Account == Destination, or
-
637 // 2. If Account is deposit preauthorized by destination, or
-
638 // 3. If the destination's XRP balance is
-
639 // a. less than or equal to the base reserve and
-
640 // b. the deposit amount is less than or equal to the base reserve,
-
641 // then we allow the deposit.
-
642 //
-
643 // Rule 3 is designed to keep an account from getting wedged
-
644 // in an unusable state if it sets the lsfDepositAuth flag and
-
645 // then consumes all of its XRP. Without the rule if an
-
646 // account with lsfDepositAuth set spent all of its XRP, it
-
647 // would be unable to acquire more XRP required to pay fees.
-
648 //
-
649 // We choose the base reserve as our bound because it is
-
650 // a small number that seldom changes but is always sufficient
-
651 // to get the account un-wedged.
-
652
-
653 // Get the base reserve.
-
654 XRPAmount const dstReserve{view().fees().accountReserve(0)};
-
655
-
656 if (dstAmount > dstReserve ||
-
657 sleDst->getFieldAmount(sfBalance) > dstReserve)
-
658 {
-
659 if (auto err = verifyDepositPreauth(
-
660 ctx_.tx,
-
661 ctx_.view(),
-
662 account_,
-
663 dstAccountID,
-
664 sleDst,
-
665 ctx_.journal);
-
666 !isTesSuccess(err))
-
667 return err;
-
668 }
-
669 }
-
670
-
671 // Do the arithmetic for the transfer and make the ledger change.
-
672 sleSrc->setFieldAmount(sfBalance, mSourceBalance - dstAmount);
-
673 sleDst->setFieldAmount(
-
674 sfBalance, sleDst->getFieldAmount(sfBalance) + dstAmount);
-
675
-
676 // Re-arm the password change fee if we can and need to.
-
677 if ((sleDst->getFlags() & lsfPasswordSpent))
-
678 sleDst->clearFlag(lsfPasswordSpent);
+
619 if (mPriorBalance < dstAmount.xrp() + mmm)
+
620 {
+
621 // Vote no. However the transaction might succeed, if applied in
+
622 // a different order.
+
623 JLOG(j_.trace()) << "Delay transaction: Insufficient funds: "
+
624 << to_string(mPriorBalance) << " / "
+
625 << to_string(dstAmount.xrp() + mmm) << " ("
+
626 << to_string(reserve) << ")";
+
627
+
628 return tecUNFUNDED_PAYMENT;
+
629 }
+
630
+
631 // Pseudo-accounts cannot receive payments, other than these native to
+
632 // their underlying ledger object - implemented in their respective
+
633 // transaction types. Note, this is not amendment-gated because all writes
+
634 // to pseudo-account discriminator fields **are** amendment gated, hence the
+
635 // behaviour of this check will always match the active amendments.
+
636 if (isPseudoAccount(sleDst))
+
637 return tecNO_PERMISSION;
+
638
+
639 // The source account does have enough money. Make sure the
+
640 // source account has authority to deposit to the destination.
+
641 if (depositAuth)
+
642 {
+
643 // If depositPreauth is enabled, then an account that requires
+
644 // authorization has three ways to get an XRP Payment in:
+
645 // 1. If Account == Destination, or
+
646 // 2. If Account is deposit preauthorized by destination, or
+
647 // 3. If the destination's XRP balance is
+
648 // a. less than or equal to the base reserve and
+
649 // b. the deposit amount is less than or equal to the base reserve,
+
650 // then we allow the deposit.
+
651 //
+
652 // Rule 3 is designed to keep an account from getting wedged
+
653 // in an unusable state if it sets the lsfDepositAuth flag and
+
654 // then consumes all of its XRP. Without the rule if an
+
655 // account with lsfDepositAuth set spent all of its XRP, it
+
656 // would be unable to acquire more XRP required to pay fees.
+
657 //
+
658 // We choose the base reserve as our bound because it is
+
659 // a small number that seldom changes but is always sufficient
+
660 // to get the account un-wedged.
+
661
+
662 // Get the base reserve.
+
663 XRPAmount const dstReserve{view().fees().accountReserve(0)};
+
664
+
665 if (dstAmount > dstReserve ||
+
666 sleDst->getFieldAmount(sfBalance) > dstReserve)
+
667 {
+
668 if (auto err = verifyDepositPreauth(
+
669 ctx_.tx,
+
670 ctx_.view(),
+
671 account_,
+
672 dstAccountID,
+
673 sleDst,
+
674 ctx_.journal);
+
675 !isTesSuccess(err))
+
676 return err;
+
677 }
+
678 }
679
-
680 return tesSUCCESS;
-
681}
-
682
-
683} // namespace ripple
+
680 // Do the arithmetic for the transfer and make the ledger change.
+
681 sleSrc->setFieldAmount(sfBalance, mSourceBalance - dstAmount);
+
682 sleDst->setFieldAmount(
+
683 sfBalance, sleDst->getFieldAmount(sfBalance) + dstAmount);
+
684
+
685 // Re-arm the password change fee if we can and need to.
+
686 if ((sleDst->getFlags() & lsfPasswordSpent))
+
687 sleDst->clearFlag(lsfPasswordSpent);
+
688
+
689 return tesSUCCESS;
+
690}
+
691
+
692} // namespace ripple
T any_of(T... args)
Stream debug() const
Definition: Journal.h:328
Stream trace() const
Severity stream access functions.
Definition: Journal.h:322
diff --git a/classripple_1_1test_1_1CheckDeliveredAmount.html b/classripple_1_1test_1_1CheckDeliveredAmount.html index 092f649acb..ea3322433c 100644 --- a/classripple_1_1test_1_1CheckDeliveredAmount.html +++ b/classripple_1_1test_1_1CheckDeliveredAmount.html @@ -115,7 +115,7 @@ Private Attributes

Detailed Description

-

Definition at line 30 of file DeliveredAmount_test.cpp.

+

Definition at line 31 of file DeliveredAmount_test.cpp.

Constructor & Destructor Documentation

◆ CheckDeliveredAmount()

@@ -141,7 +141,7 @@ Private Attributes
-

Definition at line 67 of file DeliveredAmount_test.cpp.

+

Definition at line 68 of file DeliveredAmount_test.cpp.

@@ -180,7 +180,7 @@ Private Attributes
-

Definition at line 47 of file DeliveredAmount_test.cpp.

+

Definition at line 48 of file DeliveredAmount_test.cpp.

@@ -199,7 +199,7 @@ Private Attributes
-

Definition at line 73 of file DeliveredAmount_test.cpp.

+

Definition at line 74 of file DeliveredAmount_test.cpp.

@@ -218,7 +218,7 @@ Private Attributes
-

Definition at line 79 of file DeliveredAmount_test.cpp.

+

Definition at line 80 of file DeliveredAmount_test.cpp.

@@ -237,7 +237,7 @@ Private Attributes
-

Definition at line 84 of file DeliveredAmount_test.cpp.

+

Definition at line 85 of file DeliveredAmount_test.cpp.

@@ -256,7 +256,7 @@ Private Attributes
-

Definition at line 92 of file DeliveredAmount_test.cpp.

+

Definition at line 93 of file DeliveredAmount_test.cpp.

@@ -286,7 +286,7 @@ Private Attributes
-

Definition at line 103 of file DeliveredAmount_test.cpp.

+

Definition at line 104 of file DeliveredAmount_test.cpp.

@@ -311,7 +311,7 @@ Private Attributes
-

Definition at line 33 of file DeliveredAmount_test.cpp.

+

Definition at line 34 of file DeliveredAmount_test.cpp.

@@ -335,7 +335,7 @@ Private Attributes
-

Definition at line 35 of file DeliveredAmount_test.cpp.

+

Definition at line 36 of file DeliveredAmount_test.cpp.

@@ -359,7 +359,7 @@ Private Attributes
-

Definition at line 38 of file DeliveredAmount_test.cpp.

+

Definition at line 39 of file DeliveredAmount_test.cpp.

@@ -383,7 +383,7 @@ Private Attributes
-

Definition at line 40 of file DeliveredAmount_test.cpp.

+

Definition at line 41 of file DeliveredAmount_test.cpp.

diff --git a/classripple_1_1test_1_1DeliveredAmount__test-members.html b/classripple_1_1test_1_1DeliveredAmount__test-members.html index dc42a4dfd1..b712f19dff 100644 --- a/classripple_1_1test_1_1DeliveredAmount__test-members.html +++ b/classripple_1_1test_1_1DeliveredAmount__test-members.html @@ -104,13 +104,14 @@ $(function() { suite(suite const &)=deletebeast::unit_test::suite testAccountDeliveredAmountSubscribe()ripple::test::DeliveredAmount_testprivate testcasebeast::unit_test::suite - testTxDeliveredAmountRPC()ripple::test::DeliveredAmount_testprivate - this_suite()beast::unit_test::suitestatic - unexcept(F &&f, String const &reason)beast::unit_test::suite - unexcept(F &&f)beast::unit_test::suite - unexpected(Condition shouldBeFalse, String const &reason)beast::unit_test::suite - unexpected(Condition shouldBeFalse)beast::unit_test::suite - ~suite()=defaultbeast::unit_test::suitevirtual + testMPTDeliveredAmountRPC(FeatureBitset features)ripple::test::DeliveredAmount_testprivate + testTxDeliveredAmountRPC()ripple::test::DeliveredAmount_testprivate + this_suite()beast::unit_test::suitestatic + unexcept(F &&f, String const &reason)beast::unit_test::suite + unexcept(F &&f)beast::unit_test::suite + unexpected(Condition shouldBeFalse, String const &reason)beast::unit_test::suite + unexpected(Condition shouldBeFalse)beast::unit_test::suite + ~suite()=defaultbeast::unit_test::suitevirtual