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/impl/TransactionSign.h>
29 #include <ripple/rpc/GRPCHandlers.h>
30 #include <ripple/rpc/impl/RPCHelpers.h>
31 #include <ripple/rpc/impl/GRPCHelpers.h>
32 
33 namespace ripple {
34 
36 {
37  return NetworkOPs::doFailHard (
38  context.params.isMember ("fail_hard")
39  && context.params["fail_hard"].asBool ());
40 }
41 
42 // {
43 // tx_json: <object>,
44 // secret: <secret>
45 // }
47 {
49 
50  if (!context.params.isMember (jss::tx_blob))
51  {
52  auto const failType = getFailHard (context);
53 
54  if (context.role != Role::ADMIN && !context.app.config().canSign())
56  "Signing is not supported by this server.");
57 
58  auto ret = RPC::transactionSubmit (
59  context.params, failType, context.role,
61  context.app, RPC::getProcessTxnFn (context.netOps));
62 
63  ret[jss::deprecated] = "Signing support in the 'submit' command has been "
64  "deprecated and will be removed in a future version "
65  "of the server. Please migrate to a standalone "
66  "signing tool.";
67 
68  return ret;
69  }
70 
71  Json::Value jvResult;
72 
73  auto ret = strUnHex (context.params[jss::tx_blob].asString ());
74 
75  if (!ret || !ret->size ())
76  return rpcError (rpcINVALID_PARAMS);
77 
78  SerialIter sitTrans (makeSlice(*ret));
79 
81 
82  try
83  {
84  stpTrans = std::make_shared<STTx const> (std::ref (sitTrans));
85  }
86  catch (std::exception& e)
87  {
88  jvResult[jss::error] = "invalidTransaction";
89  jvResult[jss::error_exception] = e.what ();
90 
91  return jvResult;
92  }
93 
94 
95  {
96  if (!context.app.checkSigs())
99  auto [validity, reason] = checkValidity(context.app.getHashRouter(),
100  *stpTrans, context.ledgerMaster.getCurrentLedger()->rules(),
101  context.app.config());
102  if (validity != Validity::Valid)
103  {
104  jvResult[jss::error] = "invalidTransaction";
105  jvResult[jss::error_exception] = "fails local checks: " + reason;
106 
107  return jvResult;
108  }
109  }
110 
111  std::string reason;
112  auto tpTrans = std::make_shared<Transaction> (
113  stpTrans, reason, context.app);
114  if (tpTrans->getStatus() != NEW)
115  {
116  jvResult[jss::error] = "invalidTransaction";
117  jvResult[jss::error_exception] = "fails local checks: " + reason;
118 
119  return jvResult;
120  }
121 
122  try
123  {
124  auto const failType = getFailHard (context);
125 
126  context.netOps.processTransaction (
127  tpTrans, isUnlimited (context.role), true, failType);
128  }
129  catch (std::exception& e)
130  {
131  jvResult[jss::error] = "internalSubmit";
132  jvResult[jss::error_exception] = e.what ();
133 
134  return jvResult;
135  }
136 
137 
138  try
139  {
140  jvResult[jss::tx_json] = tpTrans->getJson (JsonOptions::none);
141  jvResult[jss::tx_blob] = strHex (
142  tpTrans->getSTransaction ()->getSerializer ().peekData ());
143 
144  if (temUNCERTAIN != tpTrans->getResult ())
145  {
146  std::string sToken;
147  std::string sHuman;
148 
149  transResultInfo (tpTrans->getResult (), sToken, sHuman);
150 
151  jvResult[jss::engine_result] = sToken;
152  jvResult[jss::engine_result_code] = tpTrans->getResult ();
153  jvResult[jss::engine_result_message] = sHuman;
154 
155  auto const submitResult = tpTrans->getSubmitResult();
156 
157  jvResult[jss::accepted] = submitResult.any();
158  jvResult[jss::applied] = submitResult.applied;
159  jvResult[jss::broadcast] = submitResult.broadcast;
160  jvResult[jss::queued] = submitResult.queued;
161  jvResult[jss::kept] = submitResult.kept;
162 
163  if (auto currentLedgerState = tpTrans->getCurrentLedgerState())
164  {
165  jvResult[jss::account_sequence_next]
166  = safe_cast<Json::Value::UInt>(currentLedgerState->accountSeqNext);
167  jvResult[jss::account_sequence_available]
168  = safe_cast<Json::Value::UInt>(currentLedgerState->accountSeqAvail);
169  jvResult[jss::open_ledger_cost]
170  = to_string(currentLedgerState->minFeeRequired);
171  jvResult[jss::validated_ledger_index]
172  = safe_cast<Json::Value::UInt>(currentLedgerState->validatedLedger);
173  }
174  }
175 
176  return jvResult;
177  }
178  catch (std::exception& e)
179  {
180  jvResult[jss::error] = "internalJson";
181  jvResult[jss::error_exception] = e.what ();
182 
183  return jvResult;
184  }
185 }
186 
189 {
190  // return values
191  org::xrpl::rpc::v1::SubmitTransactionResponse result;
192  grpc::Status status = grpc::Status::OK;
193 
194  // input
195  auto request = context.params;
196 
197  std::string const& tx = request.signed_transaction();
198 
199  // convert to blob
200  Blob blob{tx.begin(), tx.end()};
201 
202  // serialize
203  SerialIter sitTrans(makeSlice(blob));
205  try
206  {
207  stpTrans = std::make_shared<STTx const>(std::ref(sitTrans));
208  }
209  catch (std::exception& e)
210  {
211  grpc::Status errorStatus{
212  grpc::StatusCode::INVALID_ARGUMENT,
213  "invalid transaction: " + std::string(e.what())};
214  return {result, errorStatus};
215  }
216 
217  // check validity
218  {
219  if (!context.app.checkSigs())
221  context.app.getHashRouter(),
222  stpTrans->getTransactionID(),
224  auto [validity, reason] = checkValidity(
225  context.app.getHashRouter(),
226  *stpTrans,
227  context.ledgerMaster.getCurrentLedger()->rules(),
228  context.app.config());
229  if (validity != Validity::Valid)
230  {
231  grpc::Status errorStatus{grpc::StatusCode::INVALID_ARGUMENT,
232  "invalid transaction: " + reason};
233  return {result, errorStatus};
234  }
235  }
236 
237  std::string reason;
238  auto tpTrans = std::make_shared<Transaction>(stpTrans, reason, context.app);
239  if (tpTrans->getStatus() != NEW)
240  {
241  grpc::Status errorStatus{grpc::StatusCode::INVALID_ARGUMENT,
242  "invalid transaction: " + reason};
243  return {result, errorStatus};
244  }
245 
246  try
247  {
248  auto const failType = NetworkOPs::doFailHard(request.fail_hard());
249 
250  // submit to network
251  context.netOps.processTransaction(
252  tpTrans, isUnlimited(context.role), true, failType);
253  }
254  catch (std::exception& e)
255  {
256  grpc::Status errorStatus{
257  grpc::StatusCode::INVALID_ARGUMENT,
258  "invalid transaction : " + std::string(e.what())};
259  return {result, errorStatus};
260  }
261 
262  // return preliminary result
263  if (temUNCERTAIN != tpTrans->getResult())
264  {
265  RPC::convert(*result.mutable_engine_result(), tpTrans->getResult());
266 
267  std::string sToken;
268  std::string sHuman;
269 
270  transResultInfo(tpTrans->getResult(), sToken, sHuman);
271 
272  result.mutable_engine_result()->set_result(sToken);
273  result.set_engine_result_code(TERtoInt(tpTrans->getResult()));
274  result.set_engine_result_message(sHuman);
275 
276  uint256 hash = tpTrans->getID();
277  result.set_hash(hash.data(), hash.size());
278  }
279  return {result, status};
280 }
281 
282 } // namespace ripple
ripple::Application::checkSigs
virtual bool checkSigs() const =0
ripple::RPC::JsonContext
Definition: Context.h:52
ripple::rpcNOT_SUPPORTED
@ rpcNOT_SUPPORTED
Definition: ErrorCodes.h:133
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:199
std::string
STL class.
std::shared_ptr
STL class.
ripple::rpcINVALID_PARAMS
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:85
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:69
ripple::TERtoInt
constexpr TERUnderlyingType TERtoInt(TELcodes v)
Definition: TER.h:289
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::RPC::Context::role
Role role
Definition: Context.h:47
ripple::base_uint::data
pointer data()
Definition: base_uint.h:102
ripple::forceValidity
void forceValidity(HashRouter &router, uint256 const &txid, Validity validity)
Sets the validity of a given transaction in the cache.
Definition: apply.cpp:87
ripple::base_uint::size
constexpr static std::size_t size()
Definition: base_uint.h:417
Json::Value::asBool
bool asBool() const
Definition: json_value.cpp:626
ripple::temUNCERTAIN
@ temUNCERTAIN
Definition: TER.h:121
ripple::Validity::SigGoodOnly
@ SigGoodOnly
Signature is good, but local checks fail.
ripple::base_uint< 256 >
ripple::RPC::convert
void convert(org::xrpl::rpc::v1::TransactionResult &to, TER from)
Definition: GRPCHelpers.cpp:897
ripple::RPC::getProcessTxnFn
ProcessTransactionFn getProcessTxnFn(NetworkOPs &netOPs)
Definition: TransactionSign.h:78
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:790
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:46
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:35
ripple::SerialIter
Definition: Serializer.h:311
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:961
ripple::Config::canSign
bool canSign() const
Definition: Config.h:206
ripple::NetworkOPs::FailHard
FailHard
Definition: NetworkOPs.h:98
ripple::rpcError
Json::Value rpcError(int iError, Json::Value jvResult)
Definition: RPCErr.cpp:28
ripple::LedgerMaster::getCurrentLedger
std::shared_ptr< ReadView const > getCurrentLedger()
Definition: LedgerMaster.cpp:1503
ripple::RPC::Context::netOps
NetworkOPs & netOps
Definition: Context.h:44
ripple::STTx::getTransactionID
uint256 getTransactionID() const
Definition: STTx.h:120
ripple::isUnlimited
bool isUnlimited(Role const &role)
ADMIN and IDENTIFIED roles shall have unlimited resources.
Definition: Role.cpp:86
ripple::LedgerMaster::getValidatedLedgerAge
std::chrono::seconds getValidatedLedgerAge()
Definition: LedgerMaster.cpp:276
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:169
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:103
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:70
std::string::end
T end(T... args)
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:63
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:182
std::ref
T ref(T... args)
std::exception::what
T what(T... args)
Json::Value
Represents a JSON value.
Definition: json_value.h:141
ripple::doSubmitGrpc
std::pair< org::xrpl::rpc::v1::SubmitTransactionResponse, grpc::Status > doSubmitGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::SubmitTransactionRequest > &context)
Definition: Submit.cpp:188
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:482