rippled
Loading...
Searching...
No Matches
DeliveredAmount.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2019 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 <xrpld/app/ledger/LedgerMaster.h>
21#include <xrpld/app/ledger/OpenLedger.h>
22#include <xrpld/app/misc/Transaction.h>
23#include <xrpld/rpc/Context.h>
24#include <xrpld/rpc/DeliveredAmount.h>
25
26#include <xrpl/protocol/Feature.h>
27#include <xrpl/protocol/RPCErr.h>
28
29namespace ripple {
30namespace RPC {
31
32/*
33 GetLedgerIndex and GetCloseTime are lambdas that allow the close time and
34 ledger index to be lazily calculated. Without these lambdas, these values
35 would be calculated even when not needed, and in some circumstances they are
36 not trivial to compute.
37
38 GetLedgerIndex is a callable that returns a LedgerIndex
39 GetCloseTime is a callable that returns a
40 std::optional<NetClock::time_point>
41 */
42template <class GetLedgerIndex, class GetCloseTime>
45 GetLedgerIndex const& getLedgerIndex,
46 GetCloseTime const& getCloseTime,
47 std::shared_ptr<STTx const> const& serializedTx,
48 TxMeta const& transactionMeta)
49{
50 if (!serializedTx)
51 return {};
52
53 if (auto const& deliveredAmount = transactionMeta.getDeliveredAmount();
54 deliveredAmount.has_value())
55 {
56 return *deliveredAmount;
57 }
58
59 if (serializedTx->isFieldPresent(sfAmount))
60 {
61 using namespace std::chrono_literals;
62
63 // Ledger 4594095 is the first ledger in which the DeliveredAmount field
64 // was present when a partial payment was made and its absence indicates
65 // that the amount delivered is listed in the Amount field.
66 //
67 // If the ledger closed long after the DeliveredAmount code was deployed
68 // then its absence indicates that the amount delivered is listed in the
69 // Amount field. DeliveredAmount went live January 24, 2014.
70 // 446000000 is in Feb 2014, well after DeliveredAmount went live
71 if (getLedgerIndex() >= 4594095 ||
72 getCloseTime() > NetClock::time_point{446000000s})
73 {
74 return serializedTx->getFieldAmount(sfAmount);
75 }
76 }
77
78 return {};
79}
80
81// Returns true if transaction meta could contain a delivered amount field,
82// based on transaction type and transaction result
83bool
85 std::shared_ptr<STTx const> const& serializedTx,
86 TxMeta const& transactionMeta)
87{
88 if (!serializedTx)
89 return false;
90
91 TxType const tt{serializedTx->getTxnType()};
92 // Transaction type should be ttPAYMENT, ttACCOUNT_DELETE or ttCHECK_CASH
93 // and if the transaction failed nothing could have been delivered.
94 if ((tt == ttPAYMENT || tt == ttCHECK_CASH || tt == ttACCOUNT_DELETE) &&
95 transactionMeta.getResultTER() == tesSUCCESS)
96 {
97 return true;
98 }
99
100 return false;
101}
102
103void
105 Json::Value& meta,
106 ReadView const& ledger,
107 std::shared_ptr<STTx const> const& serializedTx,
108 TxMeta const& transactionMeta)
109{
110 auto const info = ledger.info();
111
112 if (canHaveDeliveredAmount(serializedTx, transactionMeta))
113 {
114 auto const getLedgerIndex = [&info] { return info.seq; };
115 auto const getCloseTime = [&info] { return info.closeTime; };
116
117 auto amt = getDeliveredAmount(
118 getLedgerIndex, getCloseTime, serializedTx, transactionMeta);
119 if (amt)
120 {
121 meta[jss::delivered_amount] =
122 amt->getJson(JsonOptions::include_date);
123 }
124 else
125 {
126 // report "unavailable" which cannot be parsed into a sensible
127 // amount.
128 meta[jss::delivered_amount] = Json::Value("unavailable");
129 }
130 }
131}
132
133template <class GetLedgerIndex>
136 RPC::Context const& context,
137 std::shared_ptr<STTx const> const& serializedTx,
138 TxMeta const& transactionMeta,
139 GetLedgerIndex const& getLedgerIndex)
140{
141 if (canHaveDeliveredAmount(serializedTx, transactionMeta))
142 {
143 auto const getCloseTime =
144 [&context,
145 &getLedgerIndex]() -> std::optional<NetClock::time_point> {
146 return context.ledgerMaster.getCloseTimeBySeq(getLedgerIndex());
147 };
148 return getDeliveredAmount(
149 getLedgerIndex, getCloseTime, serializedTx, transactionMeta);
150 }
151
152 return {};
153}
154
157 RPC::Context const& context,
158 std::shared_ptr<STTx const> const& serializedTx,
159 TxMeta const& transactionMeta,
160 LedgerIndex const& ledgerIndex)
161{
162 return getDeliveredAmount(
163 context, serializedTx, transactionMeta, [&ledgerIndex]() {
164 return ledgerIndex;
165 });
166}
167
168void
170 Json::Value& meta,
171 RPC::JsonContext const& context,
172 std::shared_ptr<Transaction> const& transaction,
173 TxMeta const& transactionMeta)
174{
176 meta, context, transaction->getSTransaction(), transactionMeta);
177}
178
179void
181 Json::Value& meta,
182 RPC::JsonContext const& context,
183 std::shared_ptr<STTx const> const& transaction,
184 TxMeta const& transactionMeta)
185{
186 if (canHaveDeliveredAmount(transaction, transactionMeta))
187 {
188 auto amt = getDeliveredAmount(
189 context, transaction, transactionMeta, [&transactionMeta]() {
190 return transactionMeta.getLgrSeq();
191 });
192
193 if (amt)
194 {
195 meta[jss::delivered_amount] =
196 amt->getJson(JsonOptions::include_date);
197 }
198 else
199 {
200 // report "unavailable" which cannot be parsed into a sensible
201 // amount.
202 meta[jss::delivered_amount] = Json::Value("unavailable");
203 }
204 }
205}
206
207} // namespace RPC
208} // namespace ripple
Represents a JSON value.
Definition json_value.h:149
std::optional< NetClock::time_point > getCloseTimeBySeq(LedgerIndex ledgerIndex)
A view into a ledger.
Definition ReadView.h:51
virtual LedgerInfo const & info() const =0
Returns information about the ledger.
std::uint32_t getLgrSeq() const
Definition TxMeta.h:47
TER getResultTER() const
Definition TxMeta.h:57
std::optional< STAmount > const & getDeliveredAmount() const
Definition TxMeta.h:110
std::optional< STAmount > getDeliveredAmount(RPC::Context const &context, std::shared_ptr< STTx const > const &serializedTx, TxMeta const &transactionMeta, LedgerIndex const &ledgerIndex)
void insertDeliveredAmount(Json::Value &meta, ReadView const &, std::shared_ptr< STTx const > const &serializedTx, TxMeta const &)
Add a delivered_amount field to the meta input/output parameter.
bool canHaveDeliveredAmount(std::shared_ptr< STTx const > const &serializedTx, TxMeta const &transactionMeta)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
TxType
Transaction type identifiers.
Definition TxFormats.h:57
@ tesSUCCESS
Definition TER.h:245
The context of information needed to call an RPC.
Definition Context.h:39
LedgerMaster & ledgerMaster
Definition Context.h:44