rippled
Submit.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2014 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/app/ledger/LedgerMaster.h>
21 #include <ripple/app/misc/HashRouter.h>
22 #include <ripple/app/misc/Transaction.h>
23 #include <ripple/app/tx/apply.h>
24 #include <ripple/net/RPCErr.h>
25 #include <ripple/protocol/ErrorCodes.h>
26 #include <ripple/resource/Fees.h>
27 #include <ripple/rpc/Context.h>
28 #include <ripple/rpc/GRPCHandlers.h>
29 #include <ripple/rpc/impl/GRPCHelpers.h>
30 #include <ripple/rpc/impl/RPCHelpers.h>
31 #include <ripple/rpc/impl/TransactionSign.h>
32 
33 namespace ripple {
34 
37 {
39  context.params.isMember("fail_hard") &&
40  context.params["fail_hard"].asBool());
41 }
42 
43 // {
44 // tx_json: <object>,
45 // secret: <secret>
46 // }
49 {
51 
52  if (!context.params.isMember(jss::tx_blob))
53  {
54  auto const failType = getFailHard(context);
55 
56  if (context.role != Role::ADMIN && !context.app.config().canSign())
57  return RPC::make_error(
58  rpcNOT_SUPPORTED, "Signing is not supported by this server.");
59 
60  auto ret = RPC::transactionSubmit(
61  context.params,
62  failType,
63  context.role,
65  context.app,
66  RPC::getProcessTxnFn(context.netOps));
67 
68  ret[jss::deprecated] =
69  "Signing support in the 'submit' command has been "
70  "deprecated and will be removed in a future version "
71  "of the server. Please migrate to a standalone "
72  "signing tool.";
73 
74  return ret;
75  }
76 
77  Json::Value jvResult;
78 
79  auto ret = strUnHex(context.params[jss::tx_blob].asString());
80 
81  if (!ret || !ret->size())
83 
84  SerialIter sitTrans(makeSlice(*ret));
85 
87 
88  try
89  {
90  stpTrans = std::make_shared<STTx const>(std::ref(sitTrans));
91  }
92  catch (std::exception& e)
93  {
94  jvResult[jss::error] = "invalidTransaction";
95  jvResult[jss::error_exception] = e.what();
96 
97  return jvResult;
98  }
99 
100  {
101  if (!context.app.checkSigs())
103  context.app.getHashRouter(),
104  stpTrans->getTransactionID(),
106  auto [validity, reason] = checkValidity(
107  context.app.getHashRouter(),
108  *stpTrans,
109  context.ledgerMaster.getCurrentLedger()->rules(),
110  context.app.config());
111  if (validity != Validity::Valid)
112  {
113  jvResult[jss::error] = "invalidTransaction";
114  jvResult[jss::error_exception] = "fails local checks: " + reason;
115 
116  return jvResult;
117  }
118  }
119 
120  std::string reason;
121  auto tpTrans = std::make_shared<Transaction>(stpTrans, reason, context.app);
122  if (tpTrans->getStatus() != NEW)
123  {
124  jvResult[jss::error] = "invalidTransaction";
125  jvResult[jss::error_exception] = "fails local checks: " + reason;
126 
127  return jvResult;
128  }
129 
130  try
131  {
132  auto const failType = getFailHard(context);
133 
134  context.netOps.processTransaction(
135  tpTrans, isUnlimited(context.role), true, failType);
136  }
137  catch (std::exception& e)
138  {
139  jvResult[jss::error] = "internalSubmit";
140  jvResult[jss::error_exception] = e.what();
141 
142  return jvResult;
143  }
144 
145  try
146  {
147  jvResult[jss::tx_json] = tpTrans->getJson(JsonOptions::none);
148  jvResult[jss::tx_blob] =
149  strHex(tpTrans->getSTransaction()->getSerializer().peekData());
150 
151  if (temUNCERTAIN != tpTrans->getResult())
152  {
153  std::string sToken;
154  std::string sHuman;
155 
156  transResultInfo(tpTrans->getResult(), sToken, sHuman);
157 
158  jvResult[jss::engine_result] = sToken;
159  jvResult[jss::engine_result_code] = tpTrans->getResult();
160  jvResult[jss::engine_result_message] = sHuman;
161 
162  auto const submitResult = tpTrans->getSubmitResult();
163 
164  jvResult[jss::accepted] = submitResult.any();
165  jvResult[jss::applied] = submitResult.applied;
166  jvResult[jss::broadcast] = submitResult.broadcast;
167  jvResult[jss::queued] = submitResult.queued;
168  jvResult[jss::kept] = submitResult.kept;
169 
170  if (auto currentLedgerState = tpTrans->getCurrentLedgerState())
171  {
172  jvResult[jss::account_sequence_next] =
173  safe_cast<Json::Value::UInt>(
174  currentLedgerState->accountSeqNext);
175  jvResult[jss::account_sequence_available] =
176  safe_cast<Json::Value::UInt>(
177  currentLedgerState->accountSeqAvail);
178  jvResult[jss::open_ledger_cost] =
179  to_string(currentLedgerState->minFeeRequired);
180  jvResult[jss::validated_ledger_index] =
181  safe_cast<Json::Value::UInt>(
182  currentLedgerState->validatedLedger);
183  }
184  }
185 
186  return jvResult;
187  }
188  catch (std::exception& e)
189  {
190  jvResult[jss::error] = "internalJson";
191  jvResult[jss::error_exception] = e.what();
192 
193  return jvResult;
194  }
195 }
196 
200 {
201  // return values
202  org::xrpl::rpc::v1::SubmitTransactionResponse result;
203  grpc::Status status = grpc::Status::OK;
204 
205  // input
206  auto request = context.params;
207 
208  std::string const& tx = request.signed_transaction();
209 
210  // convert to blob
211  Blob blob{tx.begin(), tx.end()};
212 
213  // serialize
214  SerialIter sitTrans(makeSlice(blob));
216  try
217  {
218  stpTrans = std::make_shared<STTx const>(std::ref(sitTrans));
219  }
220  catch (std::exception& e)
221  {
222  grpc::Status errorStatus{
223  grpc::StatusCode::INVALID_ARGUMENT,
224  "invalid transaction: " + std::string(e.what())};
225  return {result, errorStatus};
226  }
227 
228  // check validity
229  {
230  if (!context.app.checkSigs())
232  context.app.getHashRouter(),
233  stpTrans->getTransactionID(),
235  auto [validity, reason] = checkValidity(
236  context.app.getHashRouter(),
237  *stpTrans,
238  context.ledgerMaster.getCurrentLedger()->rules(),
239  context.app.config());
240  if (validity != Validity::Valid)
241  {
242  grpc::Status errorStatus{
243  grpc::StatusCode::INVALID_ARGUMENT,
244  "invalid transaction: " + reason};
245  return {result, errorStatus};
246  }
247  }
248 
249  std::string reason;
250  auto tpTrans = std::make_shared<Transaction>(stpTrans, reason, context.app);
251  if (tpTrans->getStatus() != NEW)
252  {
253  grpc::Status errorStatus{
254  grpc::StatusCode::INVALID_ARGUMENT,
255  "invalid transaction: " + reason};
256  return {result, errorStatus};
257  }
258 
259  try
260  {
261  auto const failType = NetworkOPs::doFailHard(request.fail_hard());
262 
263  // submit to network
264  context.netOps.processTransaction(
265  tpTrans, isUnlimited(context.role), true, failType);
266  }
267  catch (std::exception& e)
268  {
269  grpc::Status errorStatus{
270  grpc::StatusCode::INVALID_ARGUMENT,
271  "invalid transaction : " + std::string(e.what())};
272  return {result, errorStatus};
273  }
274 
275  // return preliminary result
276  if (temUNCERTAIN != tpTrans->getResult())
277  {
278  RPC::convert(*result.mutable_engine_result(), tpTrans->getResult());
279 
280  std::string sToken;
281  std::string sHuman;
282 
283  transResultInfo(tpTrans->getResult(), sToken, sHuman);
284 
285  result.mutable_engine_result()->set_result(sToken);
286  result.set_engine_result_code(TERtoInt(tpTrans->getResult()));
287  result.set_engine_result_message(sHuman);
288 
289  uint256 hash = tpTrans->getID();
290  result.set_hash(hash.data(), hash.size());
291  }
292  return {result, status};
293 }
294 
295 } // namespace ripple
ripple::Application::checkSigs
virtual bool checkSigs() const =0
ripple::RPC::JsonContext
Definition: Context.h:53
ripple::rpcNOT_SUPPORTED
@ rpcNOT_SUPPORTED
Definition: ErrorCodes.h:132
ripple::makeSlice
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:240
std::string
STL class.
std::shared_ptr
STL class.
ripple::rpcINVALID_PARAMS
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
std::exception
STL class.
ripple::Resource::feeMediumBurdenRPC
const Charge feeMediumBurdenRPC
std::pair
ripple::RPC::Context::loadType
Resource::Charge & loadType
Definition: Context.h:43
std::vector< unsigned char >
ripple::NEW
@ NEW
Definition: Transaction.h:45
ripple::RPC::Context::ledgerMaster
LedgerMaster & ledgerMaster
Definition: Context.h:45
ripple::strUnHex
boost::optional< Blob > strUnHex(std::size_t strSize, Iterator begin, Iterator end)
Definition: StringUtilities.h:49
ripple::TERtoInt
constexpr TERUnderlyingType TERtoInt(TELcodes v)
Definition: TER.h:287
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:45
ripple::RPC::Context::role
Role role
Definition: Context.h:47
ripple::base_uint::data
pointer data()
Definition: base_uint.h:113
ripple::forceValidity
void forceValidity(HashRouter &router, uint256 const &txid, Validity validity)
Sets the validity of a given transaction in the cache.
Definition: apply.cpp:89
ripple::base_uint::size
constexpr static std::size_t size()
Definition: base_uint.h:426
Json::Value::asBool
bool asBool() const
Definition: json_value.cpp:619
ripple::temUNCERTAIN
@ temUNCERTAIN
Definition: TER.h:119
ripple::Validity::SigGoodOnly
@ SigGoodOnly
Signature is good, but local checks fail.
ripple::base_uint
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:73
ripple::RPC::convert
void convert(org::xrpl::rpc::v1::TransactionResult &to, TER from)
Definition: GRPCHelpers.cpp:961
ripple::RPC::getProcessTxnFn
ProcessTransactionFn getProcessTxnFn(NetworkOPs &netOPs)
Definition: TransactionSign.h:82
ripple::RPC::transactionSubmit
Json::Value transactionSubmit(Json::Value jvRequest, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:800
ripple::checkValidity
std::pair< Validity, std::string > checkValidity(HashRouter &router, STTx const &tx, Rules const &rules, Config const &config)
Checks transaction signature and local checks.
Definition: apply.cpp:37
ripple::doSubmit
Json::Value doSubmit(RPC::JsonContext &)
Definition: Submit.cpp:48
ripple::Role::ADMIN
@ ADMIN
ripple::JsonOptions::none
@ none
ripple::Application::config
virtual Config & config()=0
ripple::RPC::GRPCContext
Definition: Context.h:70
ripple::NetworkOPs::processTransaction
virtual void processTransaction(std::shared_ptr< Transaction > &transaction, bool bUnlimited, bool bLocal, FailHard failType)=0
Process transactions as they arrive from the network or which are submitted by clients.
ripple::RPC::Context::app
Application & app
Definition: Context.h:42
ripple::getFailHard
static NetworkOPs::FailHard getFailHard(RPC::JsonContext const &context)
Definition: Submit.cpp:36
ripple::SerialIter
Definition: Serializer.h:308
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::Config::canSign
bool canSign() const
Definition: Config.h:291
ripple::NetworkOPs::FailHard
FailHard
Definition: NetworkOPs.h:96
ripple::rpcError
Json::Value rpcError(int iError, Json::Value jvResult)
Definition: RPCErr.cpp:29
ripple::LedgerMaster::getCurrentLedger
std::shared_ptr< ReadView const > getCurrentLedger()
Definition: LedgerMaster.cpp:1571
ripple::RPC::Context::netOps
NetworkOPs & netOps
Definition: Context.h:44
ripple::STTx::getTransactionID
uint256 getTransactionID() const
Definition: STTx.h:117
ripple::isUnlimited
bool isUnlimited(Role const &role)
ADMIN and IDENTIFIED roles shall have unlimited resources.
Definition: Role.cpp:94
ripple::LedgerMaster::getValidatedLedgerAge
std::chrono::seconds getValidatedLedgerAge()
Definition: LedgerMaster.cpp:271
ripple::RPC::GRPCContext::params
RequestType params
Definition: Context.h:72
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::transResultInfo
bool transResultInfo(TER code, std::string &token, std::string &text)
Definition: TER.cpp:180
ripple::Validity::Valid
@ Valid
Signature and local checks are good / passed.
std::string::begin
T begin(T... args)
ripple::NetworkOPs::doFailHard
static FailHard doFailHard(bool noMeansDont)
Definition: NetworkOPs.h:98
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:45
std::string::end
T end(T... args)
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:64
ripple::Application::getHashRouter
virtual HashRouter & getHashRouter()=0
ripple::RPC::make_error
Json::Value make_error(error_code_i code)
Returns a new json object that reflects the error code.
Definition: ErrorCodes.cpp:209
std::ref
T ref(T... args)
std::exception::what
T what(T... args)
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::doSubmitGrpc
std::pair< org::xrpl::rpc::v1::SubmitTransactionResponse, grpc::Status > doSubmitGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::SubmitTransactionRequest > &context)
Definition: Submit.cpp:198
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469