rippled
Loading...
Searching...
No Matches
Discrepancy_test.cpp
1#include <test/jtx.h>
2#include <test/jtx/Env.h>
3#include <test/jtx/PathSet.h>
4
5#include <xrpl/beast/core/LexicalCast.h>
6#include <xrpl/beast/unit_test.h>
7#include <xrpl/protocol/Feature.h>
8#include <xrpl/protocol/SField.h>
9#include <xrpl/protocol/jss.h>
10
11namespace xrpl {
12
14{
15 // This is a legacy test ported from js/coffee. The ledger
16 // state was originally setup via a saved ledger file and the relevant
17 // entries have since been converted to the equivalent jtx/Env setup.
18 // A payment with path and sendmax is made and the transaction is queried
19 // to verify that the net of balance changes match the fee charged.
20 void
22 {
23 testcase("Discrepancy test : XRP Discrepancy");
24 using namespace test::jtx;
25 Env env{*this, features};
26
27 Account const A1{"A1"};
28 Account const A2{"A2"};
29 Account const A3{"A3"};
30 Account const A4{"A4"};
31 Account const A5{"A5"};
32 Account const A6{"A6"};
33 Account const A7{"A7"};
34
35 env.fund(XRP(2000), A1);
36 env.fund(XRP(1000), A2, A6, A7);
37 env.fund(XRP(5000), A3);
38 env.fund(XRP(1000000), A4);
39 env.fund(XRP(600000), A5);
40 env.close();
41
42 env(trust(A1, A3["CNY"](200000)));
43 env(pay(A3, A1, A3["CNY"](31)));
44 env.close();
45
46 env(trust(A1, A2["JPY"](1000000)));
47 env(pay(A2, A1, A2["JPY"](729117)));
48 env.close();
49
50 env(trust(A4, A2["JPY"](10000000)));
51 env(pay(A2, A4, A2["JPY"](470056)));
52 env.close();
53
54 env(trust(A5, A3["CNY"](50000)));
55 env(pay(A3, A5, A3["CNY"](8683)));
56 env.close();
57
58 env(trust(A6, A3["CNY"](3000)));
59 env(pay(A3, A6, A3["CNY"](293)));
60 env.close();
61
62 env(trust(A7, A6["CNY"](50000)));
63 env(pay(A6, A7, A6["CNY"](261)));
64 env.close();
65
66 env(offer(A4, XRP(49147), A2["JPY"](34501)));
67 env(offer(A5, A3["CNY"](3150), XRP(80086)));
68 env(offer(A7, XRP(1233), A6["CNY"](25)));
69 env.close();
70
71 test::PathSet const payPaths{
72 test::Path{A2["JPY"], A2},
73 test::Path{XRP, A2["JPY"], A2},
74 test::Path{A6, XRP, A2["JPY"], A2}};
75
76 env(pay(A1, A1, A2["JPY"](1000)),
77 json(payPaths.json()),
78 txflags(tfPartialPayment),
79 sendmax(A3["CNY"](56)));
80 env.close();
81
82 Json::Value jrq2;
83 jrq2[jss::binary] = false;
84 jrq2[jss::transaction] = env.tx()->getJson(JsonOptions::none)[jss::hash];
85 jrq2[jss::id] = 3;
86 auto jrr = env.rpc("json", "tx", to_string(jrq2))[jss::result];
87 uint64_t const fee{jrr[jss::Fee].asUInt()};
88 auto meta = jrr[jss::meta];
89 uint64_t sumPrev{0};
90 uint64_t sumFinal{0};
91 BEAST_EXPECT(meta[sfAffectedNodes.fieldName].size() == 9);
92 for (auto const& an : meta[sfAffectedNodes.fieldName])
93 {
94 Json::Value node;
95 if (an.isMember(sfCreatedNode.fieldName))
96 {
97 node = an[sfCreatedNode.fieldName];
98 }
99 else if (an.isMember(sfModifiedNode.fieldName))
100 {
101 node = an[sfModifiedNode.fieldName];
102 }
103 else if (an.isMember(sfDeletedNode.fieldName))
104 {
105 node = an[sfDeletedNode.fieldName];
106 }
107
108 if (node && node[sfLedgerEntryType.fieldName] == jss::AccountRoot)
109 {
110 Json::Value prevFields = node.isMember(sfPreviousFields.fieldName)
111 ? node[sfPreviousFields.fieldName]
112 : node[sfNewFields.fieldName];
113 Json::Value finalFields = node.isMember(sfFinalFields.fieldName)
114 ? node[sfFinalFields.fieldName]
115 : node[sfNewFields.fieldName];
116 if (prevFields)
117 {
118 sumPrev += beast::lexicalCastThrow<std::uint64_t>(
119 prevFields[sfBalance.fieldName].asString());
120 }
121 if (finalFields)
122 {
123 sumFinal += beast::lexicalCastThrow<std::uint64_t>(
124 finalFields[sfBalance.fieldName].asString());
125 }
126 }
127 }
128 // the difference in balances (final and prev) should be the
129 // fee charged
130 BEAST_EXPECT(sumPrev - sumFinal == fee);
131 }
132
133public:
134 void
135 run() override
136 {
137 using namespace test::jtx;
138 auto const sa = testable_amendments();
139 testXRPDiscrepancy(sa - featurePermissionedDEX);
141 }
142};
143
144BEAST_DEFINE_TESTSUITE(Discrepancy, app, xrpl);
145
146} // namespace xrpl
Represents a JSON value.
Definition json_value.h:130
UInt asUInt() const
std::string asString() const
Returns the unquoted string value.
bool isMember(char const *key) const
Return true if the object has a member named key.
A testsuite class.
Definition suite.h:51
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:150
void testXRPDiscrepancy(FeatureBitset features)
void run() override
Runs the suite.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:602