diff --git a/JSONRPC__test_8cpp_source.html b/JSONRPC__test_8cpp_source.html index 94ea47c941..1f83e1b4bf 100644 --- a/JSONRPC__test_8cpp_source.html +++ b/JSONRPC__test_8cpp_source.html @@ -2729,15 +2729,15 @@ $(function() {
std::tuple
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:242
Json::Reader
Unserialize a JSON document into a Value.
Definition: json_reader.h:36
-
ripple::RPC::transactionSubmitMultiSigned
Json::Value transactionSubmitMultiSigned(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction, RPC::SubmitSync sync)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:1062
+
ripple::RPC::transactionSubmitMultiSigned
Json::Value transactionSubmitMultiSigned(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction, RPC::SubmitSync sync)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:1068
ripple::Application::getFeeTrack
virtual LoadFeeTrack & getFeeTrack()=0
ripple::RPC::JSONRPC_test::testAutoFillFees
void testAutoFillFees()
Definition: JSONRPC_test.cpp:2040
ripple::KeyType::ed25519
@ ed25519
-
ripple::RPC::checkFee
Json::Value checkFee(Json::Value &request, Role const role, bool doAutoFill, Config const &config, LoadFeeTrack const &feeTrack, TxQ const &txQ, Application const &app)
Fill in the fee on behalf of the client.
Definition: TransactionSign.cpp:690
+
ripple::RPC::checkFee
Json::Value checkFee(Json::Value &request, Role const role, bool doAutoFill, Config const &config, LoadFeeTrack const &feeTrack, TxQ const &txQ, Application const &app)
Fill in the fee on behalf of the client.
Definition: TransactionSign.cpp:696
ripple::Role::ADMIN
@ ADMIN
ripple::RPC::contains_error
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
Definition: ErrorCodes.cpp:196
ripple::Role::USER
@ USER
-
ripple::RPC::transactionSubmit
Json::Value transactionSubmit(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction, RPC::SubmitSync sync)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:824
+
ripple::RPC::transactionSubmit
Json::Value transactionSubmit(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction, RPC::SubmitSync sync)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:830
ripple::Application::config
virtual Config & config()=0
ripple::RPC::TxnTestData::TxnTestData
TxnTestData()=delete
ripple::RPC::JSONRPC_test::run
void run() override
Definition: JSONRPC_test.cpp:2604
@@ -2747,11 +2747,11 @@ $(function() {
ripple::RPC::TxnTestData::line
const int line
Definition: JSONRPC_test.cpp:40
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
std::array
STL class.
-
ripple::RPC::transactionSign
Json::Value transactionSign(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:786
+
ripple::RPC::transactionSign
Json::Value transactionSign(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:792
ripple::test::jtx::amm::trust
Json::Value trust(AccountID const &account, STAmount const &amount, std::uint32_t flags=0)
Definition: AMM.cpp:734
ripple::Role::FORBID
@ FORBID
ripple::RPC::TxnTestData::expMsg
const std::array< char const *const, 4 > expMsg
Definition: JSONRPC_test.cpp:51
-
ripple::RPC::transactionSignFor
Json::Value transactionSignFor(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:954
+
ripple::RPC::transactionSignFor
Json::Value transactionSignFor(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:960
ripple::RPC::SubmitSync::sync
@ sync
ripple::NetworkOPs::FailHard
FailHard
Definition: NetworkOPs.h:95
std::ostringstream
STL class.
diff --git a/SignFor_8cpp_source.html b/SignFor_8cpp_source.html index 81d69b7a70..9d04c8c954 100644 --- a/SignFor_8cpp_source.html +++ b/SignFor_8cpp_source.html @@ -143,7 +143,7 @@ $(function() {
ripple::Application::config
virtual Config & config()=0
ripple::RPC::Context::app
Application & app
Definition: Context.h:42
ripple::Config::canSign
bool canSign() const
Definition: Config.h:375
-
ripple::RPC::transactionSignFor
Json::Value transactionSignFor(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:954
+
ripple::RPC::transactionSignFor
Json::Value transactionSignFor(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:960
ripple::LedgerMaster::getValidatedLedgerAge
std::chrono::seconds getValidatedLedgerAge()
Definition: LedgerMaster.cpp:274
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::RPC::Context::apiVersion
unsigned int apiVersion
Definition: Context.h:50
diff --git a/SignHandler_8cpp_source.html b/SignHandler_8cpp_source.html index 2da75c4c89..c15b08f63c 100644 --- a/SignHandler_8cpp_source.html +++ b/SignHandler_8cpp_source.html @@ -140,7 +140,7 @@ $(function() {
Json::Value::asBool
bool asBool() const
Definition: json_value.cpp:619
ripple::Role::ADMIN
@ ADMIN
ripple::Application::config
virtual Config & config()=0
-
ripple::RPC::transactionSign
Json::Value transactionSign(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:786
+
ripple::RPC::transactionSign
Json::Value transactionSign(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:792
ripple::RPC::Context::app
Application & app
Definition: Context.h:42
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:375
diff --git a/SubmitMultiSigned_8cpp_source.html b/SubmitMultiSigned_8cpp_source.html index 115e67a436..e2a48f45d7 100644 --- a/SubmitMultiSigned_8cpp_source.html +++ b/SubmitMultiSigned_8cpp_source.html @@ -132,7 +132,7 @@ $(function() {
ripple::RPC::Context::ledgerMaster
LedgerMaster & ledgerMaster
Definition: Context.h:45
ripple::RPC::Context::role
Role role
Definition: Context.h:47
ripple::doSubmitMultiSigned
Json::Value doSubmitMultiSigned(RPC::JsonContext &)
Definition: SubmitMultiSigned.cpp:36
-
ripple::RPC::transactionSubmitMultiSigned
Json::Value transactionSubmitMultiSigned(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction, RPC::SubmitSync sync)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:1062
+
ripple::RPC::transactionSubmitMultiSigned
Json::Value transactionSubmitMultiSigned(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction, RPC::SubmitSync sync)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:1068
Json::Value::asBool
bool asBool() const
Definition: json_value.cpp:619
ripple::RPC::getProcessTxnFn
ProcessTransactionFn getProcessTxnFn(NetworkOPs &netOPs)
Definition: TransactionSign.h:83
ripple::RPC::Context::app
Application & app
Definition: Context.h:42
diff --git a/Submit_8cpp_source.html b/Submit_8cpp_source.html index f0712cba30..f72622c482 100644 --- a/Submit_8cpp_source.html +++ b/Submit_8cpp_source.html @@ -296,7 +296,7 @@ $(function() {
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::RPC::transactionSubmit
Json::Value transactionSubmit(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction, RPC::SubmitSync sync)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:824
+
ripple::RPC::transactionSubmit
Json::Value transactionSubmit(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction, RPC::SubmitSync sync)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:830
ripple::Application::config
virtual Config & config()=0
ripple::RPC::Context::app
Application & app
Definition: Context.h:42
ripple::getFailHard
static NetworkOPs::FailHard getFailHard(RPC::JsonContext const &context)
Definition: Submit.cpp:36
diff --git a/TransactionSign_8cpp_source.html b/TransactionSign_8cpp_source.html index 3f0fbb4e50..3fd40390d3 100644 --- a/TransactionSign_8cpp_source.html +++ b/TransactionSign_8cpp_source.html @@ -91,1238 +91,1244 @@ $(function() {
20 #include <ripple/app/ledger/LedgerMaster.h>
21 #include <ripple/app/ledger/OpenLedger.h>
22 #include <ripple/app/main/Application.h>
-
23 #include <ripple/app/misc/LoadFeeTrack.h>
-
24 #include <ripple/app/misc/Transaction.h>
-
25 #include <ripple/app/misc/TxQ.h>
-
26 #include <ripple/app/paths/Pathfinder.h>
-
27 #include <ripple/app/tx/apply.h> // Validity::Valid
-
28 #include <ripple/basics/Log.h>
-
29 #include <ripple/basics/mulDiv.h>
-
30 #include <ripple/json/json_writer.h>
-
31 #include <ripple/net/RPCErr.h>
-
32 #include <ripple/protocol/ErrorCodes.h>
-
33 #include <ripple/protocol/Feature.h>
-
34 #include <ripple/protocol/STAccount.h>
-
35 #include <ripple/protocol/STParsedJSON.h>
-
36 #include <ripple/protocol/Sign.h>
-
37 #include <ripple/protocol/TxFlags.h>
-
38 #include <ripple/rpc/impl/LegacyPathFind.h>
-
39 #include <ripple/rpc/impl/RPCHelpers.h>
-
40 #include <ripple/rpc/impl/TransactionSign.h>
-
41 #include <ripple/rpc/impl/Tuning.h>
-
42 #include <algorithm>
-
43 #include <iterator>
-
44 
-
45 namespace ripple {
-
46 namespace RPC {
-
47 namespace detail {
-
48 
-
49 // Used to pass extra parameters used when returning a
-
50 // a SigningFor object.
-
51 class SigningForParams
-
52 {
-
53 private:
-
54  AccountID const* const multiSigningAcctID_;
-
55  PublicKey* const multiSignPublicKey_;
-
56  Buffer* const multiSignature_;
-
57 
-
58 public:
-
59  explicit SigningForParams()
-
60  : multiSigningAcctID_(nullptr)
-
61  , multiSignPublicKey_(nullptr)
-
62  , multiSignature_(nullptr)
-
63  {
-
64  }
-
65 
-
66  SigningForParams(SigningForParams const& rhs) = delete;
-
67 
-
68  SigningForParams(
-
69  AccountID const& multiSigningAcctID,
-
70  PublicKey& multiSignPublicKey,
-
71  Buffer& multiSignature)
-
72  : multiSigningAcctID_(&multiSigningAcctID)
-
73  , multiSignPublicKey_(&multiSignPublicKey)
-
74  , multiSignature_(&multiSignature)
-
75  {
-
76  }
-
77 
-
78  bool
-
79  isMultiSigning() const
-
80  {
-
81  return (
-
82  (multiSigningAcctID_ != nullptr) &&
-
83  (multiSignPublicKey_ != nullptr) && (multiSignature_ != nullptr));
-
84  }
-
85 
-
86  bool
-
87  isSingleSigning() const
-
88  {
-
89  return !isMultiSigning();
-
90  }
-
91 
-
92  // When multi-signing we should not edit the tx_json fields.
-
93  bool
-
94  editFields() const
-
95  {
-
96  return !isMultiSigning();
-
97  }
-
98 
-
99  // Don't call this method unless isMultiSigning() returns true.
-
100  AccountID const&
-
101  getSigner()
-
102  {
-
103  return *multiSigningAcctID_;
-
104  }
-
105 
-
106  void
-
107  setPublicKey(PublicKey const& multiSignPublicKey)
-
108  {
-
109  *multiSignPublicKey_ = multiSignPublicKey;
-
110  }
-
111 
-
112  void
-
113  moveMultiSignature(Buffer&& multiSignature)
-
114  {
-
115  *multiSignature_ = std::move(multiSignature);
-
116  }
-
117 };
-
118 
-
119 //------------------------------------------------------------------------------
-
120 
-
121 static error_code_i
-
122 acctMatchesPubKey(
-
123  std::shared_ptr<SLE const> accountState,
-
124  AccountID const& accountID,
-
125  PublicKey const& publicKey)
-
126 {
-
127  auto const publicKeyAcctID = calcAccountID(publicKey);
-
128  bool const isMasterKey = publicKeyAcctID == accountID;
-
129 
-
130  // If we can't get the accountRoot, but the accountIDs match, that's
-
131  // good enough.
-
132  if (!accountState)
-
133  {
-
134  if (isMasterKey)
-
135  return rpcSUCCESS;
-
136  return rpcBAD_SECRET;
-
137  }
-
138 
-
139  // If we *can* get to the accountRoot, check for MASTER_DISABLED.
-
140  auto const& sle = *accountState;
-
141  if (isMasterKey)
-
142  {
-
143  if (sle.isFlag(lsfDisableMaster))
-
144  return rpcMASTER_DISABLED;
-
145  return rpcSUCCESS;
-
146  }
-
147 
-
148  // The last gasp is that we have public Regular key.
-
149  if ((sle.isFieldPresent(sfRegularKey)) &&
-
150  (publicKeyAcctID == sle.getAccountID(sfRegularKey)))
-
151  {
-
152  return rpcSUCCESS;
-
153  }
-
154  return rpcBAD_SECRET;
-
155 }
-
156 
-
157 static Json::Value
-
158 checkPayment(
-
159  Json::Value const& params,
-
160  Json::Value& tx_json,
-
161  AccountID const& srcAddressID,
-
162  Role const role,
-
163  Application& app,
-
164  bool doPath)
-
165 {
-
166  // Only path find for Payments.
-
167  if (tx_json[jss::TransactionType].asString() != jss::Payment)
-
168  return Json::Value();
-
169 
-
170  // DeliverMax is an alias to Amount and we use Amount internally
-
171  if (tx_json.isMember(jss::DeliverMax))
-
172  {
-
173  if (tx_json.isMember(jss::Amount))
-
174  {
-
175  if (tx_json[jss::DeliverMax] != tx_json[jss::Amount])
-
176  return RPC::make_error(
-
177  rpcINVALID_PARAMS,
-
178  "Cannot specify differing 'Amount' and 'DeliverMax'");
-
179  }
-
180  else
-
181  tx_json[jss::Amount] = tx_json[jss::DeliverMax];
-
182 
-
183  tx_json.removeMember(jss::DeliverMax);
-
184  }
-
185 
-
186  if (!tx_json.isMember(jss::Amount))
-
187  return RPC::missing_field_error("tx_json.Amount");
-
188 
-
189  STAmount amount;
-
190 
-
191  if (!amountFromJsonNoThrow(amount, tx_json[jss::Amount]))
-
192  return RPC::invalid_field_error("tx_json.Amount");
-
193 
-
194  if (!tx_json.isMember(jss::Destination))
-
195  return RPC::missing_field_error("tx_json.Destination");
-
196 
-
197  auto const dstAccountID =
-
198  parseBase58<AccountID>(tx_json[jss::Destination].asString());
-
199  if (!dstAccountID)
-
200  return RPC::invalid_field_error("tx_json.Destination");
-
201 
-
202  if ((doPath == false) && params.isMember(jss::build_path))
-
203  return RPC::make_error(
-
204  rpcINVALID_PARAMS,
-
205  "Field 'build_path' not allowed in this context.");
-
206 
-
207  if (tx_json.isMember(jss::Paths) && params.isMember(jss::build_path))
-
208  return RPC::make_error(
-
209  rpcINVALID_PARAMS,
-
210  "Cannot specify both 'tx_json.Paths' and 'build_path'");
-
211 
-
212  if (!tx_json.isMember(jss::Paths) && params.isMember(jss::build_path))
-
213  {
-
214  STAmount sendMax;
-
215 
-
216  if (tx_json.isMember(jss::SendMax))
-
217  {
-
218  if (!amountFromJsonNoThrow(sendMax, tx_json[jss::SendMax]))
-
219  return RPC::invalid_field_error("tx_json.SendMax");
-
220  }
-
221  else
-
222  {
-
223  // If no SendMax, default to Amount with sender as issuer.
-
224  sendMax = amount;
-
225  sendMax.setIssuer(srcAddressID);
-
226  }
-
227 
-
228  if (sendMax.native() && amount.native())
-
229  return RPC::make_error(
-
230  rpcINVALID_PARAMS, "Cannot build XRP to XRP paths.");
-
231 
-
232  {
-
233  LegacyPathFind lpf(isUnlimited(role), app);
-
234  if (!lpf.isOk())
-
235  return rpcError(rpcTOO_BUSY);
-
236 
-
237  STPathSet result;
-
238 
-
239  if (auto ledger = app.openLedger().current())
-
240  {
-
241  Pathfinder pf(
-
242  std::make_shared<RippleLineCache>(
-
243  ledger, app.journal("RippleLineCache")),
-
244  srcAddressID,
-
245  *dstAccountID,
-
246  sendMax.issue().currency,
-
247  sendMax.issue().account,
-
248  amount,
-
249  std::nullopt,
-
250  app);
-
251  if (pf.findPaths(app.config().PATH_SEARCH_OLD))
-
252  {
-
253  // 4 is the maxium paths
-
254  pf.computePathRanks(4);
-
255  STPath fullLiquidityPath;
-
256  STPathSet paths;
-
257  result = pf.getBestPaths(
-
258  4, fullLiquidityPath, paths, sendMax.issue().account);
-
259  }
-
260  }
-
261 
-
262  auto j = app.journal("RPCHandler");
-
263  JLOG(j.debug()) << "transactionSign: build_path: "
-
264  << result.getJson(JsonOptions::none);
-
265 
-
266  if (!result.empty())
-
267  tx_json[jss::Paths] = result.getJson(JsonOptions::none);
-
268  }
-
269  }
-
270  return Json::Value();
-
271 }
-
272 
-
273 //------------------------------------------------------------------------------
-
274 
-
275 // Validate (but don't modify) the contents of the tx_json.
-
276 //
-
277 // Returns a pair<Json::Value, AccountID>. The Json::Value will contain error
-
278 // information if there was an error. On success, the account ID is returned
-
279 // and the Json::Value will be empty.
-
280 //
-
281 // This code does not check the "Sequence" field, since the expectations
-
282 // for that field are particularly context sensitive.
-
283 static std::pair<Json::Value, AccountID>
-
284 checkTxJsonFields(
-
285  Json::Value const& tx_json,
-
286  Role const role,
-
287  bool const verify,
-
288  std::chrono::seconds validatedLedgerAge,
-
289  Config const& config,
-
290  LoadFeeTrack const& feeTrack,
-
291  unsigned apiVersion)
-
292 {
-
293  std::pair<Json::Value, AccountID> ret;
-
294 
-
295  if (!tx_json.isObject())
-
296  {
-
297  ret.first = RPC::object_field_error(jss::tx_json);
-
298  return ret;
-
299  }
-
300 
-
301  if (!tx_json.isMember(jss::TransactionType))
-
302  {
-
303  ret.first = RPC::missing_field_error("tx_json.TransactionType");
-
304  return ret;
-
305  }
-
306 
-
307  if (!tx_json.isMember(jss::Account))
-
308  {
-
309  ret.first = RPC::make_error(
-
310  rpcSRC_ACT_MISSING, RPC::missing_field_message("tx_json.Account"));
-
311  return ret;
-
312  }
-
313 
-
314  auto const srcAddressID =
-
315  parseBase58<AccountID>(tx_json[jss::Account].asString());
-
316 
-
317  if (!srcAddressID)
-
318  {
-
319  ret.first = RPC::make_error(
-
320  rpcSRC_ACT_MALFORMED,
-
321  RPC::invalid_field_message("tx_json.Account"));
-
322  return ret;
-
323  }
-
324 
-
325  // Check for current ledger.
-
326  if (verify && !config.standalone() &&
-
327  (validatedLedgerAge > Tuning::maxValidatedLedgerAge))
-
328  {
-
329  if (apiVersion == 1)
-
330  ret.first = rpcError(rpcNO_CURRENT);
-
331  else
-
332  ret.first = rpcError(rpcNOT_SYNCED);
-
333  return ret;
-
334  }
-
335 
-
336  // Check for load.
-
337  if (feeTrack.isLoadedCluster() && !isUnlimited(role))
-
338  {
-
339  ret.first = rpcError(rpcTOO_BUSY);
-
340  return ret;
-
341  }
-
342 
-
343  // It's all good. Return the AccountID.
-
344  ret.second = *srcAddressID;
-
345  return ret;
-
346 }
-
347 
-
348 //------------------------------------------------------------------------------
-
349 
-
350 // A move-only struct that makes it easy to return either a Json::Value or a
-
351 // std::shared_ptr<STTx const> from transactionPreProcessImpl ().
-
352 struct transactionPreProcessResult
-
353 {
-
354  Json::Value const first;
-
355  std::shared_ptr<STTx> const second;
-
356 
-
357  transactionPreProcessResult() = delete;
-
358  transactionPreProcessResult(transactionPreProcessResult const&) = delete;
-
359  transactionPreProcessResult(transactionPreProcessResult&& rhs) = default;
-
360 
-
361  transactionPreProcessResult&
-
362  operator=(transactionPreProcessResult const&) = delete;
-
363  transactionPreProcessResult&
-
364  operator=(transactionPreProcessResult&&) = delete;
-
365 
-
366  transactionPreProcessResult(Json::Value&& json)
-
367  : first(std::move(json)), second()
-
368  {
-
369  }
-
370 
-
371  explicit transactionPreProcessResult(std::shared_ptr<STTx>&& st)
-
372  : first(), second(std::move(st))
-
373  {
-
374  }
-
375 };
-
376 
-
377 static transactionPreProcessResult
-
378 transactionPreProcessImpl(
-
379  Json::Value& params,
-
380  Role role,
-
381  SigningForParams& signingArgs,
-
382  std::chrono::seconds validatedLedgerAge,
-
383  Application& app)
-
384 {
-
385  auto j = app.journal("RPCHandler");
-
386 
-
387  Json::Value jvResult;
-
388  auto const [pk, sk] = keypairForSignature(params, jvResult);
-
389  if (contains_error(jvResult))
-
390  return jvResult;
-
391 
-
392  bool const verify =
-
393  !(params.isMember(jss::offline) && params[jss::offline].asBool());
-
394 
-
395  if (!params.isMember(jss::tx_json))
-
396  return RPC::missing_field_error(jss::tx_json);
-
397 
-
398  Json::Value& tx_json(params[jss::tx_json]);
-
399 
-
400  // Check tx_json fields, but don't add any.
-
401  auto [txJsonResult, srcAddressID] = checkTxJsonFields(
-
402  tx_json,
-
403  role,
-
404  verify,
-
405  validatedLedgerAge,
-
406  app.config(),
-
407  app.getFeeTrack(),
-
408  getAPIVersionNumber(params, app.config().BETA_RPC_API));
-
409 
-
410  if (RPC::contains_error(txJsonResult))
-
411  return std::move(txJsonResult);
-
412 
-
413  // This test covers the case where we're offline so the sequence number
-
414  // cannot be determined locally. If we're offline then the caller must
-
415  // provide the sequence number.
-
416  if (!verify && !tx_json.isMember(jss::Sequence))
-
417  return RPC::missing_field_error("tx_json.Sequence");
-
418 
-
419  std::shared_ptr<SLE const> sle;
-
420  if (verify)
-
421  sle = app.openLedger().current()->read(keylet::account(srcAddressID));
-
422 
-
423  if (verify && !sle)
-
424  {
-
425  // If not offline and did not find account, error.
-
426  JLOG(j.debug()) << "transactionSign: Failed to find source account "
-
427  << "in current ledger: " << toBase58(srcAddressID);
-
428 
-
429  return rpcError(rpcSRC_ACT_NOT_FOUND);
-
430  }
-
431 
-
432  {
-
433  Json::Value err = checkFee(
-
434  params,
-
435  role,
-
436  verify && signingArgs.editFields(),
-
437  app.config(),
-
438  app.getFeeTrack(),
-
439  app.getTxQ(),
-
440  app);
-
441 
-
442  if (RPC::contains_error(err))
-
443  return err;
-
444 
-
445  err = checkPayment(
-
446  params,
-
447  tx_json,
-
448  srcAddressID,
-
449  role,
-
450  app,
-
451  verify && signingArgs.editFields());
-
452 
-
453  if (RPC::contains_error(err))
-
454  return err;
-
455  }
-
456 
-
457  if (signingArgs.editFields())
-
458  {
-
459  if (!tx_json.isMember(jss::Sequence))
-
460  {
-
461  bool const hasTicketSeq =
-
462  tx_json.isMember(sfTicketSequence.jsonName);
-
463  if (!hasTicketSeq && !sle)
-
464  {
-
465  JLOG(j.debug())
-
466  << "transactionSign: Failed to find source account "
-
467  << "in current ledger: " << toBase58(srcAddressID);
-
468 
-
469  return rpcError(rpcSRC_ACT_NOT_FOUND);
-
470  }
-
471  tx_json[jss::Sequence] =
-
472  hasTicketSeq ? 0 : app.getTxQ().nextQueuableSeq(sle).value();
-
473  }
-
474 
-
475  if (!tx_json.isMember(jss::Flags))
-
476  tx_json[jss::Flags] = tfFullyCanonicalSig;
-
477  }
-
478 
-
479  // If multisigning there should not be a single signature and vice versa.
-
480  if (signingArgs.isMultiSigning())
-
481  {
-
482  if (tx_json.isMember(sfTxnSignature.jsonName))
-
483  return rpcError(rpcALREADY_SINGLE_SIG);
-
484 
-
485  // If multisigning then we need to return the public key.
-
486  signingArgs.setPublicKey(pk);
-
487  }
-
488  else if (signingArgs.isSingleSigning())
-
489  {
-
490  if (tx_json.isMember(sfSigners.jsonName))
-
491  return rpcError(rpcALREADY_MULTISIG);
-
492  }
-
493 
-
494  if (verify)
-
495  {
-
496  if (!sle)
-
497  // XXX Ignore transactions for accounts not created.
-
498  return rpcError(rpcSRC_ACT_NOT_FOUND);
-
499 
-
500  JLOG(j.trace()) << "verify: " << toBase58(calcAccountID(pk)) << " : "
-
501  << toBase58(srcAddressID);
-
502 
-
503  // Don't do this test if multisigning since the account and secret
-
504  // probably don't belong together in that case.
-
505  if (!signingArgs.isMultiSigning())
-
506  {
-
507  // Make sure the account and secret belong together.
-
508  auto const err = acctMatchesPubKey(sle, srcAddressID, pk);
-
509 
-
510  if (err != rpcSUCCESS)
-
511  return rpcError(err);
-
512  }
-
513  }
-
514 
-
515  STParsedJSONObject parsed(std::string(jss::tx_json), tx_json);
-
516  if (!parsed.object.has_value())
-
517  {
-
518  Json::Value err;
-
519  err[jss::error] = parsed.error[jss::error];
-
520  err[jss::error_code] = parsed.error[jss::error_code];
-
521  err[jss::error_message] = parsed.error[jss::error_message];
-
522  return err;
-
523  }
-
524 
-
525  std::shared_ptr<STTx> stpTrans;
-
526  try
-
527  {
-
528  // If we're generating a multi-signature the SigningPubKey must be
-
529  // empty, otherwise it must be the master account's public key.
-
530  parsed.object->setFieldVL(
-
531  sfSigningPubKey,
-
532  signingArgs.isMultiSigning() ? Slice(nullptr, 0) : pk.slice());
-
533 
-
534  stpTrans = std::make_shared<STTx>(std::move(parsed.object.value()));
-
535  }
-
536  catch (STObject::FieldErr& err)
-
537  {
-
538  return RPC::make_error(rpcINVALID_PARAMS, err.what());
-
539  }
-
540  catch (std::exception&)
-
541  {
-
542  return RPC::make_error(
-
543  rpcINTERNAL,
-
544  "Exception occurred constructing serialized transaction");
-
545  }
-
546 
-
547  std::string reason;
-
548  if (!passesLocalChecks(*stpTrans, reason))
-
549  return RPC::make_error(rpcINVALID_PARAMS, reason);
-
550 
-
551  // If multisign then return multiSignature, else set TxnSignature field.
-
552  if (signingArgs.isMultiSigning())
-
553  {
-
554  Serializer s =
-
555  buildMultiSigningData(*stpTrans, signingArgs.getSigner());
-
556 
-
557  auto multisig = ripple::sign(pk, sk, s.slice());
-
558 
-
559  signingArgs.moveMultiSignature(std::move(multisig));
-
560  }
-
561  else if (signingArgs.isSingleSigning())
-
562  {
-
563  stpTrans->sign(pk, sk);
-
564  }
-
565 
-
566  return transactionPreProcessResult{std::move(stpTrans)};
-
567 }
-
568 
-
569 static std::pair<Json::Value, Transaction::pointer>
-
570 transactionConstructImpl(
-
571  std::shared_ptr<STTx const> const& stpTrans,
-
572  Rules const& rules,
-
573  Application& app)
-
574 {
-
575  std::pair<Json::Value, Transaction::pointer> ret;
-
576 
-
577  // Turn the passed in STTx into a Transaction.
-
578  Transaction::pointer tpTrans;
-
579  {
-
580  std::string reason;
-
581  tpTrans = std::make_shared<Transaction>(stpTrans, reason, app);
-
582  if (tpTrans->getStatus() != NEW)
-
583  {
-
584  ret.first = RPC::make_error(
-
585  rpcINTERNAL, "Unable to construct transaction: " + reason);
-
586  return ret;
-
587  }
-
588  }
-
589  try
-
590  {
-
591  // Make sure the Transaction we just built is legit by serializing it
-
592  // and then de-serializing it. If the result isn't equivalent
-
593  // to the initial transaction then there's something wrong with the
-
594  // passed-in STTx.
-
595  {
-
596  Serializer s;
-
597  tpTrans->getSTransaction()->add(s);
-
598  Blob transBlob = s.getData();
-
599  SerialIter sit{makeSlice(transBlob)};
-
600 
-
601  // Check the signature if that's called for.
-
602  auto sttxNew = std::make_shared<STTx const>(sit);
-
603  if (!app.checkSigs())
-
604  forceValidity(
-
605  app.getHashRouter(),
-
606  sttxNew->getTransactionID(),
-
607  Validity::SigGoodOnly);
-
608  if (checkValidity(
-
609  app.getHashRouter(), *sttxNew, rules, app.config())
-
610  .first != Validity::Valid)
-
611  {
-
612  ret.first = RPC::make_error(rpcINTERNAL, "Invalid signature.");
-
613  return ret;
-
614  }
-
615 
-
616  std::string reason;
-
617  auto tpTransNew =
-
618  std::make_shared<Transaction>(sttxNew, reason, app);
-
619 
-
620  if (tpTransNew)
-
621  {
-
622  if (!tpTransNew->getSTransaction()->isEquivalent(
-
623  *tpTrans->getSTransaction()))
-
624  {
-
625  tpTransNew.reset();
-
626  }
-
627  tpTrans = std::move(tpTransNew);
-
628  }
-
629  }
-
630  }
-
631  catch (std::exception&)
-
632  {
-
633  // Assume that any exceptions are related to transaction sterilization.
-
634  tpTrans.reset();
-
635  }
-
636 
-
637  if (!tpTrans)
-
638  {
-
639  ret.first =
-
640  RPC::make_error(rpcINTERNAL, "Unable to sterilize transaction.");
-
641  return ret;
-
642  }
-
643  ret.second = std::move(tpTrans);
-
644  return ret;
-
645 }
-
646 
-
647 static Json::Value
-
648 transactionFormatResultImpl(Transaction::pointer tpTrans, unsigned apiVersion)
-
649 {
-
650  Json::Value jvResult;
-
651  try
-
652  {
-
653  if (apiVersion > 1)
-
654  {
-
655  jvResult[jss::tx_json] =
-
656  tpTrans->getJson(JsonOptions::disable_API_prior_V2);
-
657  jvResult[jss::hash] = to_string(tpTrans->getID());
-
658  }
-
659  else
-
660  jvResult[jss::tx_json] = tpTrans->getJson(JsonOptions::none);
-
661 
-
662  jvResult[jss::tx_blob] =
-
663  strHex(tpTrans->getSTransaction()->getSerializer().peekData());
-
664 
-
665  if (temUNCERTAIN != tpTrans->getResult())
-
666  {
-
667  std::string sToken;
-
668  std::string sHuman;
-
669 
-
670  transResultInfo(tpTrans->getResult(), sToken, sHuman);
-
671 
-
672  jvResult[jss::engine_result] = sToken;
-
673  jvResult[jss::engine_result_code] = tpTrans->getResult();
-
674  jvResult[jss::engine_result_message] = sHuman;
-
675  }
-
676  }
-
677  catch (std::exception&)
-
678  {
-
679  jvResult = RPC::make_error(
-
680  rpcINTERNAL, "Exception occurred during JSON handling.");
-
681  }
-
682  return jvResult;
-
683 }
-
684 
-
685 } // namespace detail
-
686 
-
687 //------------------------------------------------------------------------------
-
688 
-
689 Json::Value
-
690 checkFee(
-
691  Json::Value& request,
-
692  Role const role,
-
693  bool doAutoFill,
-
694  Config const& config,
-
695  LoadFeeTrack const& feeTrack,
-
696  TxQ const& txQ,
-
697  Application const& app)
-
698 {
-
699  Json::Value& tx(request[jss::tx_json]);
-
700  if (tx.isMember(jss::Fee))
-
701  return Json::Value();
-
702 
-
703  if (!doAutoFill)
-
704  return RPC::missing_field_error("tx_json.Fee");
-
705 
-
706  int mult = Tuning::defaultAutoFillFeeMultiplier;
-
707  int div = Tuning::defaultAutoFillFeeDivisor;
-
708  if (request.isMember(jss::fee_mult_max))
-
709  {
-
710  if (request[jss::fee_mult_max].isInt())
-
711  {
-
712  mult = request[jss::fee_mult_max].asInt();
-
713  if (mult < 0)
-
714  return RPC::make_error(
-
715  rpcINVALID_PARAMS,
-
716  RPC::expected_field_message(
-
717  jss::fee_mult_max, "a positive integer"));
-
718  }
-
719  else
-
720  {
-
721  return RPC::make_error(
-
722  rpcHIGH_FEE,
-
723  RPC::expected_field_message(
-
724  jss::fee_mult_max, "a positive integer"));
-
725  }
-
726  }
-
727  if (request.isMember(jss::fee_div_max))
-
728  {
-
729  if (request[jss::fee_div_max].isInt())
-
730  {
-
731  div = request[jss::fee_div_max].asInt();
-
732  if (div <= 0)
-
733  return RPC::make_error(
-
734  rpcINVALID_PARAMS,
-
735  RPC::expected_field_message(
-
736  jss::fee_div_max, "a positive integer"));
-
737  }
-
738  else
-
739  {
-
740  return RPC::make_error(
-
741  rpcHIGH_FEE,
-
742  RPC::expected_field_message(
-
743  jss::fee_div_max, "a positive integer"));
-
744  }
-
745  }
-
746 
-
747  XRPAmount const feeDefault = config.FEES.reference_fee;
-
748 
-
749  auto ledger = app.openLedger().current();
-
750  // Administrative and identified endpoints are exempt from local fees.
-
751  XRPAmount const loadFee =
-
752  scaleFeeLoad(feeDefault, feeTrack, ledger->fees(), isUnlimited(role));
-
753  XRPAmount fee = loadFee;
-
754  {
-
755  auto const metrics = txQ.getMetrics(*ledger);
-
756  auto const baseFee = ledger->fees().base;
-
757  auto escalatedFee =
-
758  toDrops(metrics.openLedgerFeeLevel - FeeLevel64(1), baseFee) + 1;
-
759  fee = std::max(fee, escalatedFee);
-
760  }
-
761 
-
762  auto const limit = [&]() {
-
763  // Scale fee units to drops:
-
764  auto const result = mulDiv(feeDefault, mult, div);
-
765  if (!result)
-
766  Throw<std::overflow_error>("mulDiv");
-
767  return *result;
-
768  }();
-
769 
-
770  if (fee > limit)
-
771  {
-
772  std::stringstream ss;
-
773  ss << "Fee of " << fee << " exceeds the requested tx limit of "
-
774  << limit;
-
775  return RPC::make_error(rpcHIGH_FEE, ss.str());
-
776  }
-
777 
-
778  tx[jss::Fee] = fee.jsonClipped();
-
779  return Json::Value();
-
780 }
-
781 
-
782 //------------------------------------------------------------------------------
+
23 #include <ripple/app/misc/DeliverMax.h>
+
24 #include <ripple/app/misc/LoadFeeTrack.h>
+
25 #include <ripple/app/misc/Transaction.h>
+
26 #include <ripple/app/misc/TxQ.h>
+
27 #include <ripple/app/paths/Pathfinder.h>
+
28 #include <ripple/app/tx/apply.h> // Validity::Valid
+
29 #include <ripple/basics/Log.h>
+
30 #include <ripple/basics/mulDiv.h>
+
31 #include <ripple/json/json_writer.h>
+
32 #include <ripple/net/RPCErr.h>
+
33 #include <ripple/protocol/ErrorCodes.h>
+
34 #include <ripple/protocol/Feature.h>
+
35 #include <ripple/protocol/STAccount.h>
+
36 #include <ripple/protocol/STParsedJSON.h>
+
37 #include <ripple/protocol/Sign.h>
+
38 #include <ripple/protocol/TxFlags.h>
+
39 #include <ripple/rpc/impl/LegacyPathFind.h>
+
40 #include <ripple/rpc/impl/RPCHelpers.h>
+
41 #include <ripple/rpc/impl/TransactionSign.h>
+
42 #include <ripple/rpc/impl/Tuning.h>
+
43 #include <algorithm>
+
44 #include <iterator>
+
45 
+
46 namespace ripple {
+
47 namespace RPC {
+
48 namespace detail {
+
49 
+
50 // Used to pass extra parameters used when returning a
+
51 // a SigningFor object.
+
52 class SigningForParams
+
53 {
+
54 private:
+
55  AccountID const* const multiSigningAcctID_;
+
56  PublicKey* const multiSignPublicKey_;
+
57  Buffer* const multiSignature_;
+
58 
+
59 public:
+
60  explicit SigningForParams()
+
61  : multiSigningAcctID_(nullptr)
+
62  , multiSignPublicKey_(nullptr)
+
63  , multiSignature_(nullptr)
+
64  {
+
65  }
+
66 
+
67  SigningForParams(SigningForParams const& rhs) = delete;
+
68 
+
69  SigningForParams(
+
70  AccountID const& multiSigningAcctID,
+
71  PublicKey& multiSignPublicKey,
+
72  Buffer& multiSignature)
+
73  : multiSigningAcctID_(&multiSigningAcctID)
+
74  , multiSignPublicKey_(&multiSignPublicKey)
+
75  , multiSignature_(&multiSignature)
+
76  {
+
77  }
+
78 
+
79  bool
+
80  isMultiSigning() const
+
81  {
+
82  return (
+
83  (multiSigningAcctID_ != nullptr) &&
+
84  (multiSignPublicKey_ != nullptr) && (multiSignature_ != nullptr));
+
85  }
+
86 
+
87  bool
+
88  isSingleSigning() const
+
89  {
+
90  return !isMultiSigning();
+
91  }
+
92 
+
93  // When multi-signing we should not edit the tx_json fields.
+
94  bool
+
95  editFields() const
+
96  {
+
97  return !isMultiSigning();
+
98  }
+
99 
+
100  // Don't call this method unless isMultiSigning() returns true.
+
101  AccountID const&
+
102  getSigner()
+
103  {
+
104  return *multiSigningAcctID_;
+
105  }
+
106 
+
107  void
+
108  setPublicKey(PublicKey const& multiSignPublicKey)
+
109  {
+
110  *multiSignPublicKey_ = multiSignPublicKey;
+
111  }
+
112 
+
113  void
+
114  moveMultiSignature(Buffer&& multiSignature)
+
115  {
+
116  *multiSignature_ = std::move(multiSignature);
+
117  }
+
118 };
+
119 
+
120 //------------------------------------------------------------------------------
+
121 
+
122 static error_code_i
+
123 acctMatchesPubKey(
+
124  std::shared_ptr<SLE const> accountState,
+
125  AccountID const& accountID,
+
126  PublicKey const& publicKey)
+
127 {
+
128  auto const publicKeyAcctID = calcAccountID(publicKey);
+
129  bool const isMasterKey = publicKeyAcctID == accountID;
+
130 
+
131  // If we can't get the accountRoot, but the accountIDs match, that's
+
132  // good enough.
+
133  if (!accountState)
+
134  {
+
135  if (isMasterKey)
+
136  return rpcSUCCESS;
+
137  return rpcBAD_SECRET;
+
138  }
+
139 
+
140  // If we *can* get to the accountRoot, check for MASTER_DISABLED.
+
141  auto const& sle = *accountState;
+
142  if (isMasterKey)
+
143  {
+
144  if (sle.isFlag(lsfDisableMaster))
+
145  return rpcMASTER_DISABLED;
+
146  return rpcSUCCESS;
+
147  }
+
148 
+
149  // The last gasp is that we have public Regular key.
+
150  if ((sle.isFieldPresent(sfRegularKey)) &&
+
151  (publicKeyAcctID == sle.getAccountID(sfRegularKey)))
+
152  {
+
153  return rpcSUCCESS;
+
154  }
+
155  return rpcBAD_SECRET;
+
156 }
+
157 
+
158 static Json::Value
+
159 checkPayment(
+
160  Json::Value const& params,
+
161  Json::Value& tx_json,
+
162  AccountID const& srcAddressID,
+
163  Role const role,
+
164  Application& app,
+
165  bool doPath)
+
166 {
+
167  // Only path find for Payments.
+
168  if (tx_json[jss::TransactionType].asString() != jss::Payment)
+
169  return Json::Value();
+
170 
+
171  // DeliverMax is an alias to Amount and we use Amount internally
+
172  if (tx_json.isMember(jss::DeliverMax))
+
173  {
+
174  if (tx_json.isMember(jss::Amount))
+
175  {
+
176  if (tx_json[jss::DeliverMax] != tx_json[jss::Amount])
+
177  return RPC::make_error(
+
178  rpcINVALID_PARAMS,
+
179  "Cannot specify differing 'Amount' and 'DeliverMax'");
+
180  }
+
181  else
+
182  tx_json[jss::Amount] = tx_json[jss::DeliverMax];
+
183 
+
184  tx_json.removeMember(jss::DeliverMax);
+
185  }
+
186 
+
187  if (!tx_json.isMember(jss::Amount))
+
188  return RPC::missing_field_error("tx_json.Amount");
+
189 
+
190  STAmount amount;
+
191 
+
192  if (!amountFromJsonNoThrow(amount, tx_json[jss::Amount]))
+
193  return RPC::invalid_field_error("tx_json.Amount");
+
194 
+
195  if (!tx_json.isMember(jss::Destination))
+
196  return RPC::missing_field_error("tx_json.Destination");
+
197 
+
198  auto const dstAccountID =
+
199  parseBase58<AccountID>(tx_json[jss::Destination].asString());
+
200  if (!dstAccountID)
+
201  return RPC::invalid_field_error("tx_json.Destination");
+
202 
+
203  if ((doPath == false) && params.isMember(jss::build_path))
+
204  return RPC::make_error(
+
205  rpcINVALID_PARAMS,
+
206  "Field 'build_path' not allowed in this context.");
+
207 
+
208  if (tx_json.isMember(jss::Paths) && params.isMember(jss::build_path))
+
209  return RPC::make_error(
+
210  rpcINVALID_PARAMS,
+
211  "Cannot specify both 'tx_json.Paths' and 'build_path'");
+
212 
+
213  if (!tx_json.isMember(jss::Paths) && params.isMember(jss::build_path))
+
214  {
+
215  STAmount sendMax;
+
216 
+
217  if (tx_json.isMember(jss::SendMax))
+
218  {
+
219  if (!amountFromJsonNoThrow(sendMax, tx_json[jss::SendMax]))
+
220  return RPC::invalid_field_error("tx_json.SendMax");
+
221  }
+
222  else
+
223  {
+
224  // If no SendMax, default to Amount with sender as issuer.
+
225  sendMax = amount;
+
226  sendMax.setIssuer(srcAddressID);
+
227  }
+
228 
+
229  if (sendMax.native() && amount.native())
+
230  return RPC::make_error(
+
231  rpcINVALID_PARAMS, "Cannot build XRP to XRP paths.");
+
232 
+
233  {
+
234  LegacyPathFind lpf(isUnlimited(role), app);
+
235  if (!lpf.isOk())
+
236  return rpcError(rpcTOO_BUSY);
+
237 
+
238  STPathSet result;
+
239 
+
240  if (auto ledger = app.openLedger().current())
+
241  {
+
242  Pathfinder pf(
+
243  std::make_shared<RippleLineCache>(
+
244  ledger, app.journal("RippleLineCache")),
+
245  srcAddressID,
+
246  *dstAccountID,
+
247  sendMax.issue().currency,
+
248  sendMax.issue().account,
+
249  amount,
+
250  std::nullopt,
+
251  app);
+
252  if (pf.findPaths(app.config().PATH_SEARCH_OLD))
+
253  {
+
254  // 4 is the maxium paths
+
255  pf.computePathRanks(4);
+
256  STPath fullLiquidityPath;
+
257  STPathSet paths;
+
258  result = pf.getBestPaths(
+
259  4, fullLiquidityPath, paths, sendMax.issue().account);
+
260  }
+
261  }
+
262 
+
263  auto j = app.journal("RPCHandler");
+
264  JLOG(j.debug()) << "transactionSign: build_path: "
+
265  << result.getJson(JsonOptions::none);
+
266 
+
267  if (!result.empty())
+
268  tx_json[jss::Paths] = result.getJson(JsonOptions::none);
+
269  }
+
270  }
+
271  return Json::Value();
+
272 }
+
273 
+
274 //------------------------------------------------------------------------------
+
275 
+
276 // Validate (but don't modify) the contents of the tx_json.
+
277 //
+
278 // Returns a pair<Json::Value, AccountID>. The Json::Value will contain error
+
279 // information if there was an error. On success, the account ID is returned
+
280 // and the Json::Value will be empty.
+
281 //
+
282 // This code does not check the "Sequence" field, since the expectations
+
283 // for that field are particularly context sensitive.
+
284 static std::pair<Json::Value, AccountID>
+
285 checkTxJsonFields(
+
286  Json::Value const& tx_json,
+
287  Role const role,
+
288  bool const verify,
+
289  std::chrono::seconds validatedLedgerAge,
+
290  Config const& config,
+
291  LoadFeeTrack const& feeTrack,
+
292  unsigned apiVersion)
+
293 {
+
294  std::pair<Json::Value, AccountID> ret;
+
295 
+
296  if (!tx_json.isObject())
+
297  {
+
298  ret.first = RPC::object_field_error(jss::tx_json);
+
299  return ret;
+
300  }
+
301 
+
302  if (!tx_json.isMember(jss::TransactionType))
+
303  {
+
304  ret.first = RPC::missing_field_error("tx_json.TransactionType");
+
305  return ret;
+
306  }
+
307 
+
308  if (!tx_json.isMember(jss::Account))
+
309  {
+
310  ret.first = RPC::make_error(
+
311  rpcSRC_ACT_MISSING, RPC::missing_field_message("tx_json.Account"));
+
312  return ret;
+
313  }
+
314 
+
315  auto const srcAddressID =
+
316  parseBase58<AccountID>(tx_json[jss::Account].asString());
+
317 
+
318  if (!srcAddressID)
+
319  {
+
320  ret.first = RPC::make_error(
+
321  rpcSRC_ACT_MALFORMED,
+
322  RPC::invalid_field_message("tx_json.Account"));
+
323  return ret;
+
324  }
+
325 
+
326  // Check for current ledger.
+
327  if (verify && !config.standalone() &&
+
328  (validatedLedgerAge > Tuning::maxValidatedLedgerAge))
+
329  {
+
330  if (apiVersion == 1)
+
331  ret.first = rpcError(rpcNO_CURRENT);
+
332  else
+
333  ret.first = rpcError(rpcNOT_SYNCED);
+
334  return ret;
+
335  }
+
336 
+
337  // Check for load.
+
338  if (feeTrack.isLoadedCluster() && !isUnlimited(role))
+
339  {
+
340  ret.first = rpcError(rpcTOO_BUSY);
+
341  return ret;
+
342  }
+
343 
+
344  // It's all good. Return the AccountID.
+
345  ret.second = *srcAddressID;
+
346  return ret;
+
347 }
+
348 
+
349 //------------------------------------------------------------------------------
+
350 
+
351 // A move-only struct that makes it easy to return either a Json::Value or a
+
352 // std::shared_ptr<STTx const> from transactionPreProcessImpl ().
+
353 struct transactionPreProcessResult
+
354 {
+
355  Json::Value const first;
+
356  std::shared_ptr<STTx> const second;
+
357 
+
358  transactionPreProcessResult() = delete;
+
359  transactionPreProcessResult(transactionPreProcessResult const&) = delete;
+
360  transactionPreProcessResult(transactionPreProcessResult&& rhs) = default;
+
361 
+
362  transactionPreProcessResult&
+
363  operator=(transactionPreProcessResult const&) = delete;
+
364  transactionPreProcessResult&
+
365  operator=(transactionPreProcessResult&&) = delete;
+
366 
+
367  transactionPreProcessResult(Json::Value&& json)
+
368  : first(std::move(json)), second()
+
369  {
+
370  }
+
371 
+
372  explicit transactionPreProcessResult(std::shared_ptr<STTx>&& st)
+
373  : first(), second(std::move(st))
+
374  {
+
375  }
+
376 };
+
377 
+
378 static transactionPreProcessResult
+
379 transactionPreProcessImpl(
+
380  Json::Value& params,
+
381  Role role,
+
382  SigningForParams& signingArgs,
+
383  std::chrono::seconds validatedLedgerAge,
+
384  Application& app)
+
385 {
+
386  auto j = app.journal("RPCHandler");
+
387 
+
388  Json::Value jvResult;
+
389  auto const [pk, sk] = keypairForSignature(params, jvResult);
+
390  if (contains_error(jvResult))
+
391  return jvResult;
+
392 
+
393  bool const verify =
+
394  !(params.isMember(jss::offline) && params[jss::offline].asBool());
+
395 
+
396  if (!params.isMember(jss::tx_json))
+
397  return RPC::missing_field_error(jss::tx_json);
+
398 
+
399  Json::Value& tx_json(params[jss::tx_json]);
+
400 
+
401  // Check tx_json fields, but don't add any.
+
402  auto [txJsonResult, srcAddressID] = checkTxJsonFields(
+
403  tx_json,
+
404  role,
+
405  verify,
+
406  validatedLedgerAge,
+
407  app.config(),
+
408  app.getFeeTrack(),
+
409  getAPIVersionNumber(params, app.config().BETA_RPC_API));
+
410 
+
411  if (RPC::contains_error(txJsonResult))
+
412  return std::move(txJsonResult);
+
413 
+
414  // This test covers the case where we're offline so the sequence number
+
415  // cannot be determined locally. If we're offline then the caller must
+
416  // provide the sequence number.
+
417  if (!verify && !tx_json.isMember(jss::Sequence))
+
418  return RPC::missing_field_error("tx_json.Sequence");
+
419 
+
420  std::shared_ptr<SLE const> sle;
+
421  if (verify)
+
422  sle = app.openLedger().current()->read(keylet::account(srcAddressID));
+
423 
+
424  if (verify && !sle)
+
425  {
+
426  // If not offline and did not find account, error.
+
427  JLOG(j.debug()) << "transactionSign: Failed to find source account "
+
428  << "in current ledger: " << toBase58(srcAddressID);
+
429 
+
430  return rpcError(rpcSRC_ACT_NOT_FOUND);
+
431  }
+
432 
+
433  {
+
434  Json::Value err = checkFee(
+
435  params,
+
436  role,
+
437  verify && signingArgs.editFields(),
+
438  app.config(),
+
439  app.getFeeTrack(),
+
440  app.getTxQ(),
+
441  app);
+
442 
+
443  if (RPC::contains_error(err))
+
444  return err;
+
445 
+
446  err = checkPayment(
+
447  params,
+
448  tx_json,
+
449  srcAddressID,
+
450  role,
+
451  app,
+
452  verify && signingArgs.editFields());
+
453 
+
454  if (RPC::contains_error(err))
+
455  return err;
+
456  }
+
457 
+
458  if (signingArgs.editFields())
+
459  {
+
460  if (!tx_json.isMember(jss::Sequence))
+
461  {
+
462  bool const hasTicketSeq =
+
463  tx_json.isMember(sfTicketSequence.jsonName);
+
464  if (!hasTicketSeq && !sle)
+
465  {
+
466  JLOG(j.debug())
+
467  << "transactionSign: Failed to find source account "
+
468  << "in current ledger: " << toBase58(srcAddressID);
+
469 
+
470  return rpcError(rpcSRC_ACT_NOT_FOUND);
+
471  }
+
472  tx_json[jss::Sequence] =
+
473  hasTicketSeq ? 0 : app.getTxQ().nextQueuableSeq(sle).value();
+
474  }
+
475 
+
476  if (!tx_json.isMember(jss::Flags))
+
477  tx_json[jss::Flags] = tfFullyCanonicalSig;
+
478  }
+
479 
+
480  // If multisigning there should not be a single signature and vice versa.
+
481  if (signingArgs.isMultiSigning())
+
482  {
+
483  if (tx_json.isMember(sfTxnSignature.jsonName))
+
484  return rpcError(rpcALREADY_SINGLE_SIG);
+
485 
+
486  // If multisigning then we need to return the public key.
+
487  signingArgs.setPublicKey(pk);
+
488  }
+
489  else if (signingArgs.isSingleSigning())
+
490  {
+
491  if (tx_json.isMember(sfSigners.jsonName))
+
492  return rpcError(rpcALREADY_MULTISIG);
+
493  }
+
494 
+
495  if (verify)
+
496  {
+
497  if (!sle)
+
498  // XXX Ignore transactions for accounts not created.
+
499  return rpcError(rpcSRC_ACT_NOT_FOUND);
+
500 
+
501  JLOG(j.trace()) << "verify: " << toBase58(calcAccountID(pk)) << " : "
+
502  << toBase58(srcAddressID);
+
503 
+
504  // Don't do this test if multisigning since the account and secret
+
505  // probably don't belong together in that case.
+
506  if (!signingArgs.isMultiSigning())
+
507  {
+
508  // Make sure the account and secret belong together.
+
509  auto const err = acctMatchesPubKey(sle, srcAddressID, pk);
+
510 
+
511  if (err != rpcSUCCESS)
+
512  return rpcError(err);
+
513  }
+
514  }
+
515 
+
516  STParsedJSONObject parsed(std::string(jss::tx_json), tx_json);
+
517  if (!parsed.object.has_value())
+
518  {
+
519  Json::Value err;
+
520  err[jss::error] = parsed.error[jss::error];
+
521  err[jss::error_code] = parsed.error[jss::error_code];
+
522  err[jss::error_message] = parsed.error[jss::error_message];
+
523  return err;
+
524  }
+
525 
+
526  std::shared_ptr<STTx> stpTrans;
+
527  try
+
528  {
+
529  // If we're generating a multi-signature the SigningPubKey must be
+
530  // empty, otherwise it must be the master account's public key.
+
531  parsed.object->setFieldVL(
+
532  sfSigningPubKey,
+
533  signingArgs.isMultiSigning() ? Slice(nullptr, 0) : pk.slice());
+
534 
+
535  stpTrans = std::make_shared<STTx>(std::move(parsed.object.value()));
+
536  }
+
537  catch (STObject::FieldErr& err)
+
538  {
+
539  return RPC::make_error(rpcINVALID_PARAMS, err.what());
+
540  }
+
541  catch (std::exception&)
+
542  {
+
543  return RPC::make_error(
+
544  rpcINTERNAL,
+
545  "Exception occurred constructing serialized transaction");
+
546  }
+
547 
+
548  std::string reason;
+
549  if (!passesLocalChecks(*stpTrans, reason))
+
550  return RPC::make_error(rpcINVALID_PARAMS, reason);
+
551 
+
552  // If multisign then return multiSignature, else set TxnSignature field.
+
553  if (signingArgs.isMultiSigning())
+
554  {
+
555  Serializer s =
+
556  buildMultiSigningData(*stpTrans, signingArgs.getSigner());
+
557 
+
558  auto multisig = ripple::sign(pk, sk, s.slice());
+
559 
+
560  signingArgs.moveMultiSignature(std::move(multisig));
+
561  }
+
562  else if (signingArgs.isSingleSigning())
+
563  {
+
564  stpTrans->sign(pk, sk);
+
565  }
+
566 
+
567  return transactionPreProcessResult{std::move(stpTrans)};
+
568 }
+
569 
+
570 static std::pair<Json::Value, Transaction::pointer>
+
571 transactionConstructImpl(
+
572  std::shared_ptr<STTx const> const& stpTrans,
+
573  Rules const& rules,
+
574  Application& app)
+
575 {
+
576  std::pair<Json::Value, Transaction::pointer> ret;
+
577 
+
578  // Turn the passed in STTx into a Transaction.
+
579  Transaction::pointer tpTrans;
+
580  {
+
581  std::string reason;
+
582  tpTrans = std::make_shared<Transaction>(stpTrans, reason, app);
+
583  if (tpTrans->getStatus() != NEW)
+
584  {
+
585  ret.first = RPC::make_error(
+
586  rpcINTERNAL, "Unable to construct transaction: " + reason);
+
587  return ret;
+
588  }
+
589  }
+
590  try
+
591  {
+
592  // Make sure the Transaction we just built is legit by serializing it
+
593  // and then de-serializing it. If the result isn't equivalent
+
594  // to the initial transaction then there's something wrong with the
+
595  // passed-in STTx.
+
596  {
+
597  Serializer s;
+
598  tpTrans->getSTransaction()->add(s);
+
599  Blob transBlob = s.getData();
+
600  SerialIter sit{makeSlice(transBlob)};
+
601 
+
602  // Check the signature if that's called for.
+
603  auto sttxNew = std::make_shared<STTx const>(sit);
+
604  if (!app.checkSigs())
+
605  forceValidity(
+
606  app.getHashRouter(),
+
607  sttxNew->getTransactionID(),
+
608  Validity::SigGoodOnly);
+
609  if (checkValidity(
+
610  app.getHashRouter(), *sttxNew, rules, app.config())
+
611  .first != Validity::Valid)
+
612  {
+
613  ret.first = RPC::make_error(rpcINTERNAL, "Invalid signature.");
+
614  return ret;
+
615  }
+
616 
+
617  std::string reason;
+
618  auto tpTransNew =
+
619  std::make_shared<Transaction>(sttxNew, reason, app);
+
620 
+
621  if (tpTransNew)
+
622  {
+
623  if (!tpTransNew->getSTransaction()->isEquivalent(
+
624  *tpTrans->getSTransaction()))
+
625  {
+
626  tpTransNew.reset();
+
627  }
+
628  tpTrans = std::move(tpTransNew);
+
629  }
+
630  }
+
631  }
+
632  catch (std::exception&)
+
633  {
+
634  // Assume that any exceptions are related to transaction sterilization.
+
635  tpTrans.reset();
+
636  }
+
637 
+
638  if (!tpTrans)
+
639  {
+
640  ret.first =
+
641  RPC::make_error(rpcINTERNAL, "Unable to sterilize transaction.");
+
642  return ret;
+
643  }
+
644  ret.second = std::move(tpTrans);
+
645  return ret;
+
646 }
+
647 
+
648 static Json::Value
+
649 transactionFormatResultImpl(Transaction::pointer tpTrans, unsigned apiVersion)
+
650 {
+
651  Json::Value jvResult;
+
652  try
+
653  {
+
654  if (apiVersion > 1)
+
655  {
+
656  jvResult[jss::tx_json] =
+
657  tpTrans->getJson(JsonOptions::disable_API_prior_V2);
+
658  jvResult[jss::hash] = to_string(tpTrans->getID());
+
659  }
+
660  else
+
661  jvResult[jss::tx_json] = tpTrans->getJson(JsonOptions::none);
+
662 
+
663  RPC::insertDeliverMax(
+
664  jvResult[jss::tx_json],
+
665  tpTrans->getSTransaction()->getTxnType(),
+
666  apiVersion);
+
667 
+
668  jvResult[jss::tx_blob] =
+
669  strHex(tpTrans->getSTransaction()->getSerializer().peekData());
+
670 
+
671  if (temUNCERTAIN != tpTrans->getResult())
+
672  {
+
673  std::string sToken;
+
674  std::string sHuman;
+
675 
+
676  transResultInfo(tpTrans->getResult(), sToken, sHuman);
+
677 
+
678  jvResult[jss::engine_result] = sToken;
+
679  jvResult[jss::engine_result_code] = tpTrans->getResult();
+
680  jvResult[jss::engine_result_message] = sHuman;
+
681  }
+
682  }
+
683  catch (std::exception&)
+
684  {
+
685  jvResult = RPC::make_error(
+
686  rpcINTERNAL, "Exception occurred during JSON handling.");
+
687  }
+
688  return jvResult;
+
689 }
+
690 
+
691 } // namespace detail
+
692 
+
693 //------------------------------------------------------------------------------
+
694 
+
695 Json::Value
+
696 checkFee(
+
697  Json::Value& request,
+
698  Role const role,
+
699  bool doAutoFill,
+
700  Config const& config,
+
701  LoadFeeTrack const& feeTrack,
+
702  TxQ const& txQ,
+
703  Application const& app)
+
704 {
+
705  Json::Value& tx(request[jss::tx_json]);
+
706  if (tx.isMember(jss::Fee))
+
707  return Json::Value();
+
708 
+
709  if (!doAutoFill)
+
710  return RPC::missing_field_error("tx_json.Fee");
+
711 
+
712  int mult = Tuning::defaultAutoFillFeeMultiplier;
+
713  int div = Tuning::defaultAutoFillFeeDivisor;
+
714  if (request.isMember(jss::fee_mult_max))
+
715  {
+
716  if (request[jss::fee_mult_max].isInt())
+
717  {
+
718  mult = request[jss::fee_mult_max].asInt();
+
719  if (mult < 0)
+
720  return RPC::make_error(
+
721  rpcINVALID_PARAMS,
+
722  RPC::expected_field_message(
+
723  jss::fee_mult_max, "a positive integer"));
+
724  }
+
725  else
+
726  {
+
727  return RPC::make_error(
+
728  rpcHIGH_FEE,
+
729  RPC::expected_field_message(
+
730  jss::fee_mult_max, "a positive integer"));
+
731  }
+
732  }
+
733  if (request.isMember(jss::fee_div_max))
+
734  {
+
735  if (request[jss::fee_div_max].isInt())
+
736  {
+
737  div = request[jss::fee_div_max].asInt();
+
738  if (div <= 0)
+
739  return RPC::make_error(
+
740  rpcINVALID_PARAMS,
+
741  RPC::expected_field_message(
+
742  jss::fee_div_max, "a positive integer"));
+
743  }
+
744  else
+
745  {
+
746  return RPC::make_error(
+
747  rpcHIGH_FEE,
+
748  RPC::expected_field_message(
+
749  jss::fee_div_max, "a positive integer"));
+
750  }
+
751  }
+
752 
+
753  XRPAmount const feeDefault = config.FEES.reference_fee;
+
754 
+
755  auto ledger = app.openLedger().current();
+
756  // Administrative and identified endpoints are exempt from local fees.
+
757  XRPAmount const loadFee =
+
758  scaleFeeLoad(feeDefault, feeTrack, ledger->fees(), isUnlimited(role));
+
759  XRPAmount fee = loadFee;
+
760  {
+
761  auto const metrics = txQ.getMetrics(*ledger);
+
762  auto const baseFee = ledger->fees().base;
+
763  auto escalatedFee =
+
764  toDrops(metrics.openLedgerFeeLevel - FeeLevel64(1), baseFee) + 1;
+
765  fee = std::max(fee, escalatedFee);
+
766  }
+
767 
+
768  auto const limit = [&]() {
+
769  // Scale fee units to drops:
+
770  auto const result = mulDiv(feeDefault, mult, div);
+
771  if (!result)
+
772  Throw<std::overflow_error>("mulDiv");
+
773  return *result;
+
774  }();
+
775 
+
776  if (fee > limit)
+
777  {
+
778  std::stringstream ss;
+
779  ss << "Fee of " << fee << " exceeds the requested tx limit of "
+
780  << limit;
+
781  return RPC::make_error(rpcHIGH_FEE, ss.str());
+
782  }
783 
-
785 Json::Value
-
786 transactionSign(
-
787  Json::Value jvRequest,
-
788  unsigned apiVersion,
-
789  NetworkOPs::FailHard failType,
-
790  Role role,
-
791  std::chrono::seconds validatedLedgerAge,
-
792  Application& app)
-
793 {
-
794  using namespace detail;
-
795 
-
796  auto j = app.journal("RPCHandler");
-
797  JLOG(j.debug()) << "transactionSign: " << jvRequest;
-
798 
-
799  // Add and amend fields based on the transaction type.
-
800  SigningForParams signForParams;
-
801  transactionPreProcessResult preprocResult = transactionPreProcessImpl(
-
802  jvRequest, role, signForParams, validatedLedgerAge, app);
-
803 
-
804  if (!preprocResult.second)
-
805  return preprocResult.first;
-
806 
-
807  std::shared_ptr<const ReadView> ledger;
-
808  if (app.config().reporting())
-
809  ledger = app.getLedgerMaster().getValidatedLedger();
-
810  else
-
811  ledger = app.openLedger().current();
-
812  // Make sure the STTx makes a legitimate Transaction.
-
813  std::pair<Json::Value, Transaction::pointer> txn =
-
814  transactionConstructImpl(preprocResult.second, ledger->rules(), app);
-
815 
-
816  if (!txn.second)
-
817  return txn.first;
-
818 
-
819  return transactionFormatResultImpl(txn.second, apiVersion);
-
820 }
+
784  tx[jss::Fee] = fee.jsonClipped();
+
785  return Json::Value();
+
786 }
+
787 
+
788 //------------------------------------------------------------------------------
+
789 
+
791 Json::Value
+
792 transactionSign(
+
793  Json::Value jvRequest,
+
794  unsigned apiVersion,
+
795  NetworkOPs::FailHard failType,
+
796  Role role,
+
797  std::chrono::seconds validatedLedgerAge,
+
798  Application& app)
+
799 {
+
800  using namespace detail;
+
801 
+
802  auto j = app.journal("RPCHandler");
+
803  JLOG(j.debug()) << "transactionSign: " << jvRequest;
+
804 
+
805  // Add and amend fields based on the transaction type.
+
806  SigningForParams signForParams;
+
807  transactionPreProcessResult preprocResult = transactionPreProcessImpl(
+
808  jvRequest, role, signForParams, validatedLedgerAge, app);
+
809 
+
810  if (!preprocResult.second)
+
811  return preprocResult.first;
+
812 
+
813  std::shared_ptr<const ReadView> ledger;
+
814  if (app.config().reporting())
+
815  ledger = app.getLedgerMaster().getValidatedLedger();
+
816  else
+
817  ledger = app.openLedger().current();
+
818  // Make sure the STTx makes a legitimate Transaction.
+
819  std::pair<Json::Value, Transaction::pointer> txn =
+
820  transactionConstructImpl(preprocResult.second, ledger->rules(), app);
821 
-
823 Json::Value
-
824 transactionSubmit(
-
825  Json::Value jvRequest,
-
826  unsigned apiVersion,
-
827  NetworkOPs::FailHard failType,
-
828  Role role,
-
829  std::chrono::seconds validatedLedgerAge,
-
830  Application& app,
-
831  ProcessTransactionFn const& processTransaction,
-
832  RPC::SubmitSync sync)
-
833 {
-
834  using namespace detail;
-
835 
-
836  auto const& ledger = app.openLedger().current();
-
837  auto j = app.journal("RPCHandler");
-
838  JLOG(j.debug()) << "transactionSubmit: " << jvRequest;
-
839 
-
840  // Add and amend fields based on the transaction type.
-
841  SigningForParams signForParams;
-
842  transactionPreProcessResult preprocResult = transactionPreProcessImpl(
-
843  jvRequest, role, signForParams, validatedLedgerAge, app);
-
844 
-
845  if (!preprocResult.second)
-
846  return preprocResult.first;
-
847 
-
848  // Make sure the STTx makes a legitimate Transaction.
-
849  std::pair<Json::Value, Transaction::pointer> txn =
-
850  transactionConstructImpl(preprocResult.second, ledger->rules(), app);
-
851 
-
852  if (!txn.second)
-
853  return txn.first;
-
854 
-
855  // Finally, submit the transaction.
-
856  try
-
857  {
-
858  processTransaction(txn.second, isUnlimited(role), sync, failType);
-
859  }
-
860  catch (std::exception&)
-
861  {
-
862  return RPC::make_error(
-
863  rpcINTERNAL, "Exception occurred during transaction submission.");
-
864  }
-
865 
-
866  return transactionFormatResultImpl(txn.second, apiVersion);
-
867 }
-
868 
-
869 namespace detail {
-
870 // There are a some field checks shared by transactionSignFor
-
871 // and transactionSubmitMultiSigned. Gather them together here.
-
872 static Json::Value
-
873 checkMultiSignFields(Json::Value const& jvRequest)
-
874 {
-
875  if (!jvRequest.isMember(jss::tx_json))
-
876  return RPC::missing_field_error(jss::tx_json);
-
877 
-
878  Json::Value const& tx_json(jvRequest[jss::tx_json]);
-
879 
-
880  if (!tx_json.isObject())
-
881  return RPC::invalid_field_message(jss::tx_json);
-
882 
-
883  // There are a couple of additional fields we need to check before
-
884  // we serialize. If we serialize first then we generate less useful
-
885  // error messages.
-
886  if (!tx_json.isMember(jss::Sequence))
-
887  return RPC::missing_field_error("tx_json.Sequence");
+
822  if (!txn.second)
+
823  return txn.first;
+
824 
+
825  return transactionFormatResultImpl(txn.second, apiVersion);
+
826 }
+
827 
+
829 Json::Value
+
830 transactionSubmit(
+
831  Json::Value jvRequest,
+
832  unsigned apiVersion,
+
833  NetworkOPs::FailHard failType,
+
834  Role role,
+
835  std::chrono::seconds validatedLedgerAge,
+
836  Application& app,
+
837  ProcessTransactionFn const& processTransaction,
+
838  RPC::SubmitSync sync)
+
839 {
+
840  using namespace detail;
+
841 
+
842  auto const& ledger = app.openLedger().current();
+
843  auto j = app.journal("RPCHandler");
+
844  JLOG(j.debug()) << "transactionSubmit: " << jvRequest;
+
845 
+
846  // Add and amend fields based on the transaction type.
+
847  SigningForParams signForParams;
+
848  transactionPreProcessResult preprocResult = transactionPreProcessImpl(
+
849  jvRequest, role, signForParams, validatedLedgerAge, app);
+
850 
+
851  if (!preprocResult.second)
+
852  return preprocResult.first;
+
853 
+
854  // Make sure the STTx makes a legitimate Transaction.
+
855  std::pair<Json::Value, Transaction::pointer> txn =
+
856  transactionConstructImpl(preprocResult.second, ledger->rules(), app);
+
857 
+
858  if (!txn.second)
+
859  return txn.first;
+
860 
+
861  // Finally, submit the transaction.
+
862  try
+
863  {
+
864  processTransaction(txn.second, isUnlimited(role), sync, failType);
+
865  }
+
866  catch (std::exception&)
+
867  {
+
868  return RPC::make_error(
+
869  rpcINTERNAL, "Exception occurred during transaction submission.");
+
870  }
+
871 
+
872  return transactionFormatResultImpl(txn.second, apiVersion);
+
873 }
+
874 
+
875 namespace detail {
+
876 // There are a some field checks shared by transactionSignFor
+
877 // and transactionSubmitMultiSigned. Gather them together here.
+
878 static Json::Value
+
879 checkMultiSignFields(Json::Value const& jvRequest)
+
880 {
+
881  if (!jvRequest.isMember(jss::tx_json))
+
882  return RPC::missing_field_error(jss::tx_json);
+
883 
+
884  Json::Value const& tx_json(jvRequest[jss::tx_json]);
+
885 
+
886  if (!tx_json.isObject())
+
887  return RPC::invalid_field_message(jss::tx_json);
888 
-
889  if (!tx_json.isMember(sfSigningPubKey.getJsonName()))
-
890  return RPC::missing_field_error("tx_json.SigningPubKey");
-
891 
-
892  if (!tx_json[sfSigningPubKey.getJsonName()].asString().empty())
-
893  return RPC::make_error(
-
894  rpcINVALID_PARAMS,
-
895  "When multi-signing 'tx_json.SigningPubKey' must be empty.");
-
896 
-
897  return Json::Value();
-
898 }
-
899 
-
900 // Sort and validate an stSigners array.
-
901 //
-
902 // Returns a null Json::Value if there are no errors.
-
903 static Json::Value
-
904 sortAndValidateSigners(STArray& signers, AccountID const& signingForID)
-
905 {
-
906  if (signers.empty())
-
907  return RPC::make_param_error("Signers array may not be empty.");
-
908 
-
909  // Signers must be sorted by Account.
-
910  std::sort(
-
911  signers.begin(),
-
912  signers.end(),
-
913  [](STObject const& a, STObject const& b) {
-
914  return (a[sfAccount] < b[sfAccount]);
-
915  });
-
916 
-
917  // Signers may not contain any duplicates.
-
918  auto const dupIter = std::adjacent_find(
-
919  signers.begin(),
-
920  signers.end(),
-
921  [](STObject const& a, STObject const& b) {
-
922  return (a[sfAccount] == b[sfAccount]);
-
923  });
-
924 
-
925  if (dupIter != signers.end())
-
926  {
-
927  std::ostringstream err;
-
928  err << "Duplicate Signers:Signer:Account entries ("
-
929  << toBase58((*dupIter)[sfAccount]) << ") are not allowed.";
-
930  return RPC::make_param_error(err.str());
-
931  }
-
932 
-
933  // An account may not sign for itself.
-
934  if (signers.end() !=
-
935  std::find_if(
-
936  signers.begin(),
-
937  signers.end(),
-
938  [&signingForID](STObject const& elem) {
-
939  return elem[sfAccount] == signingForID;
-
940  }))
-
941  {
-
942  std::ostringstream err;
-
943  err << "A Signer may not be the transaction's Account ("
-
944  << toBase58(signingForID) << ").";
-
945  return RPC::make_param_error(err.str());
-
946  }
-
947  return {};
-
948 }
-
949 
-
950 } // namespace detail
-
951 
-
953 Json::Value
-
954 transactionSignFor(
-
955  Json::Value jvRequest,
-
956  unsigned apiVersion,
-
957  NetworkOPs::FailHard failType,
-
958  Role role,
-
959  std::chrono::seconds validatedLedgerAge,
-
960  Application& app)
-
961 {
-
962  auto const& ledger = app.openLedger().current();
-
963  auto j = app.journal("RPCHandler");
-
964  JLOG(j.debug()) << "transactionSignFor: " << jvRequest;
-
965 
-
966  // Verify presence of the signer's account field.
-
967  const char accountField[] = "account";
-
968 
-
969  if (!jvRequest.isMember(accountField))
-
970  return RPC::missing_field_error(accountField);
+
889  // There are a couple of additional fields we need to check before
+
890  // we serialize. If we serialize first then we generate less useful
+
891  // error messages.
+
892  if (!tx_json.isMember(jss::Sequence))
+
893  return RPC::missing_field_error("tx_json.Sequence");
+
894 
+
895  if (!tx_json.isMember(sfSigningPubKey.getJsonName()))
+
896  return RPC::missing_field_error("tx_json.SigningPubKey");
+
897 
+
898  if (!tx_json[sfSigningPubKey.getJsonName()].asString().empty())
+
899  return RPC::make_error(
+
900  rpcINVALID_PARAMS,
+
901  "When multi-signing 'tx_json.SigningPubKey' must be empty.");
+
902 
+
903  return Json::Value();
+
904 }
+
905 
+
906 // Sort and validate an stSigners array.
+
907 //
+
908 // Returns a null Json::Value if there are no errors.
+
909 static Json::Value
+
910 sortAndValidateSigners(STArray& signers, AccountID const& signingForID)
+
911 {
+
912  if (signers.empty())
+
913  return RPC::make_param_error("Signers array may not be empty.");
+
914 
+
915  // Signers must be sorted by Account.
+
916  std::sort(
+
917  signers.begin(),
+
918  signers.end(),
+
919  [](STObject const& a, STObject const& b) {
+
920  return (a[sfAccount] < b[sfAccount]);
+
921  });
+
922 
+
923  // Signers may not contain any duplicates.
+
924  auto const dupIter = std::adjacent_find(
+
925  signers.begin(),
+
926  signers.end(),
+
927  [](STObject const& a, STObject const& b) {
+
928  return (a[sfAccount] == b[sfAccount]);
+
929  });
+
930 
+
931  if (dupIter != signers.end())
+
932  {
+
933  std::ostringstream err;
+
934  err << "Duplicate Signers:Signer:Account entries ("
+
935  << toBase58((*dupIter)[sfAccount]) << ") are not allowed.";
+
936  return RPC::make_param_error(err.str());
+
937  }
+
938 
+
939  // An account may not sign for itself.
+
940  if (signers.end() !=
+
941  std::find_if(
+
942  signers.begin(),
+
943  signers.end(),
+
944  [&signingForID](STObject const& elem) {
+
945  return elem[sfAccount] == signingForID;
+
946  }))
+
947  {
+
948  std::ostringstream err;
+
949  err << "A Signer may not be the transaction's Account ("
+
950  << toBase58(signingForID) << ").";
+
951  return RPC::make_param_error(err.str());
+
952  }
+
953  return {};
+
954 }
+
955 
+
956 } // namespace detail
+
957 
+
959 Json::Value
+
960 transactionSignFor(
+
961  Json::Value jvRequest,
+
962  unsigned apiVersion,
+
963  NetworkOPs::FailHard failType,
+
964  Role role,
+
965  std::chrono::seconds validatedLedgerAge,
+
966  Application& app)
+
967 {
+
968  auto const& ledger = app.openLedger().current();
+
969  auto j = app.journal("RPCHandler");
+
970  JLOG(j.debug()) << "transactionSignFor: " << jvRequest;
971 
-
972  // Turn the signer's account into an AccountID for multi-sign.
-
973  auto const signerAccountID =
-
974  parseBase58<AccountID>(jvRequest[accountField].asString());
-
975  if (!signerAccountID)
-
976  {
-
977  return RPC::make_error(
-
978  rpcSRC_ACT_MALFORMED, RPC::invalid_field_message(accountField));
-
979  }
-
980 
-
981  if (!jvRequest.isMember(jss::tx_json))
-
982  return RPC::missing_field_error(jss::tx_json);
-
983 
-
984  {
-
985  Json::Value& tx_json(jvRequest[jss::tx_json]);
+
972  // Verify presence of the signer's account field.
+
973  const char accountField[] = "account";
+
974 
+
975  if (!jvRequest.isMember(accountField))
+
976  return RPC::missing_field_error(accountField);
+
977 
+
978  // Turn the signer's account into an AccountID for multi-sign.
+
979  auto const signerAccountID =
+
980  parseBase58<AccountID>(jvRequest[accountField].asString());
+
981  if (!signerAccountID)
+
982  {
+
983  return RPC::make_error(
+
984  rpcSRC_ACT_MALFORMED, RPC::invalid_field_message(accountField));
+
985  }
986 
-
987  if (!tx_json.isObject())
-
988  return RPC::object_field_error(jss::tx_json);
+
987  if (!jvRequest.isMember(jss::tx_json))
+
988  return RPC::missing_field_error(jss::tx_json);
989 
-
990  // If the tx_json.SigningPubKey field is missing,
-
991  // insert an empty one.
-
992  if (!tx_json.isMember(sfSigningPubKey.getJsonName()))
-
993  tx_json[sfSigningPubKey.getJsonName()] = "";
-
994  }
+
990  {
+
991  Json::Value& tx_json(jvRequest[jss::tx_json]);
+
992 
+
993  if (!tx_json.isObject())
+
994  return RPC::object_field_error(jss::tx_json);
995 
-
996  // When multi-signing, the "Sequence" and "SigningPubKey" fields must
-
997  // be passed in by the caller.
-
998  using namespace detail;
-
999  {
-
1000  Json::Value err = checkMultiSignFields(jvRequest);
-
1001  if (RPC::contains_error(err))
-
1002  return err;
-
1003  }
-
1004 
-
1005  // Add and amend fields based on the transaction type.
-
1006  Buffer multiSignature;
-
1007  PublicKey multiSignPubKey;
-
1008  SigningForParams signForParams(
-
1009  *signerAccountID, multiSignPubKey, multiSignature);
+
996  // If the tx_json.SigningPubKey field is missing,
+
997  // insert an empty one.
+
998  if (!tx_json.isMember(sfSigningPubKey.getJsonName()))
+
999  tx_json[sfSigningPubKey.getJsonName()] = "";
+
1000  }
+
1001 
+
1002  // When multi-signing, the "Sequence" and "SigningPubKey" fields must
+
1003  // be passed in by the caller.
+
1004  using namespace detail;
+
1005  {
+
1006  Json::Value err = checkMultiSignFields(jvRequest);
+
1007  if (RPC::contains_error(err))
+
1008  return err;
+
1009  }
1010 
-
1011  transactionPreProcessResult preprocResult = transactionPreProcessImpl(
-
1012  jvRequest, role, signForParams, validatedLedgerAge, app);
-
1013 
-
1014  if (!preprocResult.second)
-
1015  return preprocResult.first;
+
1011  // Add and amend fields based on the transaction type.
+
1012  Buffer multiSignature;
+
1013  PublicKey multiSignPubKey;
+
1014  SigningForParams signForParams(
+
1015  *signerAccountID, multiSignPubKey, multiSignature);
1016 
-
1017  {
-
1018  std::shared_ptr<SLE const> account_state =
-
1019  ledger->read(keylet::account(*signerAccountID));
-
1020  // Make sure the account and secret belong together.
-
1021  auto const err =
-
1022  acctMatchesPubKey(account_state, *signerAccountID, multiSignPubKey);
-
1023 
-
1024  if (err != rpcSUCCESS)
-
1025  return rpcError(err);
-
1026  }
-
1027 
-
1028  // Inject the newly generated signature into tx_json.Signers.
-
1029  auto& sttx = preprocResult.second;
-
1030  {
-
1031  // Make the signer object that we'll inject.
-
1032  STObject signer(sfSigner);
-
1033  signer[sfAccount] = *signerAccountID;
-
1034  signer.setFieldVL(sfTxnSignature, multiSignature);
-
1035  signer.setFieldVL(sfSigningPubKey, multiSignPubKey.slice());
-
1036 
-
1037  // If there is not yet a Signers array, make one.
-
1038  if (!sttx->isFieldPresent(sfSigners))
-
1039  sttx->setFieldArray(sfSigners, {});
-
1040 
-
1041  auto& signers = sttx->peekFieldArray(sfSigners);
-
1042  signers.emplace_back(std::move(signer));
-
1043 
-
1044  // The array must be sorted and validated.
-
1045  auto err = sortAndValidateSigners(signers, (*sttx)[sfAccount]);
-
1046  if (RPC::contains_error(err))
-
1047  return err;
-
1048  }
+
1017  transactionPreProcessResult preprocResult = transactionPreProcessImpl(
+
1018  jvRequest, role, signForParams, validatedLedgerAge, app);
+
1019 
+
1020  if (!preprocResult.second)
+
1021  return preprocResult.first;
+
1022 
+
1023  {
+
1024  std::shared_ptr<SLE const> account_state =
+
1025  ledger->read(keylet::account(*signerAccountID));
+
1026  // Make sure the account and secret belong together.
+
1027  auto const err =
+
1028  acctMatchesPubKey(account_state, *signerAccountID, multiSignPubKey);
+
1029 
+
1030  if (err != rpcSUCCESS)
+
1031  return rpcError(err);
+
1032  }
+
1033 
+
1034  // Inject the newly generated signature into tx_json.Signers.
+
1035  auto& sttx = preprocResult.second;
+
1036  {
+
1037  // Make the signer object that we'll inject.
+
1038  STObject signer(sfSigner);
+
1039  signer[sfAccount] = *signerAccountID;
+
1040  signer.setFieldVL(sfTxnSignature, multiSignature);
+
1041  signer.setFieldVL(sfSigningPubKey, multiSignPubKey.slice());
+
1042 
+
1043  // If there is not yet a Signers array, make one.
+
1044  if (!sttx->isFieldPresent(sfSigners))
+
1045  sttx->setFieldArray(sfSigners, {});
+
1046 
+
1047  auto& signers = sttx->peekFieldArray(sfSigners);
+
1048  signers.emplace_back(std::move(signer));
1049 
-
1050  // Make sure the STTx makes a legitimate Transaction.
-
1051  std::pair<Json::Value, Transaction::pointer> txn =
-
1052  transactionConstructImpl(sttx, ledger->rules(), app);
-
1053 
-
1054  if (!txn.second)
-
1055  return txn.first;
-
1056 
-
1057  return transactionFormatResultImpl(txn.second, apiVersion);
-
1058 }
+
1050  // The array must be sorted and validated.
+
1051  auto err = sortAndValidateSigners(signers, (*sttx)[sfAccount]);
+
1052  if (RPC::contains_error(err))
+
1053  return err;
+
1054  }
+
1055 
+
1056  // Make sure the STTx makes a legitimate Transaction.
+
1057  std::pair<Json::Value, Transaction::pointer> txn =
+
1058  transactionConstructImpl(sttx, ledger->rules(), app);
1059 
-
1061 Json::Value
-
1062 transactionSubmitMultiSigned(
-
1063  Json::Value jvRequest,
-
1064  unsigned apiVersion,
-
1065  NetworkOPs::FailHard failType,
-
1066  Role role,
-
1067  std::chrono::seconds validatedLedgerAge,
-
1068  Application& app,
-
1069  ProcessTransactionFn const& processTransaction,
-
1070  RPC::SubmitSync sync)
-
1071 {
-
1072  auto const& ledger = app.openLedger().current();
-
1073  auto j = app.journal("RPCHandler");
-
1074  JLOG(j.debug()) << "transactionSubmitMultiSigned: " << jvRequest;
-
1075 
-
1076  // When multi-signing, the "Sequence" and "SigningPubKey" fields must
-
1077  // be passed in by the caller.
-
1078  using namespace detail;
-
1079  {
-
1080  Json::Value err = checkMultiSignFields(jvRequest);
-
1081  if (RPC::contains_error(err))
-
1082  return err;
-
1083  }
-
1084 
-
1085  Json::Value& tx_json(jvRequest["tx_json"]);
-
1086 
-
1087  auto [txJsonResult, srcAddressID] = checkTxJsonFields(
-
1088  tx_json,
-
1089  role,
-
1090  true,
-
1091  validatedLedgerAge,
-
1092  app.config(),
-
1093  app.getFeeTrack(),
-
1094  getAPIVersionNumber(jvRequest, app.config().BETA_RPC_API));
-
1095 
-
1096  if (RPC::contains_error(txJsonResult))
-
1097  return std::move(txJsonResult);
-
1098 
-
1099  std::shared_ptr<SLE const> sle =
-
1100  ledger->read(keylet::account(srcAddressID));
+
1060  if (!txn.second)
+
1061  return txn.first;
+
1062 
+
1063  return transactionFormatResultImpl(txn.second, apiVersion);
+
1064 }
+
1065 
+
1067 Json::Value
+
1068 transactionSubmitMultiSigned(
+
1069  Json::Value jvRequest,
+
1070  unsigned apiVersion,
+
1071  NetworkOPs::FailHard failType,
+
1072  Role role,
+
1073  std::chrono::seconds validatedLedgerAge,
+
1074  Application& app,
+
1075  ProcessTransactionFn const& processTransaction,
+
1076  RPC::SubmitSync sync)
+
1077 {
+
1078  auto const& ledger = app.openLedger().current();
+
1079  auto j = app.journal("RPCHandler");
+
1080  JLOG(j.debug()) << "transactionSubmitMultiSigned: " << jvRequest;
+
1081 
+
1082  // When multi-signing, the "Sequence" and "SigningPubKey" fields must
+
1083  // be passed in by the caller.
+
1084  using namespace detail;
+
1085  {
+
1086  Json::Value err = checkMultiSignFields(jvRequest);
+
1087  if (RPC::contains_error(err))
+
1088  return err;
+
1089  }
+
1090 
+
1091  Json::Value& tx_json(jvRequest["tx_json"]);
+
1092 
+
1093  auto [txJsonResult, srcAddressID] = checkTxJsonFields(
+
1094  tx_json,
+
1095  role,
+
1096  true,
+
1097  validatedLedgerAge,
+
1098  app.config(),
+
1099  app.getFeeTrack(),
+
1100  getAPIVersionNumber(jvRequest, app.config().BETA_RPC_API));
1101 
-
1102  if (!sle)
-
1103  {
-
1104  // If did not find account, error.
-
1105  JLOG(j.debug())
-
1106  << "transactionSubmitMultiSigned: Failed to find source account "
-
1107  << "in current ledger: " << toBase58(srcAddressID);
-
1108 
-
1109  return rpcError(rpcSRC_ACT_NOT_FOUND);
-
1110  }
-
1111 
-
1112  {
-
1113  Json::Value err = checkFee(
-
1114  jvRequest,
-
1115  role,
-
1116  false,
-
1117  app.config(),
-
1118  app.getFeeTrack(),
-
1119  app.getTxQ(),
-
1120  app);
-
1121 
-
1122  if (RPC::contains_error(err))
-
1123  return err;
-
1124 
-
1125  err = checkPayment(jvRequest, tx_json, srcAddressID, role, app, false);
-
1126 
-
1127  if (RPC::contains_error(err))
-
1128  return err;
-
1129  }
+
1102  if (RPC::contains_error(txJsonResult))
+
1103  return std::move(txJsonResult);
+
1104 
+
1105  std::shared_ptr<SLE const> sle =
+
1106  ledger->read(keylet::account(srcAddressID));
+
1107 
+
1108  if (!sle)
+
1109  {
+
1110  // If did not find account, error.
+
1111  JLOG(j.debug())
+
1112  << "transactionSubmitMultiSigned: Failed to find source account "
+
1113  << "in current ledger: " << toBase58(srcAddressID);
+
1114 
+
1115  return rpcError(rpcSRC_ACT_NOT_FOUND);
+
1116  }
+
1117 
+
1118  {
+
1119  Json::Value err = checkFee(
+
1120  jvRequest,
+
1121  role,
+
1122  false,
+
1123  app.config(),
+
1124  app.getFeeTrack(),
+
1125  app.getTxQ(),
+
1126  app);
+
1127 
+
1128  if (RPC::contains_error(err))
+
1129  return err;
1130 
-
1131  // Grind through the JSON in tx_json to produce a STTx.
-
1132  std::shared_ptr<STTx> stpTrans;
-
1133  {
-
1134  STParsedJSONObject parsedTx_json("tx_json", tx_json);
-
1135  if (!parsedTx_json.object)
-
1136  {
-
1137  Json::Value jvResult;
-
1138  jvResult["error"] = parsedTx_json.error["error"];
-
1139  jvResult["error_code"] = parsedTx_json.error["error_code"];
-
1140  jvResult["error_message"] = parsedTx_json.error["error_message"];
-
1141  return jvResult;
-
1142  }
-
1143  try
-
1144  {
-
1145  stpTrans =
-
1146  std::make_shared<STTx>(std::move(parsedTx_json.object.value()));
-
1147  }
-
1148  catch (STObject::FieldErr& err)
-
1149  {
-
1150  return RPC::make_error(rpcINVALID_PARAMS, err.what());
-
1151  }
-
1152  catch (std::exception& ex)
-
1153  {
-
1154  std::string reason(ex.what());
-
1155  return RPC::make_error(
-
1156  rpcINTERNAL,
-
1157  "Exception while serializing transaction: " + reason);
-
1158  }
-
1159  std::string reason;
-
1160  if (!passesLocalChecks(*stpTrans, reason))
-
1161  return RPC::make_error(rpcINVALID_PARAMS, reason);
-
1162  }
-
1163 
-
1164  // Validate the fields in the serialized transaction.
-
1165  {
-
1166  // We now have the transaction text serialized and in the right format.
-
1167  // Verify the values of select fields.
-
1168  //
-
1169  // The SigningPubKey must be present but empty.
-
1170  if (!stpTrans->getFieldVL(sfSigningPubKey).empty())
-
1171  {
-
1172  std::ostringstream err;
-
1173  err << "Invalid " << sfSigningPubKey.fieldName
-
1174  << " field. Field must be empty when multi-signing.";
-
1175  return RPC::make_error(rpcINVALID_PARAMS, err.str());
-
1176  }
-
1177 
-
1178  // There may not be a TxnSignature field.
-
1179  if (stpTrans->isFieldPresent(sfTxnSignature))
-
1180  return rpcError(rpcSIGNING_MALFORMED);
-
1181 
-
1182  // The Fee field must be in XRP and greater than zero.
-
1183  auto const fee = stpTrans->getFieldAmount(sfFee);
-
1184 
-
1185  if (!isLegalNet(fee))
-
1186  {
-
1187  std::ostringstream err;
-
1188  err << "Invalid " << sfFee.fieldName
-
1189  << " field. Fees must be specified in XRP.";
-
1190  return RPC::make_error(rpcINVALID_PARAMS, err.str());
-
1191  }
-
1192  if (fee <= STAmount{0})
-
1193  {
-
1194  std::ostringstream err;
-
1195  err << "Invalid " << sfFee.fieldName
-
1196  << " field. Fees must be greater than zero.";
-
1197  return RPC::make_error(rpcINVALID_PARAMS, err.str());
-
1198  }
-
1199  }
-
1200 
-
1201  // Verify that the Signers field is present.
-
1202  if (!stpTrans->isFieldPresent(sfSigners))
-
1203  return RPC::missing_field_error("tx_json.Signers");
-
1204 
-
1205  // If the Signers field is present the SField guarantees it to be an array.
-
1206  // Get a reference to the Signers array so we can verify and sort it.
-
1207  auto& signers = stpTrans->peekFieldArray(sfSigners);
-
1208 
-
1209  if (signers.empty())
-
1210  return RPC::make_param_error("tx_json.Signers array may not be empty.");
-
1211 
-
1212  // The Signers array may only contain Signer objects.
-
1213  if (std::find_if_not(
-
1214  signers.begin(), signers.end(), [](STObject const& obj) {
-
1215  return (
-
1216  // A Signer object always contains these fields and no
-
1217  // others.
-
1218  obj.isFieldPresent(sfAccount) &&
-
1219  obj.isFieldPresent(sfSigningPubKey) &&
-
1220  obj.isFieldPresent(sfTxnSignature) && obj.getCount() == 3);
-
1221  }) != signers.end())
-
1222  {
-
1223  return RPC::make_param_error(
-
1224  "Signers array may only contain Signer entries.");
-
1225  }
-
1226 
-
1227  // The array must be sorted and validated.
-
1228  auto err = sortAndValidateSigners(signers, srcAddressID);
-
1229  if (RPC::contains_error(err))
-
1230  return err;
-
1231 
-
1232  // Make sure the SerializedTransaction makes a legitimate Transaction.
-
1233  std::pair<Json::Value, Transaction::pointer> txn =
-
1234  transactionConstructImpl(stpTrans, ledger->rules(), app);
-
1235 
-
1236  if (!txn.second)
-
1237  return txn.first;
-
1238 
-
1239  // Finally, submit the transaction.
-
1240  try
-
1241  {
-
1242  // FIXME: For performance, should use asynch interface
-
1243  processTransaction(txn.second, isUnlimited(role), sync, failType);
-
1244  }
-
1245  catch (std::exception&)
-
1246  {
-
1247  return RPC::make_error(
-
1248  rpcINTERNAL, "Exception occurred during transaction submission.");
-
1249  }
-
1250 
-
1251  return transactionFormatResultImpl(txn.second, apiVersion);
-
1252 }
-
1253 
-
1254 } // namespace RPC
-
1255 } // namespace ripple
+
1131  err = checkPayment(jvRequest, tx_json, srcAddressID, role, app, false);
+
1132 
+
1133  if (RPC::contains_error(err))
+
1134  return err;
+
1135  }
+
1136 
+
1137  // Grind through the JSON in tx_json to produce a STTx.
+
1138  std::shared_ptr<STTx> stpTrans;
+
1139  {
+
1140  STParsedJSONObject parsedTx_json("tx_json", tx_json);
+
1141  if (!parsedTx_json.object)
+
1142  {
+
1143  Json::Value jvResult;
+
1144  jvResult["error"] = parsedTx_json.error["error"];
+
1145  jvResult["error_code"] = parsedTx_json.error["error_code"];
+
1146  jvResult["error_message"] = parsedTx_json.error["error_message"];
+
1147  return jvResult;
+
1148  }
+
1149  try
+
1150  {
+
1151  stpTrans =
+
1152  std::make_shared<STTx>(std::move(parsedTx_json.object.value()));
+
1153  }
+
1154  catch (STObject::FieldErr& err)
+
1155  {
+
1156  return RPC::make_error(rpcINVALID_PARAMS, err.what());
+
1157  }
+
1158  catch (std::exception& ex)
+
1159  {
+
1160  std::string reason(ex.what());
+
1161  return RPC::make_error(
+
1162  rpcINTERNAL,
+
1163  "Exception while serializing transaction: " + reason);
+
1164  }
+
1165  std::string reason;
+
1166  if (!passesLocalChecks(*stpTrans, reason))
+
1167  return RPC::make_error(rpcINVALID_PARAMS, reason);
+
1168  }
+
1169 
+
1170  // Validate the fields in the serialized transaction.
+
1171  {
+
1172  // We now have the transaction text serialized and in the right format.
+
1173  // Verify the values of select fields.
+
1174  //
+
1175  // The SigningPubKey must be present but empty.
+
1176  if (!stpTrans->getFieldVL(sfSigningPubKey).empty())
+
1177  {
+
1178  std::ostringstream err;
+
1179  err << "Invalid " << sfSigningPubKey.fieldName
+
1180  << " field. Field must be empty when multi-signing.";
+
1181  return RPC::make_error(rpcINVALID_PARAMS, err.str());
+
1182  }
+
1183 
+
1184  // There may not be a TxnSignature field.
+
1185  if (stpTrans->isFieldPresent(sfTxnSignature))
+
1186  return rpcError(rpcSIGNING_MALFORMED);
+
1187 
+
1188  // The Fee field must be in XRP and greater than zero.
+
1189  auto const fee = stpTrans->getFieldAmount(sfFee);
+
1190 
+
1191  if (!isLegalNet(fee))
+
1192  {
+
1193  std::ostringstream err;
+
1194  err << "Invalid " << sfFee.fieldName
+
1195  << " field. Fees must be specified in XRP.";
+
1196  return RPC::make_error(rpcINVALID_PARAMS, err.str());
+
1197  }
+
1198  if (fee <= STAmount{0})
+
1199  {
+
1200  std::ostringstream err;
+
1201  err << "Invalid " << sfFee.fieldName
+
1202  << " field. Fees must be greater than zero.";
+
1203  return RPC::make_error(rpcINVALID_PARAMS, err.str());
+
1204  }
+
1205  }
+
1206 
+
1207  // Verify that the Signers field is present.
+
1208  if (!stpTrans->isFieldPresent(sfSigners))
+
1209  return RPC::missing_field_error("tx_json.Signers");
+
1210 
+
1211  // If the Signers field is present the SField guarantees it to be an array.
+
1212  // Get a reference to the Signers array so we can verify and sort it.
+
1213  auto& signers = stpTrans->peekFieldArray(sfSigners);
+
1214 
+
1215  if (signers.empty())
+
1216  return RPC::make_param_error("tx_json.Signers array may not be empty.");
+
1217 
+
1218  // The Signers array may only contain Signer objects.
+
1219  if (std::find_if_not(
+
1220  signers.begin(), signers.end(), [](STObject const& obj) {
+
1221  return (
+
1222  // A Signer object always contains these fields and no
+
1223  // others.
+
1224  obj.isFieldPresent(sfAccount) &&
+
1225  obj.isFieldPresent(sfSigningPubKey) &&
+
1226  obj.isFieldPresent(sfTxnSignature) && obj.getCount() == 3);
+
1227  }) != signers.end())
+
1228  {
+
1229  return RPC::make_param_error(
+
1230  "Signers array may only contain Signer entries.");
+
1231  }
+
1232 
+
1233  // The array must be sorted and validated.
+
1234  auto err = sortAndValidateSigners(signers, srcAddressID);
+
1235  if (RPC::contains_error(err))
+
1236  return err;
+
1237 
+
1238  // Make sure the SerializedTransaction makes a legitimate Transaction.
+
1239  std::pair<Json::Value, Transaction::pointer> txn =
+
1240  transactionConstructImpl(stpTrans, ledger->rules(), app);
+
1241 
+
1242  if (!txn.second)
+
1243  return txn.first;
+
1244 
+
1245  // Finally, submit the transaction.
+
1246  try
+
1247  {
+
1248  // FIXME: For performance, should use asynch interface
+
1249  processTransaction(txn.second, isUnlimited(role), sync, failType);
+
1250  }
+
1251  catch (std::exception&)
+
1252  {
+
1253  return RPC::make_error(
+
1254  rpcINTERNAL, "Exception occurred during transaction submission.");
+
1255  }
+
1256 
+
1257  return transactionFormatResultImpl(txn.second, apiVersion);
+
1258 }
+
1259 
+
1260 } // namespace RPC
+
1261 } // namespace ripple
ripple::JsonOptions::disable_API_prior_V2
@ disable_API_prior_V2
Definition: STBase.h:44
-
ripple::RPC::detail::SigningForParams::multiSigningAcctID_
AccountID const *const multiSigningAcctID_
Definition: TransactionSign.cpp:54
+
ripple::RPC::detail::SigningForParams::multiSigningAcctID_
AccountID const *const multiSigningAcctID_
Definition: TransactionSign.cpp:55
ripple::FeeSetup::reference_fee
XRPAmount reference_fee
The cost of a reference transaction in drops.
Definition: Config.h:75
ripple::Application
Definition: Application.h:116
ripple::Application::checkSigs
virtual bool checkSigs() const =0
@@ -1332,7 +1338,7 @@ $(function() {
ripple::RPC::detail::transactionPreProcessResult::operator=
transactionPreProcessResult & operator=(transactionPreProcessResult const &)=delete
ripple::mulDiv
std::optional< Dest > mulDiv(Source1 value, Dest mul, Source2 div)
Definition: FeeUnits.h:468
ripple::OpenLedger::current
std::shared_ptr< OpenView const > current() const
Returns a view to the current open ledger.
Definition: OpenLedger.cpp:50
-
ripple::RPC::detail::SigningForParams::SigningForParams
SigningForParams()
Definition: TransactionSign.cpp:59
+
ripple::RPC::detail::SigningForParams::SigningForParams
SigningForParams()
Definition: TransactionSign.cpp:60
Json::Value::isObject
bool isObject() const
Definition: json_value.cpp:1027
std::string
STL class.
std::shared_ptr
STL class.
@@ -1340,6 +1346,7 @@ $(function() {
ripple::rpcINVALID_PARAMS
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
ripple::rpcError
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:29
std::exception
STL class.
+
ripple::RPC::insertDeliverMax
void insertDeliverMax(Json::Value &tx_json, TxType txnType, unsigned int apiVersion)
Copy Amount field to DeliverMax field in transaction output JSON.
Definition: DeliverMax.cpp:28
ripple::lsfDisableMaster
@ lsfDisableMaster
Definition: LedgerFormats.h:260
ripple::STAmount::issue
Issue const & issue() const
Definition: STAmount.h:350
ripple::RPC::missing_field_message
std::string missing_field_message(std::string const &name)
Definition: ErrorCodes.h:258
@@ -1347,9 +1354,9 @@ $(function() {
ripple::Slice
An immutable linear range of bytes.
Definition: Slice.h:44
ripple::rpcSRC_ACT_NOT_FOUND
@ rpcSRC_ACT_NOT_FOUND
Definition: ErrorCodes.h:122
std::pair
-
ripple::RPC::detail::SigningForParams::editFields
bool editFields() const
Definition: TransactionSign.cpp:94
+
ripple::RPC::detail::SigningForParams::editFields
bool editFields() const
Definition: TransactionSign.cpp:95
ripple::sfRegularKey
const SF_ACCOUNT sfRegularKey
-
ripple::RPC::detail::SigningForParams::multiSignPublicKey_
PublicKey *const multiSignPublicKey_
Definition: TransactionSign.cpp:55
+
ripple::RPC::detail::SigningForParams::multiSignPublicKey_
PublicKey *const multiSignPublicKey_
Definition: TransactionSign.cpp:56
ripple::verify
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig, bool mustBeFullyCanonical) noexcept
Verify a signature on a message.
Definition: PublicKey.cpp:272
ripple::Pathfinder::computePathRanks
void computePathRanks(int maxPaths, std::function< bool(void)> const &continueCallback={})
Compute the rankings of the paths.
Definition: Pathfinder.cpp:411
ripple::RPC::getAPIVersionNumber
unsigned int getAPIVersionNumber(Json::Value const &jv, bool betaEnabled)
Retrieve the api version number from the json value.
Definition: RPCHelpers.cpp:992
@@ -1358,16 +1365,16 @@ $(function() {
ripple::SField::fieldName
const std::string fieldName
Definition: SField.h:159
ripple::sfSigningPubKey
const SF_VL sfSigningPubKey
ripple::rpcSIGNING_MALFORMED
@ rpcSIGNING_MALFORMED
Definition: ErrorCodes.h:118
-
ripple::RPC::detail::transactionPreProcessResult::second
const std::shared_ptr< STTx > second
Definition: TransactionSign.cpp:355
+
ripple::RPC::detail::transactionPreProcessResult::second
const std::shared_ptr< STTx > second
Definition: TransactionSign.cpp:356
std::chrono::seconds
iterator
ripple::NEW
@ NEW
Definition: Transaction.h:47
ripple::Issue::currency
Currency currency
Definition: Issue.h:38
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:104
ripple::tfFullyCanonicalSig
constexpr std::uint32_t tfFullyCanonicalSig
Transaction flags.
Definition: TxFlags.h:58
-
ripple::RPC::detail::transactionPreProcessResult::first
const Json::Value first
Definition: TransactionSign.cpp:354
+
ripple::RPC::detail::transactionPreProcessResult::first
const Json::Value first
Definition: TransactionSign.cpp:355
std::stringstream
STL class.
-
ripple::RPC::detail::checkPayment
static Json::Value checkPayment(Json::Value const &params, Json::Value &tx_json, AccountID const &srcAddressID, Role const role, Application &app, bool doPath)
Definition: TransactionSign.cpp:158
+
ripple::RPC::detail::checkPayment
static Json::Value checkPayment(Json::Value const &params, Json::Value &tx_json, AccountID const &srcAddressID, Role const role, Application &app, bool doPath)
Definition: TransactionSign.cpp:159
ripple::PublicKey::slice
Slice slice() const noexcept
Definition: PublicKey.h:125
ripple::rpcTOO_BUSY
@ rpcTOO_BUSY
Definition: ErrorCodes.h:56
ripple::Buffer
Like std::vector<char> but better.
Definition: Buffer.h:35
@@ -1383,76 +1390,76 @@ $(function() {
ripple::STParsedJSONObject::object
std::optional< STObject > object
The STObject if the parse was successful.
Definition: STParsedJSON.h:50
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:163
std::sort
T sort(T... args)
-
ripple::RPC::detail::transactionConstructImpl
static std::pair< Json::Value, Transaction::pointer > transactionConstructImpl(std::shared_ptr< STTx const > const &stpTrans, Rules const &rules, Application &app)
Definition: TransactionSign.cpp:570
+
ripple::RPC::detail::transactionConstructImpl
static std::pair< Json::Value, Transaction::pointer > transactionConstructImpl(std::shared_ptr< STTx const > const &stpTrans, Rules const &rules, Application &app)
Definition: TransactionSign.cpp:571
std::shared_ptr::reset
T reset(T... args)
ripple::STPathSet
Definition: STPathSet.h:176
ripple::RPC::object_field_error
Json::Value object_field_error(std::string const &name)
Definition: ErrorCodes.h:282
algorithm
ripple::error_code_i
error_code_i
Definition: ErrorCodes.h:40
-
ripple::RPC::transactionSubmitMultiSigned
Json::Value transactionSubmitMultiSigned(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction, RPC::SubmitSync sync)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:1062
+
ripple::RPC::transactionSubmitMultiSigned
Json::Value transactionSubmitMultiSigned(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction, RPC::SubmitSync sync)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:1068
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::STPathSet::empty
bool empty() const
Definition: STPathSet.h:503
-
ripple::RPC::detail::transactionPreProcessResult::transactionPreProcessResult
transactionPreProcessResult(std::shared_ptr< STTx > &&st)
Definition: TransactionSign.cpp:371
+
ripple::RPC::detail::transactionPreProcessResult::transactionPreProcessResult
transactionPreProcessResult(std::shared_ptr< STTx > &&st)
Definition: TransactionSign.cpp:372
ripple::Application::getFeeTrack
virtual LoadFeeTrack & getFeeTrack()=0
ripple::STParsedJSONObject::error
Json::Value error
On failure, an appropriate set of error values.
Definition: STParsedJSON.h:53
-
ripple::RPC::detail::SigningForParams::setPublicKey
void setPublicKey(PublicKey const &multiSignPublicKey)
Definition: TransactionSign.cpp:107
+
ripple::RPC::detail::SigningForParams::setPublicKey
void setPublicKey(PublicKey const &multiSignPublicKey)
Definition: TransactionSign.cpp:108
Json::Value::asBool
bool asBool() const
Definition: json_value.cpp:619
ripple::temUNCERTAIN
@ temUNCERTAIN
Definition: TER.h:122
ripple::Validity::SigGoodOnly
@ SigGoodOnly
Signature is good, but local checks fail.
-
ripple::RPC::detail::acctMatchesPubKey
static error_code_i acctMatchesPubKey(std::shared_ptr< SLE const > accountState, AccountID const &accountID, PublicKey const &publicKey)
Definition: TransactionSign.cpp:122
+
ripple::RPC::detail::acctMatchesPubKey
static error_code_i acctMatchesPubKey(std::shared_ptr< SLE const > accountState, AccountID const &accountID, PublicKey const &publicKey)
Definition: TransactionSign.cpp:123
ripple::RPC::missing_field_error
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:264
-
ripple::RPC::detail::SigningForParams::getSigner
AccountID const & getSigner()
Definition: TransactionSign.cpp:101
-
ripple::RPC::checkFee
Json::Value checkFee(Json::Value &request, Role const role, bool doAutoFill, Config const &config, LoadFeeTrack const &feeTrack, TxQ const &txQ, Application const &app)
Fill in the fee on behalf of the client.
Definition: TransactionSign.cpp:690
+
ripple::RPC::detail::SigningForParams::getSigner
AccountID const & getSigner()
Definition: TransactionSign.cpp:102
+
ripple::RPC::checkFee
Json::Value checkFee(Json::Value &request, Role const role, bool doAutoFill, Config const &config, LoadFeeTrack const &feeTrack, TxQ const &txQ, Application const &app)
Fill in the fee on behalf of the client.
Definition: TransactionSign.cpp:696
ripple::base_uint< 160, detail::AccountIDTag >
ripple::RPC::keypairForSignature
std::pair< PublicKey, SecretKey > keypairForSignature(Json::Value const &params, Json::Value &error, unsigned int apiVersion)
Definition: RPCHelpers.cpp:796
ripple::RPC::expected_field_message
std::string expected_field_message(std::string const &name, std::string const &type)
Definition: ErrorCodes.h:318
ripple::rpcSUCCESS
@ rpcSUCCESS
Definition: ErrorCodes.h:44
ripple::STObject::FieldErr
Definition: STObject.h:647
ripple::Config::reporting
bool reporting() const
Definition: Config.h:351
-
ripple::RPC::detail::transactionPreProcessImpl
static transactionPreProcessResult transactionPreProcessImpl(Json::Value &params, Role role, SigningForParams &signingArgs, std::chrono::seconds validatedLedgerAge, Application &app)
Definition: TransactionSign.cpp:378
+
ripple::RPC::detail::transactionPreProcessImpl
static transactionPreProcessResult transactionPreProcessImpl(Json::Value &params, Role role, SigningForParams &signingArgs, std::chrono::seconds validatedLedgerAge, Application &app)
Definition: TransactionSign.cpp:379
ripple::TxQ
Transaction Queue.
Definition: TxQ.h:57
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::passesLocalChecks
bool passesLocalChecks(STObject const &st, std::string &reason)
Definition: STTx.cpp:547
ripple::RPC::contains_error
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
Definition: ErrorCodes.cpp:196
-
ripple::RPC::detail::checkTxJsonFields
static std::pair< Json::Value, AccountID > checkTxJsonFields(Json::Value const &tx_json, Role const role, bool const verify, std::chrono::seconds validatedLedgerAge, Config const &config, LoadFeeTrack const &feeTrack, unsigned apiVersion)
Definition: TransactionSign.cpp:284
+
ripple::RPC::detail::checkTxJsonFields
static std::pair< Json::Value, AccountID > checkTxJsonFields(Json::Value const &tx_json, Role const role, bool const verify, std::chrono::seconds validatedLedgerAge, Config const &config, LoadFeeTrack const &feeTrack, unsigned apiVersion)
Definition: TransactionSign.cpp:285
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::PublicKey
A public key.
Definition: PublicKey.h:61
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:142
ripple::Config
Definition: Config.h:92
-
ripple::RPC::transactionSubmit
Json::Value transactionSubmit(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction, RPC::SubmitSync sync)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:824
+
ripple::RPC::transactionSubmit
Json::Value transactionSubmit(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction, RPC::SubmitSync sync)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:830
ripple::rpcSRC_ACT_MISSING
@ rpcSRC_ACT_MISSING
Definition: ErrorCodes.h:121
ripple::Application::config
virtual Config & config()=0
ripple::rpcALREADY_SINGLE_SIG
@ rpcALREADY_SINGLE_SIG
Definition: ErrorCodes.h:92
-
ripple::RPC::detail::sortAndValidateSigners
static Json::Value sortAndValidateSigners(STArray &signers, AccountID const &signingForID)
Definition: TransactionSign.cpp:904
+
ripple::RPC::detail::sortAndValidateSigners
static Json::Value sortAndValidateSigners(STArray &signers, AccountID const &signingForID)
Definition: TransactionSign.cpp:910
ripple::Config::standalone
bool standalone() const
Definition: Config.h:346
ripple::rpcHIGH_FEE
@ rpcHIGH_FEE
Definition: ErrorCodes.h:58
ripple::calcAccountID
AccountID calcAccountID(PublicKey const &pk)
Definition: AccountID.cpp:158
ripple::STArray
Definition: STArray.h:28
ripple::Application::getTxQ
virtual TxQ & getTxQ()=0
ripple::LoadFeeTrack
Manages the current fee schedule.
Definition: LoadFeeTrack.h:44
-
ripple::RPC::transactionSign
Json::Value transactionSign(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:786
+
ripple::RPC::transactionSign
Json::Value transactionSign(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:792
ripple::STAmount
Definition: STAmount.h:46
ripple::Serializer::slice
Slice slice() const noexcept
Definition: Serializer.h:64
ripple::Config::BETA_RPC_API
bool BETA_RPC_API
Definition: Config.h:299
ripple::TxQ::nextQueuableSeq
SeqProxy nextQueuableSeq(std::shared_ptr< SLE const > const &sleAccount) const
Return the next sequence that would go in the TxQ for an account.
Definition: TxQ.cpp:1587
-
ripple::RPC::detail::transactionPreProcessResult
Definition: TransactionSign.cpp:352
+
ripple::RPC::detail::transactionPreProcessResult
Definition: TransactionSign.cpp:353
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:932
ripple::rpcNO_CURRENT
@ rpcNO_CURRENT
Definition: ErrorCodes.h:65
-
ripple::RPC::transactionSignFor
Json::Value transactionSignFor(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:954
+
ripple::RPC::transactionSignFor
Json::Value transactionSignFor(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:960
ripple::feeunit::TaggedFee
Definition: FeeUnits.h:70
ripple::rpcALREADY_MULTISIG
@ rpcALREADY_MULTISIG
Definition: ErrorCodes.h:91
ripple::RPC::SubmitSync::sync
@ sync
ripple::NetworkOPs::FailHard
FailHard
Definition: NetworkOPs.h:95
ripple::sfSigner
const SField sfSigner
ripple::Config::PATH_SEARCH_OLD
int PATH_SEARCH_OLD
Definition: Config.h:205
-
ripple::RPC::detail::transactionFormatResultImpl
static Json::Value transactionFormatResultImpl(Transaction::pointer tpTrans, unsigned apiVersion)
Definition: TransactionSign.cpp:648
+
ripple::RPC::detail::transactionFormatResultImpl
static Json::Value transactionFormatResultImpl(Transaction::pointer tpTrans, unsigned apiVersion)
Definition: TransactionSign.cpp:649
ripple::rpcINTERNAL
@ rpcINTERNAL
Definition: ErrorCodes.h:130
ripple::isUnlimited
bool isUnlimited(Role const &role)
ADMIN and IDENTIFIED roles shall have unlimited resources.
Definition: Role.cpp:124
ripple::Serializer
Definition: Serializer.h:40
std::ostringstream
STL class.
ripple::Pathfinder::getBestPaths
STPathSet getBestPaths(int maxPaths, STPath &fullLiquidityPath, STPathSet const &extraPaths, AccountID const &srcIssuer, std::function< bool(void)> const &continueCallback={})
Definition: Pathfinder.cpp:567
-
ripple::RPC::detail::transactionPreProcessResult::transactionPreProcessResult
transactionPreProcessResult(Json::Value &&json)
Definition: TransactionSign.cpp:366
+
ripple::RPC::detail::transactionPreProcessResult::transactionPreProcessResult
transactionPreProcessResult(Json::Value &&json)
Definition: TransactionSign.cpp:367
ripple::RPC::invalid_field_message
std::string invalid_field_message(std::string const &name)
Definition: ErrorCodes.h:294
ripple::STObject
Definition: STObject.h:53
ripple::sfTxnSignature
const SF_VL sfTxnSignature
@@ -1467,20 +1474,20 @@ $(function() {
Json::Value::removeMember
Value removeMember(const char *key)
Remove and return the named member.
Definition: json_value.cpp:907
ripple::Validity::Valid
@ Valid
Signature and local checks are good / passed.
ripple::sign
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &m)
Generate a signature for a message.
Definition: SecretKey.cpp:238
-
ripple::RPC::detail::SigningForParams::multiSignature_
Buffer *const multiSignature_
Definition: TransactionSign.cpp:56
-
ripple::RPC::detail::SigningForParams::moveMultiSignature
void moveMultiSignature(Buffer &&multiSignature)
Definition: TransactionSign.cpp:113
+
ripple::RPC::detail::SigningForParams::multiSignature_
Buffer *const multiSignature_
Definition: TransactionSign.cpp:57
+
ripple::RPC::detail::SigningForParams::moveMultiSignature
void moveMultiSignature(Buffer &&multiSignature)
Definition: TransactionSign.cpp:114
std
STL namespace.
ripple::LoadFeeTrack::isLoadedCluster
bool isLoadedCluster() const
Definition: LoadFeeTrack.h:133
ripple::STPathSet::getJson
Json::Value getJson(JsonOptions) const override
Definition: STPathSet.cpp:193
-
ripple::RPC::detail::SigningForParams::isSingleSigning
bool isSingleSigning() const
Definition: TransactionSign.cpp:87
+
ripple::RPC::detail::SigningForParams::isSingleSigning
bool isSingleSigning() const
Definition: TransactionSign.cpp:88
std::adjacent_find
T adjacent_find(T... args)
-
ripple::RPC::detail::SigningForParams::isMultiSigning
bool isMultiSigning() const
Definition: TransactionSign.cpp:79
+
ripple::RPC::detail::SigningForParams::isMultiSigning
bool isMultiSigning() const
Definition: TransactionSign.cpp:80
ripple::LedgerMaster::getValidatedLedger
std::shared_ptr< Ledger const > getValidatedLedger()
Definition: LedgerMaster.cpp:1717
std::string::empty
T empty(T... args)
ripple::Rules
Rules controlling protocol behavior.
Definition: Rules.h:33
-
ripple::RPC::detail::checkMultiSignFields
static Json::Value checkMultiSignFields(Json::Value const &jvRequest)
Definition: TransactionSign.cpp:873
+
ripple::RPC::detail::checkMultiSignFields
static Json::Value checkMultiSignFields(Json::Value const &jvRequest)
Definition: TransactionSign.cpp:879
std::stringstream::str
T str(T... args)
-
ripple::RPC::detail::SigningForParams::SigningForParams
SigningForParams(AccountID const &multiSigningAcctID, PublicKey &multiSignPublicKey, Buffer &multiSignature)
Definition: TransactionSign.cpp:68
+
ripple::RPC::detail::SigningForParams::SigningForParams
SigningForParams(AccountID const &multiSigningAcctID, PublicKey &multiSignPublicKey, Buffer &multiSignature)
Definition: TransactionSign.cpp:69
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::scaleFeeLoad
XRPAmount scaleFeeLoad(XRPAmount fee, LoadFeeTrack const &feeTrack, Fees const &fees, bool bUnlimited)
Definition: LoadFeeTrack.cpp:89
ripple::sfFee
const SF_AMOUNT sfFee
@@ -1491,7 +1498,7 @@ $(function() {
std::max
T max(T... args)
ripple::TxQ::getMetrics
Metrics getMetrics(OpenView const &view) const
Returns fee metrics in reference fee level units.
Definition: TxQ.cpp:1748
ripple::RPC::make_param_error
Json::Value make_param_error(std::string const &message)
Returns a new json object that indicates invalid parameters.
Definition: ErrorCodes.h:252
-
ripple::RPC::detail::SigningForParams
Definition: TransactionSign.cpp:51
+
ripple::RPC::detail::SigningForParams
Definition: TransactionSign.cpp:52
ripple::rpcBAD_SECRET
@ rpcBAD_SECRET
Definition: ErrorCodes.h:98
ripple::RPC::Tuning::defaultAutoFillFeeMultiplier
static constexpr int defaultAutoFillFeeMultiplier
Definition: rpc/impl/Tuning.h:60
ripple::STPath
Definition: STPathSet.h:118
diff --git a/TransactionSign_8h_source.html b/TransactionSign_8h_source.html index da59d24e87..e246d3be85 100644 --- a/TransactionSign_8h_source.html +++ b/TransactionSign_8h_source.html @@ -188,12 +188,12 @@ $(function() {
std::chrono::seconds
ripple::NetworkOPs::processTransaction
virtual void processTransaction(std::shared_ptr< Transaction > &transaction, bool bUnlimited, RPC::SubmitSync sync, bool bLocal, FailHard failType)=0
Process a transaction.
std::function
-
ripple::RPC::transactionSubmitMultiSigned
Json::Value transactionSubmitMultiSigned(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction, RPC::SubmitSync sync)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:1062
-
ripple::RPC::checkFee
Json::Value checkFee(Json::Value &request, Role const role, bool doAutoFill, Config const &config, LoadFeeTrack const &feeTrack, TxQ const &txQ, Application const &app)
Fill in the fee on behalf of the client.
Definition: TransactionSign.cpp:690
+
ripple::RPC::transactionSubmitMultiSigned
Json::Value transactionSubmitMultiSigned(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction, RPC::SubmitSync sync)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:1068
+
ripple::RPC::checkFee
Json::Value checkFee(Json::Value &request, Role const role, bool doAutoFill, Config const &config, LoadFeeTrack const &feeTrack, TxQ const &txQ, Application const &app)
Fill in the fee on behalf of the client.
Definition: TransactionSign.cpp:696
ripple::RPC::getProcessTxnFn
ProcessTransactionFn getProcessTxnFn(NetworkOPs &netOPs)
Definition: TransactionSign.h:83
-
ripple::RPC::transactionSubmit
Json::Value transactionSubmit(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction, RPC::SubmitSync sync)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:824
-
ripple::RPC::transactionSign
Json::Value transactionSign(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:786
-
ripple::RPC::transactionSignFor
Json::Value transactionSignFor(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:954
+
ripple::RPC::transactionSubmit
Json::Value transactionSubmit(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction, RPC::SubmitSync sync)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:830
+
ripple::RPC::transactionSign
Json::Value transactionSign(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:792
+
ripple::RPC::transactionSignFor
Json::Value transactionSignFor(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
Definition: TransactionSign.cpp:960
ripple::RPC::SubmitSync::sync
@ sync
ripple::NetworkOPs::FailHard
FailHard
Definition: NetworkOPs.h:95
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
diff --git a/classripple_1_1RPC_1_1detail_1_1SigningForParams.html b/classripple_1_1RPC_1_1detail_1_1SigningForParams.html index 728e6b933f..28c8337570 100644 --- a/classripple_1_1RPC_1_1detail_1_1SigningForParams.html +++ b/classripple_1_1RPC_1_1detail_1_1SigningForParams.html @@ -122,7 +122,7 @@ Private Attributes

Detailed Description

-

Definition at line 51 of file TransactionSign.cpp.

+

Definition at line 52 of file TransactionSign.cpp.

Constructor & Destructor Documentation

◆ SigningForParams() [1/3]

@@ -147,7 +147,7 @@ Private Attributes
-

Definition at line 59 of file TransactionSign.cpp.

+

Definition at line 60 of file TransactionSign.cpp.

@@ -209,7 +209,7 @@ Private Attributes
-

Definition at line 68 of file TransactionSign.cpp.

+

Definition at line 69 of file TransactionSign.cpp.

@@ -229,7 +229,7 @@ Private Attributes
-

Definition at line 79 of file TransactionSign.cpp.

+

Definition at line 80 of file TransactionSign.cpp.

@@ -248,7 +248,7 @@ Private Attributes
-

Definition at line 87 of file TransactionSign.cpp.

+

Definition at line 88 of file TransactionSign.cpp.

@@ -267,7 +267,7 @@ Private Attributes
-

Definition at line 94 of file TransactionSign.cpp.

+

Definition at line 95 of file TransactionSign.cpp.

@@ -286,7 +286,7 @@ Private Attributes
-

Definition at line 101 of file TransactionSign.cpp.

+

Definition at line 102 of file TransactionSign.cpp.

@@ -306,7 +306,7 @@ Private Attributes
-

Definition at line 107 of file TransactionSign.cpp.

+

Definition at line 108 of file TransactionSign.cpp.

@@ -326,7 +326,7 @@ Private Attributes
-

Definition at line 113 of file TransactionSign.cpp.

+

Definition at line 114 of file TransactionSign.cpp.

@@ -351,7 +351,7 @@ Private Attributes
-

Definition at line 54 of file TransactionSign.cpp.

+

Definition at line 55 of file TransactionSign.cpp.

@@ -375,7 +375,7 @@ Private Attributes
-

Definition at line 55 of file TransactionSign.cpp.

+

Definition at line 56 of file TransactionSign.cpp.

@@ -399,7 +399,7 @@ Private Attributes
-

Definition at line 56 of file TransactionSign.cpp.

+

Definition at line 57 of file TransactionSign.cpp.

diff --git a/namespaceripple_1_1RPC.html b/namespaceripple_1_1RPC.html index fce382f0e9..9a1083e392 100644 --- a/namespaceripple_1_1RPC.html +++ b/namespaceripple_1_1RPC.html @@ -2918,7 +2918,7 @@ template<class Object >
Returns
A JSON object containing the error results, if any
-

Definition at line 690 of file TransactionSign.cpp.

+

Definition at line 696 of file TransactionSign.cpp.

@@ -2974,7 +2974,7 @@ template<class Object >

Returns a Json::objectValue.

-

Definition at line 786 of file TransactionSign.cpp.

+

Definition at line 792 of file TransactionSign.cpp.

@@ -3042,7 +3042,7 @@ template<class Object >

Returns a Json::objectValue.

-

Definition at line 824 of file TransactionSign.cpp.

+

Definition at line 830 of file TransactionSign.cpp.

@@ -3098,7 +3098,7 @@ template<class Object >

Returns a Json::objectValue.

-

Definition at line 954 of file TransactionSign.cpp.

+

Definition at line 960 of file TransactionSign.cpp.

@@ -3166,7 +3166,7 @@ template<class Object >

Returns a Json::objectValue.

-

Definition at line 1062 of file TransactionSign.cpp.

+

Definition at line 1068 of file TransactionSign.cpp.

diff --git a/namespaceripple_1_1RPC_1_1detail.html b/namespaceripple_1_1RPC_1_1detail.html index e1fe25d8ec..681f26e1e1 100644 --- a/namespaceripple_1_1RPC_1_1detail.html +++ b/namespaceripple_1_1RPC_1_1detail.html @@ -184,7 +184,7 @@ template<int M, int N>
-

Definition at line 122 of file TransactionSign.cpp.

+

Definition at line 123 of file TransactionSign.cpp.

@@ -246,7 +246,7 @@ template<int M, int N>
-

Definition at line 158 of file TransactionSign.cpp.

+

Definition at line 159 of file TransactionSign.cpp.

@@ -314,7 +314,7 @@ template<int M, int N>
-

Definition at line 284 of file TransactionSign.cpp.

+

Definition at line 285 of file TransactionSign.cpp.

@@ -370,7 +370,7 @@ template<int M, int N>
-

Definition at line 378 of file TransactionSign.cpp.

+

Definition at line 379 of file TransactionSign.cpp.

@@ -414,7 +414,7 @@ template<int M, int N>
-

Definition at line 570 of file TransactionSign.cpp.

+

Definition at line 571 of file TransactionSign.cpp.

@@ -452,7 +452,7 @@ template<int M, int N>
-

Definition at line 648 of file TransactionSign.cpp.

+

Definition at line 649 of file TransactionSign.cpp.

@@ -480,7 +480,7 @@ template<int M, int N>
-

Definition at line 873 of file TransactionSign.cpp.

+

Definition at line 879 of file TransactionSign.cpp.

@@ -518,7 +518,7 @@ template<int M, int N>
-

Definition at line 904 of file TransactionSign.cpp.

+

Definition at line 910 of file TransactionSign.cpp.

diff --git a/structripple_1_1RPC_1_1detail_1_1transactionPreProcessResult.html b/structripple_1_1RPC_1_1detail_1_1transactionPreProcessResult.html index cc3f979765..2425f4ac86 100644 --- a/structripple_1_1RPC_1_1detail_1_1transactionPreProcessResult.html +++ b/structripple_1_1RPC_1_1detail_1_1transactionPreProcessResult.html @@ -135,7 +135,7 @@ Public Attributes

Detailed Description

-

Definition at line 352 of file TransactionSign.cpp.

+

Definition at line 353 of file TransactionSign.cpp.

Constructor & Destructor Documentation

◆ transactionPreProcessResult() [1/5]

@@ -230,7 +230,7 @@ Public Attributes
-

Definition at line 366 of file TransactionSign.cpp.

+

Definition at line 367 of file TransactionSign.cpp.

@@ -258,7 +258,7 @@ Public Attributes
-

Definition at line 371 of file TransactionSign.cpp.

+

Definition at line 372 of file TransactionSign.cpp.

@@ -328,7 +328,7 @@ Public Attributes
-

Definition at line 354 of file TransactionSign.cpp.

+

Definition at line 355 of file TransactionSign.cpp.

@@ -344,7 +344,7 @@ Public Attributes
-

Definition at line 355 of file TransactionSign.cpp.

+

Definition at line 356 of file TransactionSign.cpp.