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 (transactionMeta.hasDeliveredAmount())
54 {
55 return transactionMeta.getDeliveredAmount();
56 }
57
58 if (serializedTx->isFieldPresent(sfAmount))
59 {
60 using namespace std::chrono_literals;
61
62 // Ledger 4594095 is the first ledger in which the DeliveredAmount field
63 // was present when a partial payment was made and its absence indicates
64 // that the amount delivered is listed in the Amount field.
65 //
66 // If the ledger closed long after the DeliveredAmount code was deployed
67 // then its absence indicates that the amount delivered is listed in the
68 // Amount field. DeliveredAmount went live January 24, 2014.
69 // 446000000 is in Feb 2014, well after DeliveredAmount went live
70 if (getLedgerIndex() >= 4594095 ||
71 getCloseTime() > NetClock::time_point{446000000s})
72 {
73 return serializedTx->getFieldAmount(sfAmount);
74 }
75 }
76
77 return {};
78}
79
80// Returns true if transaction meta could contain a delivered amount field,
81// based on transaction type and transaction result
82bool
84 std::shared_ptr<STTx const> const& serializedTx,
85 TxMeta const& transactionMeta)
86{
87 if (!serializedTx)
88 return false;
89
90 TxType const tt{serializedTx->getTxnType()};
91 // Transaction type should be ttPAYMENT, ttACCOUNT_DELETE or ttCHECK_CASH
92 // and if the transaction failed nothing could have been delivered.
93 if ((tt == ttPAYMENT || tt == ttCHECK_CASH || tt == ttACCOUNT_DELETE) &&
94 transactionMeta.getResultTER() == tesSUCCESS)
95 {
96 return true;
97 }
98
99 return false;
100}
101
102void
104 Json::Value& meta,
105 ReadView const& ledger,
106 std::shared_ptr<STTx const> const& serializedTx,
107 TxMeta const& transactionMeta)
108{
109 auto const info = ledger.info();
110
111 if (canHaveDeliveredAmount(serializedTx, transactionMeta))
112 {
113 auto const getLedgerIndex = [&info] { return info.seq; };
114 auto const getCloseTime = [&info] { return info.closeTime; };
115
116 auto amt = getDeliveredAmount(
117 getLedgerIndex, getCloseTime, serializedTx, transactionMeta);
118 if (amt)
119 {
120 meta[jss::delivered_amount] =
121 amt->getJson(JsonOptions::include_date);
122 }
123 else
124 {
125 // report "unavailable" which cannot be parsed into a sensible
126 // amount.
127 meta[jss::delivered_amount] = Json::Value("unavailable");
128 }
129 }
130}
131
132template <class GetLedgerIndex>
135 RPC::Context const& context,
136 std::shared_ptr<STTx const> const& serializedTx,
137 TxMeta const& transactionMeta,
138 GetLedgerIndex const& getLedgerIndex)
139{
140 if (canHaveDeliveredAmount(serializedTx, transactionMeta))
141 {
142 auto const getCloseTime =
143 [&context,
144 &getLedgerIndex]() -> std::optional<NetClock::time_point> {
145 return context.ledgerMaster.getCloseTimeBySeq(getLedgerIndex());
146 };
147 return getDeliveredAmount(
148 getLedgerIndex, getCloseTime, serializedTx, transactionMeta);
149 }
150
151 return {};
152}
153
156 RPC::Context const& context,
157 std::shared_ptr<STTx const> const& serializedTx,
158 TxMeta const& transactionMeta,
159 LedgerIndex const& ledgerIndex)
160{
161 return getDeliveredAmount(
162 context, serializedTx, transactionMeta, [&ledgerIndex]() {
163 return ledgerIndex;
164 });
165}
166
167void
169 Json::Value& meta,
170 RPC::JsonContext const& context,
171 std::shared_ptr<Transaction> const& transaction,
172 TxMeta const& transactionMeta)
173{
175 meta, context, transaction->getSTransaction(), transactionMeta);
176}
177
178void
180 Json::Value& meta,
181 RPC::JsonContext const& context,
182 std::shared_ptr<STTx const> const& transaction,
183 TxMeta const& transactionMeta)
184{
185 if (canHaveDeliveredAmount(transaction, transactionMeta))
186 {
187 auto amt = getDeliveredAmount(
188 context, transaction, transactionMeta, [&transactionMeta]() {
189 return transactionMeta.getLgrSeq();
190 });
191
192 if (amt)
193 {
194 meta[jss::delivered_amount] =
195 amt->getJson(JsonOptions::include_date);
196 }
197 else
198 {
199 // report "unavailable" which cannot be parsed into a sensible
200 // amount.
201 meta[jss::delivered_amount] = Json::Value("unavailable");
202 }
203 }
204}
205
206} // namespace RPC
207} // 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.
bool hasDeliveredAmount() const
Definition TxMeta.h:131
STAmount getDeliveredAmount() const
Definition TxMeta.h:122
std::uint32_t getLgrSeq() const
Definition TxMeta.h:63
TER getResultTER() const
Definition TxMeta.h:73
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:244
The context of information needed to call an RPC.
Definition Context.h:39
LedgerMaster & ledgerMaster
Definition Context.h:44