rippled
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 <ripple/beast/core/LexicalCast.h>
21 #include <ripple/beast/unit_test.h>
22 #include <ripple/protocol/Feature.h>
23 #include <ripple/protocol/SField.h>
24 #include <ripple/protocol/jss.h>
25 #include <test/jtx.h>
26 #include <test/jtx/Env.h>
27 #include <test/jtx/PathSet.h>
28 
29 namespace ripple {
30 
31 class Discrepancy_test : public beast::unit_test::suite
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 =
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 
143 public:
144  void
145  run() override
146  {
147  using namespace test::jtx;
148  auto const sa = supported_amendments();
150  testXRPDiscrepancy(sa);
151  }
152 };
153 
154 BEAST_DEFINE_TESTSUITE(Discrepancy, app, ripple);
155 
156 } // namespace ripple
ripple::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
ripple::SField::fieldName
const std::string fieldName
Definition: SField.h:132
ripple::Discrepancy_test::testXRPDiscrepancy
void testXRPDiscrepancy(FeatureBitset features)
Definition: Discrepancy_test.cpp:39
ripple::test::Path
Definition: PathSet.h:92
ripple::sfFinalFields
const SField sfFinalFields
ripple::sfDeletedNode
const SField sfDeletedNode
ripple::tfPartialPayment
constexpr std::uint32_t tfPartialPayment
Definition: TxFlags.h:102
ripple::sfNewFields
const SField sfNewFields
ripple::JsonOptions::none
@ none
ripple::sfAffectedNodes
const SField sfAffectedNodes
ripple::test::PathSet
Definition: PathSet.h:165
ripple::sfModifiedNode
const SField sfModifiedNode
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
ripple::sfPreviousFields
const SField sfPreviousFields
ripple::Discrepancy_test::run
void run() override
Definition: Discrepancy_test.cpp:145
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::Discrepancy_test
Definition: Discrepancy_test.cpp:31
ripple::sfLedgerEntryType
const SF_UINT16 sfLedgerEntryType
Json::Value::asUInt
UInt asUInt() const
Definition: json_value.cpp:545
ripple::sfCreatedNode
const SField sfCreatedNode
ripple::sfBalance
const SF_AMOUNT sfBalance
ripple::FeatureBitset
Definition: Feature.h:113
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::featureFlowCross
const uint256 featureFlowCross
Json::Value
Represents a JSON value.
Definition: json_value.h:145
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469