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/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>
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>
129 bool const isMasterKey = publicKeyAcctID == accountID;
141 auto const& sle = *accountState;
168 if (tx_json[jss::TransactionType].asString() != jss::Payment)
172 if (tx_json.
isMember(jss::DeliverMax))
176 if (tx_json[jss::DeliverMax] != tx_json[jss::Amount])
179 "Cannot specify differing 'Amount' and 'DeliverMax'");
182 tx_json[jss::Amount] = tx_json[jss::DeliverMax];
195 if (!tx_json.
isMember(jss::Destination))
198 auto const dstAccountID =
199 parseBase58<AccountID>(tx_json[jss::Destination].asString());
203 if ((doPath ==
false) && params.
isMember(jss::build_path))
206 "Field 'build_path' not allowed in this context.");
211 "Cannot specify both 'tx_json.Paths' and 'build_path'");
243 std::make_shared<RippleLineCache>(
244 ledger, app.
journal(
"RippleLineCache")),
263 auto j = app.
journal(
"RPCHandler");
264 JLOG(j.debug()) <<
"transactionSign: build_path: "
302 if (!tx_json.
isMember(jss::TransactionType))
308 if (!tx_json.
isMember(jss::Account))
315 auto const srcAddressID =
316 parseBase58<AccountID>(tx_json[jss::Account].asString());
345 ret.
second = *srcAddressID;
378 static transactionPreProcessResult
386 auto j = app.
journal(
"RPCHandler");
394 !(params.
isMember(jss::offline) && params[jss::offline].
asBool());
412 return std::move(txJsonResult);
427 JLOG(j.debug()) <<
"transactionSign: Failed to find source account "
428 <<
"in current ledger: " <<
toBase58(srcAddressID);
460 if (!tx_json.
isMember(jss::Sequence))
462 bool const hasTicketSeq =
464 if (!hasTicketSeq && !sle)
467 <<
"transactionSign: Failed to find source account "
468 <<
"in current ledger: " <<
toBase58(srcAddressID);
472 tx_json[jss::Sequence] =
517 if (!parsed.
object.has_value())
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];
531 parsed.
object->setFieldVL(
535 stpTrans = std::make_shared<STTx>(std::move(parsed.
object.value()));
545 "Exception occurred constructing serialized transaction");
564 stpTrans->sign(pk, sk);
582 tpTrans = std::make_shared<Transaction>(stpTrans, reason, app);
583 if (tpTrans->getStatus() !=
NEW)
586 rpcINTERNAL,
"Unable to construct transaction: " + reason);
598 tpTrans->getSTransaction()->add(s);
603 auto sttxNew = std::make_shared<STTx const>(sit);
607 sttxNew->getTransactionID(),
619 std::make_shared<Transaction>(sttxNew, reason, app);
623 if (!tpTransNew->getSTransaction()->isEquivalent(
624 *tpTrans->getSTransaction()))
628 tpTrans = std::move(tpTransNew);
644 ret.
second = std::move(tpTrans);
656 jvResult[jss::tx_json] =
658 jvResult[jss::hash] =
to_string(tpTrans->getID());
664 jvResult[jss::tx_json],
665 tpTrans->getSTransaction()->getTxnType(),
668 jvResult[jss::tx_blob] =
669 strHex(tpTrans->getSTransaction()->getSerializer().peekData());
678 jvResult[jss::engine_result] = sToken;
679 jvResult[jss::engine_result_code] = tpTrans->getResult();
680 jvResult[jss::engine_result_message] = sHuman;
686 rpcINTERNAL,
"Exception occurred during JSON handling.");
714 if (request.
isMember(jss::fee_mult_max))
716 if (request[jss::fee_mult_max].isInt())
718 mult = request[jss::fee_mult_max].
asInt();
723 jss::fee_mult_max,
"a positive integer"));
730 jss::fee_mult_max,
"a positive integer"));
733 if (request.
isMember(jss::fee_div_max))
735 if (request[jss::fee_div_max].isInt())
737 div = request[jss::fee_div_max].
asInt();
742 jss::fee_div_max,
"a positive integer"));
749 jss::fee_div_max,
"a positive integer"));
762 auto const baseFee = ledger->fees().base;
768 auto const limit = [&]() {
770 auto const result =
mulDiv(feeDefault, mult, div);
772 Throw<std::overflow_error>(
"mulDiv");
779 ss <<
"Fee of " << fee <<
" exceeds the requested tx limit of "
800 using namespace detail;
802 auto j = app.
journal(
"RPCHandler");
803 JLOG(j.debug()) <<
"transactionSign: " << jvRequest;
806 SigningForParams signForParams;
808 jvRequest, role, signForParams, validatedLedgerAge, app);
810 if (!preprocResult.second)
811 return preprocResult.first;
839 using namespace detail;
842 auto j = app.
journal(
"RPCHandler");
843 JLOG(j.debug()) <<
"transactionSubmit: " << jvRequest;
846 SigningForParams signForParams;
848 jvRequest, role, signForParams, validatedLedgerAge, app);
850 if (!preprocResult.second)
851 return preprocResult.first;
869 rpcINTERNAL,
"Exception occurred during transaction submission.");
881 if (!jvRequest.
isMember(jss::tx_json))
884 Json::Value const& tx_json(jvRequest[jss::tx_json]);
892 if (!tx_json.
isMember(jss::Sequence))
901 "When multi-signing 'tx_json.SigningPubKey' must be empty.");
920 return (a[sfAccount] < b[sfAccount]);
928 return (a[sfAccount] == b[sfAccount]);
931 if (dupIter != signers.end())
934 err <<
"Duplicate Signers:Signer:Account entries ("
944 [&signingForID](
STObject const& elem) {
945 return elem[sfAccount] == signingForID;
949 err <<
"A Signer may not be the transaction's Account ("
969 auto j = app.
journal(
"RPCHandler");
970 JLOG(j.debug()) <<
"transactionSignFor: " << jvRequest;
973 const char accountField[] =
"account";
975 if (!jvRequest.
isMember(accountField))
979 auto const signerAccountID =
980 parseBase58<AccountID>(jvRequest[accountField].asString());
981 if (!signerAccountID)
987 if (!jvRequest.
isMember(jss::tx_json))
1004 using namespace detail;
1014 SigningForParams signForParams(
1015 *signerAccountID, multiSignPubKey, multiSignature);
1018 jvRequest, role, signForParams, validatedLedgerAge, app);
1020 if (!preprocResult.second)
1021 return preprocResult.first;
1035 auto& sttx = preprocResult.second;
1047 auto& signers = sttx->peekFieldArray(
sfSigners);
1048 signers.emplace_back(std::move(signer));
1070 unsigned apiVersion,
1078 auto j = app.
journal(
"RPCHandler");
1079 JLOG(j.debug()) <<
"transactionSubmitMultiSigned: " << jvRequest;
1083 using namespace detail;
1102 return std::move(txJsonResult);
1111 <<
"transactionSubmitMultiSigned: Failed to find source account "
1112 <<
"in current ledger: " <<
toBase58(srcAddressID);
1130 err =
checkPayment(jvRequest, tx_json, srcAddressID, role, app,
false);
1140 if (!parsedTx_json.
object)
1143 jvResult[
"error"] = parsedTx_json.
error[
"error"];
1144 jvResult[
"error_code"] = parsedTx_json.
error[
"error_code"];
1145 jvResult[
"error_message"] = parsedTx_json.
error[
"error_message"];
1151 std::make_shared<STTx>(std::move(parsedTx_json.
object.value()));
1162 "Exception while serializing transaction: " + reason);
1179 <<
" field. Field must be empty when multi-signing.";
1188 auto const fee = stpTrans->getFieldAmount(
sfFee);
1194 <<
" field. Fees must be specified in XRP.";
1201 <<
" field. Fees must be greater than zero.";
1207 if (!stpTrans->isFieldPresent(
sfSigners))
1212 auto& signers = stpTrans->peekFieldArray(
sfSigners);
1214 if (signers.empty())
1219 signers.begin(), signers.end(), [](
STObject const& obj) {
1223 obj.isFieldPresent(sfAccount) &&
1224 obj.isFieldPresent(sfSigningPubKey) &&
1225 obj.isFieldPresent(sfTxnSignature) && obj.getCount() == 3);
1226 }) != signers.end())
1229 "Signers array may only contain Signer entries.");
1253 rpcINTERNAL,
"Exception occurred during transaction submission.");
AccountID const *const multiSigningAcctID_
XRPAmount reference_fee
The cost of a reference transaction in drops.
virtual bool checkSigs() const =0
bool amountFromJsonNoThrow(STAmount &result, Json::Value const &jvSource)
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
transactionPreProcessResult & operator=(transactionPreProcessResult const &)=delete
std::optional< Dest > mulDiv(Source1 value, Dest mul, Source2 div)
std::shared_ptr< OpenView const > current() const
Returns a view to the current open ledger.
Json::Value rpcError(int iError)
void insertDeliverMax(Json::Value &tx_json, TxType txnType, unsigned int apiVersion)
Copy Amount field to DeliverMax field in transaction output JSON.
Issue const & issue() const
std::string missing_field_message(std::string const &name)
Calculates payment paths.
An immutable linear range of bytes.
const SF_ACCOUNT sfRegularKey
PublicKey *const multiSignPublicKey_
bool verify(PublicKey const &publicKey, Slice const &m, Slice const &sig, bool mustBeFullyCanonical) noexcept
Verify a signature on a message.
void computePathRanks(int maxPaths, std::function< bool(void)> const &continueCallback={})
Compute the rankings of the paths.
unsigned int getAPIVersionNumber(Json::Value const &jv, bool betaEnabled)
Retrieve the api version number from the json value.
const std::string fieldName
const SF_VL sfSigningPubKey
const std::shared_ptr< STTx > second
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
constexpr std::uint32_t tfFullyCanonicalSig
Transaction flags.
static Json::Value checkPayment(Json::Value const ¶ms, Json::Value &tx_json, AccountID const &srcAddressID, Role const role, Application &app, bool doPath)
Slice slice() const noexcept
Like std::vector<char> but better.
Holds the serialized result of parsing an input JSON object.
const SF_UINT32 sfTicketSequence
bool isLegalNet(STAmount const &value)
bool findPaths(int searchLevel, std::function< bool(void)> const &continueCallback={})
void setFieldVL(SField const &field, Blob const &)
void setIssuer(AccountID const &uIssuer)
Json::StaticString const & getJsonName() const
virtual OpenLedger & openLedger()=0
std::optional< STObject > object
The STObject if the parse was successful.
const Json::StaticString jsonName
static std::pair< Json::Value, Transaction::pointer > transactionConstructImpl(std::shared_ptr< STTx const > const &stpTrans, Rules const &rules, Application &app)
Json::Value object_field_error(std::string const &name)
void forceValidity(HashRouter &router, uint256 const &txid, Validity validity)
Sets the validity of a given transaction in the cache.
transactionPreProcessResult(std::shared_ptr< STTx > &&st)
virtual LoadFeeTrack & getFeeTrack()=0
Json::Value error
On failure, an appropriate set of error values.
void setPublicKey(PublicKey const &multiSignPublicKey)
@ SigGoodOnly
Signature is good, but local checks fail.
static error_code_i acctMatchesPubKey(std::shared_ptr< SLE const > accountState, AccountID const &accountID, PublicKey const &publicKey)
Json::Value missing_field_error(std::string const &name)
AccountID const & getSigner()
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.
std::pair< PublicKey, SecretKey > keypairForSignature(Json::Value const ¶ms, Json::Value &error, unsigned int apiVersion)
std::string expected_field_message(std::string const &name, std::string const &type)
static transactionPreProcessResult transactionPreProcessImpl(Json::Value ¶ms, Role role, SigningForParams &signingArgs, std::chrono::seconds validatedLedgerAge, Application &app)
std::pair< Validity, std::string > checkValidity(HashRouter &router, STTx const &tx, Rules const &rules, Config const &config)
Checks transaction signature and local checks.
bool passesLocalChecks(STObject const &st, std::string &reason)
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
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)
virtual LedgerMaster & getLedgerMaster()=0
Keylet account(AccountID const &id) noexcept
AccountID root.
virtual Config & config()=0
static Json::Value sortAndValidateSigners(STArray &signers, AccountID const &signingForID)
AccountID calcAccountID(PublicKey const &pk)
Manages the current fee schedule.
Json::Value transactionSign(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
Slice slice() const noexcept
SeqProxy nextQueuableSeq(std::shared_ptr< SLE const > const &sleAccount) const
Return the next sequence that would go in the TxQ for an account.
bool isMember(const char *key) const
Return true if the object has a member named key.
Json::Value transactionSubmit(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction)
Returns a Json::objectValue.
Json::Value transactionSignFor(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app)
Returns a Json::objectValue.
static Json::Value transactionFormatResultImpl(Transaction::pointer tpTrans, unsigned apiVersion)
bool isUnlimited(Role const &role)
ADMIN and IDENTIFIED roles shall have unlimited resources.
STPathSet getBestPaths(int maxPaths, STPath &fullLiquidityPath, STPathSet const &extraPaths, AccountID const &srcIssuer, std::function< bool(void)> const &continueCallback={})
transactionPreProcessResult(Json::Value &&json)
std::string invalid_field_message(std::string const &name)
const SF_VL sfTxnSignature
constexpr std::uint32_t value() const
bool native() const noexcept
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
bool transResultInfo(TER code, std::string &token, std::string &text)
virtual beast::Journal journal(std::string const &name)=0
Value removeMember(const char *key)
Remove and return the named member.
@ Valid
Signature and local checks are good / passed.
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &m)
Generate a signature for a message.
Buffer *const multiSignature_
void moveMultiSignature(Buffer &&multiSignature)
bool isLoadedCluster() const
Json::Value getJson(JsonOptions) const override
bool isSingleSigning() const
Json::Value transactionSubmitMultiSigned(Json::Value jvRequest, unsigned apiVersion, NetworkOPs::FailHard failType, Role role, std::chrono::seconds validatedLedgerAge, Application &app, ProcessTransactionFn const &processTransaction)
Returns a Json::objectValue.
T adjacent_find(T... args)
bool isMultiSigning() const
std::shared_ptr< Ledger const > getValidatedLedger()
Rules controlling protocol behavior.
static Json::Value checkMultiSignFields(Json::Value const &jvRequest)
SigningForParams(AccountID const &multiSigningAcctID, PublicKey &multiSignPublicKey, Buffer &multiSignature)
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
XRPAmount scaleFeeLoad(XRPAmount fee, LoadFeeTrack const &feeTrack, Fees const &fees, bool bUnlimited)
const SF_ACCOUNT sfAccount
std::string strHex(FwdIt begin, FwdIt end)
Metrics getMetrics(OpenView const &view) const
Returns fee metrics in reference fee level units.
Json::Value make_param_error(std::string const &message)
Returns a new json object that indicates invalid parameters.
static constexpr int defaultAutoFillFeeMultiplier
Json::Value invalid_field_error(std::string const &name)
virtual HashRouter & getHashRouter()=0
XRPAmount toDrops(FeeLevel< T > const &level, XRPAmount baseFee)
static constexpr int defaultAutoFillFeeDivisor
Role
Indicates the level of administrative permission to grant.
Json::Value make_error(error_code_i code)
Returns a new json object that reflects the error code.
constexpr auto maxValidatedLedgerAge
Json::Value jsonClipped() const
Serializer buildMultiSigningData(STObject const &obj, AccountID const &signingID)
Return a Serializer suitable for computing a multisigning TxnSignature.
transactionPreProcessResult()=delete
std::string asString() const
Returns the unquoted string value.