rippled
Loading...
Searching...
No Matches
Discrepancy_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012-2016 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <test/jtx.h>
21#include <test/jtx/Env.h>
22#include <test/jtx/PathSet.h>
23#include <xrpl/beast/core/LexicalCast.h>
24#include <xrpl/beast/unit_test.h>
25#include <xrpl/protocol/Feature.h>
26#include <xrpl/protocol/SField.h>
27#include <xrpl/protocol/jss.h>
28
29namespace ripple {
30
32{
33 // This is a legacy test ported from js/coffee. The ledger
34 // state was originally setup via a saved ledger file and the relevant
35 // entries have since been converted to the equivalent jtx/Env setup.
36 // A payment with path and sendmax is made and the transaction is queried
37 // to verify that the net of balance changes match the fee charged.
38 void
40 {
41 testcase("Discrepancy test : XRP Discrepancy");
42 using namespace test::jtx;
43 Env env{*this, features};
44
45 Account A1{"A1"};
46 Account A2{"A2"};
47 Account A3{"A3"};
48 Account A4{"A4"};
49 Account A5{"A5"};
50 Account A6{"A6"};
51 Account A7{"A7"};
52
53 env.fund(XRP(2000), A1);
54 env.fund(XRP(1000), A2, A6, A7);
55 env.fund(XRP(5000), A3);
56 env.fund(XRP(1000000), A4);
57 env.fund(XRP(600000), A5);
58 env.close();
59
60 env(trust(A1, A3["CNY"](200000)));
61 env(pay(A3, A1, A3["CNY"](31)));
62 env.close();
63
64 env(trust(A1, A2["JPY"](1000000)));
65 env(pay(A2, A1, A2["JPY"](729117)));
66 env.close();
67
68 env(trust(A4, A2["JPY"](10000000)));
69 env(pay(A2, A4, A2["JPY"](470056)));
70 env.close();
71
72 env(trust(A5, A3["CNY"](50000)));
73 env(pay(A3, A5, A3["CNY"](8683)));
74 env.close();
75
76 env(trust(A6, A3["CNY"](3000)));
77 env(pay(A3, A6, A3["CNY"](293)));
78 env.close();
79
80 env(trust(A7, A6["CNY"](50000)));
81 env(pay(A6, A7, A6["CNY"](261)));
82 env.close();
83
84 env(offer(A4, XRP(49147), A2["JPY"](34501)));
85 env(offer(A5, A3["CNY"](3150), XRP(80086)));
86 env(offer(A7, XRP(1233), A6["CNY"](25)));
87 env.close();
88
89 test::PathSet payPaths{
90 test::Path{A2["JPY"], A2},
91 test::Path{XRP, A2["JPY"], A2},
92 test::Path{A6, XRP, A2["JPY"], A2}};
93
94 env(pay(A1, A1, A2["JPY"](1000)),
95 json(payPaths.json()),
96 txflags(tfPartialPayment),
97 sendmax(A3["CNY"](56)));
98 env.close();
99
100 Json::Value jrq2;
101 jrq2[jss::binary] = false;
102 jrq2[jss::transaction] =
103 env.tx()->getJson(JsonOptions::none)[jss::hash];
104 jrq2[jss::id] = 3;
105 auto jrr = env.rpc("json", "tx", to_string(jrq2))[jss::result];
106 uint64_t fee{jrr[jss::Fee].asUInt()};
107 auto meta = jrr[jss::meta];
108 uint64_t sumPrev{0};
109 uint64_t sumFinal{0};
110 BEAST_EXPECT(meta[sfAffectedNodes.fieldName].size() == 9);
111 for (auto const& an : meta[sfAffectedNodes.fieldName])
112 {
113 Json::Value node;
114 if (an.isMember(sfCreatedNode.fieldName))
115 node = an[sfCreatedNode.fieldName];
116 else if (an.isMember(sfModifiedNode.fieldName))
117 node = an[sfModifiedNode.fieldName];
118 else if (an.isMember(sfDeletedNode.fieldName))
119 node = an[sfDeletedNode.fieldName];
120
121 if (node && node[sfLedgerEntryType.fieldName] == jss::AccountRoot)
122 {
123 Json::Value prevFields =
124 node.isMember(sfPreviousFields.fieldName)
125 ? node[sfPreviousFields.fieldName]
126 : node[sfNewFields.fieldName];
127 Json::Value finalFields = node.isMember(sfFinalFields.fieldName)
128 ? node[sfFinalFields.fieldName]
129 : node[sfNewFields.fieldName];
130 if (prevFields)
131 sumPrev += beast::lexicalCastThrow<std::uint64_t>(
132 prevFields[sfBalance.fieldName].asString());
133 if (finalFields)
134 sumFinal += beast::lexicalCastThrow<std::uint64_t>(
135 finalFields[sfBalance.fieldName].asString());
136 }
137 }
138 // the difference in balances (final and prev) should be the
139 // fee charged
140 BEAST_EXPECT(sumPrev - sumFinal == fee);
141 }
142
143public:
144 void
145 run() override
146 {
147 using namespace test::jtx;
148 auto const sa = supported_amendments();
149 testXRPDiscrepancy(sa - featureFlowCross);
151 }
152};
153
154BEAST_DEFINE_TESTSUITE(Discrepancy, app, ripple);
155
156} // namespace ripple
Represents a JSON value.
Definition: json_value.h:148
UInt asUInt() const
Definition: json_value.cpp:551
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:475
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:949
A testsuite class.
Definition: suite.h:55
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:155
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:26
constexpr std::uint32_t tfPartialPayment
Definition: TxFlags.h:105
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630