rippled
Oracle.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 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/protocol/digest.h>
21 #include <ripple/protocol/jss.h>
22 #include <test/jtx/Oracle.h>
23 
24 #include <boost/lexical_cast/try_lexical_convert.hpp>
25 
26 #include <vector>
27 
28 namespace ripple {
29 namespace test {
30 namespace jtx {
31 namespace oracle {
32 
33 Oracle::Oracle(Env& env, CreateArg const& arg, bool submit)
34  : env_(env), owner_{}, documentID_{}
35 {
36  // LastUpdateTime is checked to be in range
37  // {close-maxLastUpdateTimeDelta, close+maxLastUpdateTimeDelta}.
38  // To make the validation work and to make the clock consistent
39  // for tests running at different time, simulate Unix time starting
40  // on testStartTime since Ripple epoch.
41  auto const now = env_.timeKeeper().now();
42  if (now.time_since_epoch().count() == 0 || arg.close)
43  env_.close(now + testStartTime - epoch_offset);
44  if (arg.owner)
45  owner_ = *arg.owner;
46  if (arg.documentID)
47  documentID_ = *arg.documentID;
48  if (submit)
49  set(arg);
50 }
51 
52 void
54 {
55  Json::Value jv;
56  jv[jss::TransactionType] = jss::OracleDelete;
57  jv[jss::Account] = to_string(arg.owner.value_or(owner_));
58  jv[jss::OracleDocumentID] = arg.documentID.value_or(documentID_);
59  if (Oracle::fee != 0)
60  jv[jss::Fee] = std::to_string(Oracle::fee);
61  else if (arg.fee != 0)
62  jv[jss::Fee] = std::to_string(arg.fee);
63  else
64  jv[jss::Fee] = std::to_string(env_.current()->fees().increment.drops());
65  submit(jv, arg.msig, arg.seq, arg.err);
66 }
67 
68 void
70  Json::Value const& jv,
73  std::optional<ter> const& err)
74 {
75  if (msig)
76  {
77  if (seq && err)
78  env_(jv, *msig, *seq, *err);
79  else if (seq)
80  env_(jv, *msig, *seq);
81  else if (err)
82  env_(jv, *msig, *err);
83  else
84  env_(jv, *msig);
85  }
86  else if (seq && err)
87  env_(jv, *seq, *err);
88  else if (seq)
89  env_(jv, *seq);
90  else if (err)
91  env_(jv, *err);
92  else
93  env_(jv);
94  env_.close();
95 }
96 
97 bool
98 Oracle::exists(Env& env, AccountID const& account, std::uint32_t documentID)
99 {
100  assert(account.isNonZero());
101  return env.le(keylet::oracle(account, documentID)) != nullptr;
102 }
103 
104 bool
105 Oracle::expectPrice(DataSeries const& series) const
106 {
107  if (auto const sle = env_.le(keylet::oracle(owner_, documentID_)))
108  {
109  auto const& leSeries = sle->getFieldArray(sfPriceDataSeries);
110  if (leSeries.size() == 0 || leSeries.size() != series.size())
111  return false;
112  for (auto const& data : series)
113  {
114  if (std::find_if(
115  leSeries.begin(),
116  leSeries.end(),
117  [&](STObject const& o) -> bool {
118  auto const& baseAsset = o.getFieldCurrency(sfBaseAsset);
119  auto const& quoteAsset =
120  o.getFieldCurrency(sfQuoteAsset);
121  auto const& price = o.getFieldU64(sfAssetPrice);
122  auto const& scale = o.getFieldU8(sfScale);
123  return baseAsset.getText() == std::get<0>(data) &&
124  quoteAsset.getText() == std::get<1>(data) &&
125  price == std::get<2>(data) &&
126  scale == std::get<3>(data);
127  }) == leSeries.end())
128  return false;
129  }
130  return true;
131  }
132  return false;
133 }
134 
135 bool
137 {
138  auto const sle = env_.le(keylet::oracle(owner_, documentID_));
139  return sle && (*sle)[sfLastUpdateTime] == lastUpdateTime;
140 }
141 
144  Env& env,
145  std::optional<std::string> const& baseAsset,
146  std::optional<std::string> const& quoteAsset,
148  oracles,
149  std::optional<std::uint8_t> const& trim,
150  std::optional<std::uint8_t> const& timeThreshold)
151 {
152  Json::Value jv;
153  Json::Value jvOracles(Json::arrayValue);
154  if (oracles)
155  {
156  for (auto const& id : *oracles)
157  {
158  Json::Value oracle;
159  oracle[jss::account] = to_string(id.first.id());
160  oracle[jss::oracle_document_id] = id.second;
161  jvOracles.append(oracle);
162  }
163  jv[jss::oracles] = jvOracles;
164  }
165  if (trim)
166  jv[jss::trim] = *trim;
167  if (baseAsset)
168  jv[jss::base_asset] = *baseAsset;
169  if (quoteAsset)
170  jv[jss::quote_asset] = *quoteAsset;
171  if (timeThreshold)
172  jv[jss::time_threshold] = *timeThreshold;
173 
174  auto jr = env.rpc("json", "get_aggregate_price", to_string(jv));
175 
176  if (jr.isObject() && jr.isMember(jss::result) &&
177  jr[jss::result].isMember(jss::status))
178  return jr[jss::result];
179  return Json::nullValue;
180 }
181 
182 void
184 {
185  using namespace std::chrono;
186  Json::Value jv;
187  if (arg.owner)
188  owner_ = *arg.owner;
189  if (arg.documentID)
190  documentID_ = *arg.documentID;
191  jv[jss::TransactionType] = jss::OracleSet;
192  jv[jss::Account] = to_string(owner_);
193  jv[jss::OracleDocumentID] = documentID_;
194  if (arg.assetClass)
195  jv[jss::AssetClass] = strHex(*arg.assetClass);
196  if (arg.provider)
197  jv[jss::Provider] = strHex(*arg.provider);
198  if (arg.uri)
199  jv[jss::URI] = strHex(*arg.uri);
200  if (arg.flags != 0)
201  jv[jss::Flags] = arg.flags;
202  if (Oracle::fee != 0)
203  jv[jss::Fee] = std::to_string(Oracle::fee);
204  else if (arg.fee != 0)
205  jv[jss::Fee] = std::to_string(arg.fee);
206  else
207  jv[jss::Fee] = std::to_string(env_.current()->fees().increment.drops());
208  // lastUpdateTime if provided is offset from testStartTime
209  if (arg.lastUpdateTime)
210  jv[jss::LastUpdateTime] =
212  else
213  jv[jss::LastUpdateTime] = to_string(
214  duration_cast<seconds>(
215  env_.current()->info().closeTime.time_since_epoch())
216  .count() +
217  epoch_offset.count());
218  Json::Value dataSeries(Json::arrayValue);
219  auto assetToStr = [](std::string const& s) {
220  // assume standard currency
221  if (s.size() == 3)
222  return s;
223  assert(s.size() <= 20);
224  // anything else must be 160-bit hex string
225  std::string h = strHex(s);
226  return strHex(s).append(40 - s.size() * 2, '0');
227  };
228  for (auto const& data : arg.series)
229  {
230  Json::Value priceData;
231  Json::Value price;
232  price[jss::BaseAsset] = assetToStr(std::get<0>(data));
233  price[jss::QuoteAsset] = assetToStr(std::get<1>(data));
234  if (std::get<2>(data))
235  price[jss::AssetPrice] = *std::get<2>(data);
236  if (std::get<3>(data))
237  price[jss::Scale] = *std::get<3>(data);
238  priceData[jss::PriceData] = price;
239  dataSeries.append(priceData);
240  }
241  jv[jss::PriceDataSeries] = dataSeries;
242  submit(jv, arg.msig, arg.seq, arg.err);
243 }
244 
245 void
247 {
248  set(UpdateArg{
249  .owner = arg.owner,
250  .documentID = arg.documentID,
251  .series = arg.series,
252  .assetClass = arg.assetClass,
253  .provider = arg.provider,
254  .uri = arg.uri,
255  .lastUpdateTime = arg.lastUpdateTime,
256  .flags = arg.flags,
257  .msig = arg.msig,
258  .seq = arg.seq,
259  .fee = arg.fee,
260  .err = arg.err});
261 }
262 
265  Env& env,
266  AccountID const& account,
268  std::optional<std::string> const& index)
269 {
270  Json::Value jvParams;
271  jvParams[jss::oracle][jss::account] = to_string(account);
272  if (std::holds_alternative<std::uint32_t>(documentID))
273  jvParams[jss::oracle][jss::oracle_document_id] =
274  std::get<std::uint32_t>(documentID);
275  else
276  jvParams[jss::oracle][jss::oracle_document_id] =
277  std::get<std::string>(documentID);
278  if (index)
279  {
280  std::uint32_t i;
281  if (boost::conversion::try_lexical_convert(*index, i))
282  jvParams[jss::oracle][jss::ledger_index] = i;
283  else
284  jvParams[jss::oracle][jss::ledger_index] = *index;
285  }
286  return env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
287 }
288 
289 } // namespace oracle
290 } // namespace jtx
291 } // namespace test
292 } // namespace ripple
ripple::test::jtx::oracle::CreateArg::series
DataSeries series
Definition: Oracle.h:43
ripple::test::jtx::oracle::CreateArg::err
std::optional< ter > err
Definition: Oracle.h:52
ripple::sfLastUpdateTime
const SF_UINT32 sfLastUpdateTime
std::string
STL class.
ripple::test::jtx::oracle::UpdateArg::provider
std::optional< std::string > provider
Definition: Oracle.h:63
ripple::test::jtx::Env::rpc
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition: Env.h:711
ripple::test::jtx::oracle::UpdateArg::lastUpdateTime
std::optional< std::uint32_t > lastUpdateTime
Definition: Oracle.h:65
ripple::test::jtx::oracle::CreateArg::msig
std::optional< jtx::msig > msig
Definition: Oracle.h:49
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
std::pair
ripple::test::jtx::oracle::UpdateArg::err
std::optional< ter > err
Definition: Oracle.h:70
ripple::keylet::oracle
Keylet oracle(AccountID const &account, std::uint32_t const &documentID) noexcept
Definition: Indexes.cpp:449
vector
std::find_if
T find_if(T... args)
std::vector::size
T size(T... args)
std::optional::value_or
T value_or(T... args)
ripple::test::jtx::oracle::RemoveArg::msig
std::optional< jtx::msig > const & msig
Definition: Oracle.h:77
ripple::test::jtx::oracle::UpdateArg::msig
std::optional< jtx::msig > msig
Definition: Oracle.h:67
ripple::test::jtx::oracle::UpdateArg::seq
std::optional< jtx::seq > seq
Definition: Oracle.h:68
ripple::test::jtx::oracle::Oracle::documentID
std::uint32_t documentID() const
Definition: Oracle.h:134
ripple::test::jtx::msig
Set a multisignature on a JTx.
Definition: multisign.h:63
ripple::test::jtx::oracle::CreateArg::owner
std::optional< AccountID > owner
Definition: Oracle.h:41
ripple::test::jtx::oracle::CreateArg::assetClass
std::optional< std::string > assetClass
Definition: Oracle.h:44
ripple::epoch_offset
constexpr static std::chrono::seconds epoch_offset
Clock for measuring the network time.
Definition: chrono.h:56
ripple::test::jtx::oracle::Oracle::ledgerEntry
static Json::Value ledgerEntry(Env &env, AccountID const &account, std::variant< std::uint32_t, std::string > const &documentID, std::optional< std::string > const &index=std::nullopt)
Definition: Oracle.cpp:264
ripple::test::jtx::oracle::Oracle::remove
void remove(RemoveArg const &arg)
Definition: Oracle.cpp:53
ripple::test::jtx::oracle::CreateArg::flags
std::uint32_t flags
Definition: Oracle.h:48
ripple::base_uint< 160, detail::AccountIDTag >
ripple::test::jtx::oracle::Oracle::Oracle
Oracle(Env &env, CreateArg const &arg, bool submit=true)
Definition: Oracle.cpp:33
ripple::test::jtx::oracle::RemoveArg::seq
std::optional< jtx::seq > seq
Definition: Oracle.h:78
Json::Value::append
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:882
ripple::test::jtx::oracle::RemoveArg::owner
std::optional< AccountID > const & owner
Definition: Oracle.h:75
ripple::test::jtx::oracle::Oracle::env_
Env & env_
Definition: Oracle.h:100
ripple::test::jtx::oracle::UpdateArg::flags
std::uint32_t flags
Definition: Oracle.h:66
ripple::test::jtx::oracle::RemoveArg::fee
std::uint32_t fee
Definition: Oracle.h:79
ripple::test::jtx::oracle::CreateArg::lastUpdateTime
std::optional< std::uint32_t > lastUpdateTime
Definition: Oracle.h:47
ripple::test::jtx::oracle::RemoveArg
Definition: Oracle.h:73
ripple::test::jtx::oracle::testStartTime
constexpr static std::chrono::seconds testStartTime
Definition: Oracle.h:88
ripple::test::jtx::oracle::Oracle::expectPrice
bool expectPrice(DataSeries const &pricess) const
Definition: Oracle.cpp:105
ripple::test::jtx::oracle::UpdateArg
Definition: Oracle.h:57
ripple::test::jtx::oracle::Oracle::fee
static std::uint32_t fee
Definition: Oracle.h:99
ripple::test::jtx::oracle::CreateArg
Definition: Oracle.h:39
std::to_string
T to_string(T... args)
ripple::set
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Definition: BasicConfig.h:313
ripple::test::jtx::oracle::UpdateArg::uri
std::optional< std::string > uri
Definition: Oracle.h:64
ripple::test::jtx::Env::close
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:121
std::uint32_t
std::string::append
T append(T... args)
ripple::test::jtx::oracle::CreateArg::fee
std::uint32_t fee
Definition: Oracle.h:51
ripple::test::jtx::oracle::Oracle::expectLastUpdateTime
bool expectLastUpdateTime(std::uint32_t lastUpdateTime) const
Definition: Oracle.cpp:136
ripple::test::jtx::oracle::Oracle::documentID_
std::uint32_t documentID_
Definition: Oracle.h:102
ripple::test::jtx::seq
Set the sequence number on a JTx.
Definition: seq.h:33
ripple::test::jtx::oracle::UpdateArg::series
DataSeries series
Definition: Oracle.h:61
ripple::STObject
Definition: STObject.h:55
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::jtx::oracle::RemoveArg::err
std::optional< ter > const & err
Definition: Oracle.h:80
ripple::test::jtx::oracle::CreateArg::documentID
std::optional< std::uint32_t > documentID
Definition: Oracle.h:42
ripple::test::jtx::oracle::Oracle::exists
bool exists() const
Definition: Oracle.h:140
ripple::test::jtx::oracle::UpdateArg::owner
std::optional< AccountID > owner
Definition: Oracle.h:59
ripple::test::jtx::oracle::UpdateArg::documentID
std::optional< std::uint32_t > documentID
Definition: Oracle.h:60
ripple::test::jtx::oracle::Oracle::set
void set(CreateArg const &arg)
Definition: Oracle.cpp:246
ripple::test::jtx::oracle::RemoveArg::documentID
std::optional< std::uint32_t > const & documentID
Definition: Oracle.h:76
ripple::test::jtx::Env::le
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Definition: Env.cpp:216
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:36
std::chrono::seconds::count
T count(T... args)
std::optional
ripple::test::jtx::oracle::CreateArg::uri
std::optional< std::string > uri
Definition: Oracle.h:46
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::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
ripple::test::jtx::oracle::CreateArg::seq
std::optional< jtx::seq > seq
Definition: Oracle.h:50
ripple::test::jtx::oracle::Oracle::aggregatePrice
static Json::Value aggregatePrice(Env &env, std::optional< std::string > const &baseAsset, std::optional< std::string > const &quoteAsset, std::optional< std::vector< std::pair< Account, std::uint32_t >>> const &oracles=std::nullopt, std::optional< std::uint8_t > const &trim=std::nullopt, std::optional< std::uint8_t > const &timeTreshold=std::nullopt)
Definition: Oracle.cpp:143
ripple::test::jtx::oracle::Oracle::owner_
AccountID owner_
Definition: Oracle.h:101
ripple::sfPriceDataSeries
const SField sfPriceDataSeries
ripple::test::jtx::oracle::CreateArg::provider
std::optional< std::string > provider
Definition: Oracle.h:45
ripple::test::jtx::Env::current
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:311
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
ripple::test::jtx::oracle::Oracle::submit
void submit(Json::Value const &jv, std::optional< jtx::msig > const &msig, std::optional< jtx::seq > const &seq, std::optional< ter > const &err)
Definition: Oracle.cpp:69
Json::Value
Represents a JSON value.
Definition: json_value.h:145
std::variant
ripple::test::jtx::oracle::UpdateArg::fee
std::uint32_t fee
Definition: Oracle.h:69
ripple::test::jtx::oracle::UpdateArg::assetClass
std::optional< std::string > assetClass
Definition: Oracle.h:62
std::chrono