mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-16 00:55:49 +00:00
Remove TxnSignApiFacade (RIPD-945):
Replace TxnSignApiFacade with separate passed in arguments to the various sign/submit RPC commands. Also increase unit test coverage of the submit_multisign RPC command.
This commit is contained in:
committed by
Edward Hennis
parent
9b787434c9
commit
eed1a891a7
@@ -18,8 +18,8 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <BeastConfig.h>
|
#include <BeastConfig.h>
|
||||||
#include <ripple/app/main/Application.h>
|
|
||||||
#include <ripple/app/ledger/LedgerMaster.h>
|
#include <ripple/app/ledger/LedgerMaster.h>
|
||||||
|
#include <ripple/protocol/ErrorCodes.h>
|
||||||
#include <ripple/protocol/Feature.h>
|
#include <ripple/protocol/Feature.h>
|
||||||
#include <ripple/resource/Fees.h>
|
#include <ripple/resource/Fees.h>
|
||||||
#include <ripple/rpc/Context.h>
|
#include <ripple/rpc/Context.h>
|
||||||
@@ -46,7 +46,12 @@ Json::Value doSignFor (RPC::Context& context)
|
|||||||
auto const failType = NetworkOPs::doFailHard (failHard);
|
auto const failType = NetworkOPs::doFailHard (failHard);
|
||||||
|
|
||||||
return RPC::transactionSignFor (
|
return RPC::transactionSignFor (
|
||||||
context.params, failType, context.netOps, context.role);
|
context.params,
|
||||||
|
failType,
|
||||||
|
context.role,
|
||||||
|
context.ledgerMaster.getValidatedLedgerAge(),
|
||||||
|
context.app.getFeeTrack(),
|
||||||
|
context.ledgerMaster.getCurrentLedger());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|||||||
@@ -18,11 +18,8 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <BeastConfig.h>
|
#include <BeastConfig.h>
|
||||||
#include <ripple/app/misc/NetworkOPs.h>
|
#include <ripple/app/ledger/LedgerMaster.h>
|
||||||
#include <ripple/json/json_value.h>
|
|
||||||
#include <ripple/net/RPCErr.h>
|
|
||||||
#include <ripple/protocol/ErrorCodes.h>
|
#include <ripple/protocol/ErrorCodes.h>
|
||||||
#include <ripple/protocol/JsonFields.h>
|
|
||||||
#include <ripple/resource/Fees.h>
|
#include <ripple/resource/Fees.h>
|
||||||
#include <ripple/rpc/Context.h>
|
#include <ripple/rpc/Context.h>
|
||||||
#include <ripple/rpc/impl/TransactionSign.h>
|
#include <ripple/rpc/impl/TransactionSign.h>
|
||||||
@@ -42,7 +39,12 @@ Json::Value doSign (RPC::Context& context)
|
|||||||
&& context.params[jss::fail_hard].asBool ());
|
&& context.params[jss::fail_hard].asBool ());
|
||||||
|
|
||||||
return RPC::transactionSign (
|
return RPC::transactionSign (
|
||||||
context.params, failType, context.netOps, context.role);
|
context.params,
|
||||||
|
failType,
|
||||||
|
context.role,
|
||||||
|
context.ledgerMaster.getValidatedLedgerAge(),
|
||||||
|
context.app.getFeeTrack(),
|
||||||
|
context.ledgerMaster.getCurrentLedger());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|||||||
@@ -18,18 +18,13 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <BeastConfig.h>
|
#include <BeastConfig.h>
|
||||||
#include <ripple/app/main/Application.h>
|
#include <ripple/app/ledger/LedgerMaster.h>
|
||||||
#include <ripple/app/misc/NetworkOPs.h>
|
|
||||||
#include <ripple/app/misc/HashRouter.h>
|
#include <ripple/app/misc/HashRouter.h>
|
||||||
#include <ripple/basics/StringUtilities.h>
|
|
||||||
#include <ripple/basics/strHex.h>
|
|
||||||
#include <ripple/net/RPCErr.h>
|
#include <ripple/net/RPCErr.h>
|
||||||
#include <ripple/protocol/ErrorCodes.h>
|
#include <ripple/protocol/ErrorCodes.h>
|
||||||
#include <ripple/resource/Fees.h>
|
#include <ripple/resource/Fees.h>
|
||||||
#include <ripple/protocol/JsonFields.h>
|
|
||||||
#include <ripple/rpc/Context.h>
|
#include <ripple/rpc/Context.h>
|
||||||
#include <ripple/rpc/impl/TransactionSign.h>
|
#include <ripple/rpc/impl/TransactionSign.h>
|
||||||
#include <ripple/server/Role.h>
|
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
@@ -53,7 +48,13 @@ Json::Value doSubmit (RPC::Context& context)
|
|||||||
auto const failType = getFailHard (context);
|
auto const failType = getFailHard (context);
|
||||||
|
|
||||||
return RPC::transactionSubmit (
|
return RPC::transactionSubmit (
|
||||||
context.params, failType, context.netOps, context.role);
|
context.params,
|
||||||
|
failType,
|
||||||
|
context.role,
|
||||||
|
context.ledgerMaster.getValidatedLedgerAge(),
|
||||||
|
context.app.getFeeTrack(),
|
||||||
|
context.ledgerMaster.getCurrentLedger(),
|
||||||
|
RPC::getProcessTxnFn (context.netOps));
|
||||||
}
|
}
|
||||||
|
|
||||||
Json::Value jvResult;
|
Json::Value jvResult;
|
||||||
|
|||||||
@@ -18,8 +18,8 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <BeastConfig.h>
|
#include <BeastConfig.h>
|
||||||
#include <ripple/app/main/Application.h>
|
|
||||||
#include <ripple/app/ledger/LedgerMaster.h>
|
#include <ripple/app/ledger/LedgerMaster.h>
|
||||||
|
#include <ripple/protocol/ErrorCodes.h>
|
||||||
#include <ripple/protocol/Feature.h>
|
#include <ripple/protocol/Feature.h>
|
||||||
#include <ripple/resource/Fees.h>
|
#include <ripple/resource/Fees.h>
|
||||||
#include <ripple/rpc/Context.h>
|
#include <ripple/rpc/Context.h>
|
||||||
@@ -45,7 +45,13 @@ Json::Value doSubmitMultiSigned (RPC::Context& context)
|
|||||||
auto const failType = NetworkOPs::doFailHard (failHard);
|
auto const failType = NetworkOPs::doFailHard (failHard);
|
||||||
|
|
||||||
return RPC::transactionSubmitMultiSigned (
|
return RPC::transactionSubmitMultiSigned (
|
||||||
context.params, failType, context.netOps, context.role);
|
context.params,
|
||||||
|
failType,
|
||||||
|
context.role,
|
||||||
|
context.ledgerMaster.getValidatedLedgerAge(),
|
||||||
|
context.app.getFeeTrack(),
|
||||||
|
context.ledgerMaster.getCurrentLedger(),
|
||||||
|
RPC::getProcessTxnFn (context.netOps));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|||||||
@@ -18,23 +18,19 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <BeastConfig.h>
|
#include <BeastConfig.h>
|
||||||
|
#include <ripple/rpc/impl/TransactionSign.h>
|
||||||
#include <ripple/app/ledger/LedgerMaster.h>
|
#include <ripple/app/ledger/LedgerMaster.h>
|
||||||
#include <ripple/app/main/Application.h>
|
|
||||||
#include <ripple/app/paths/FindPaths.h>
|
#include <ripple/app/paths/FindPaths.h>
|
||||||
#include <ripple/basics/Log.h>
|
#include <ripple/basics/Log.h>
|
||||||
#include <ripple/basics/StringUtilities.h>
|
|
||||||
#include <ripple/core/LoadFeeTrack.h>
|
#include <ripple/core/LoadFeeTrack.h>
|
||||||
#include <ripple/json/json_reader.h>
|
|
||||||
#include <ripple/json/json_writer.h>
|
#include <ripple/json/json_writer.h>
|
||||||
#include <ripple/net/RPCErr.h>
|
#include <ripple/net/RPCErr.h>
|
||||||
#include <ripple/protocol/Sign.h>
|
#include <ripple/protocol/Sign.h>
|
||||||
#include <ripple/protocol/ErrorCodes.h>
|
#include <ripple/protocol/ErrorCodes.h>
|
||||||
#include <ripple/protocol/STParsedJSON.h>
|
#include <ripple/protocol/STParsedJSON.h>
|
||||||
#include <ripple/protocol/TxFlags.h>
|
#include <ripple/protocol/TxFlags.h>
|
||||||
#include <ripple/protocol/UintTypes.h>
|
|
||||||
#include <ripple/rpc/impl/KeypairForSignature.h>
|
#include <ripple/rpc/impl/KeypairForSignature.h>
|
||||||
#include <ripple/rpc/impl/LegacyPathFind.h>
|
#include <ripple/rpc/impl/LegacyPathFind.h>
|
||||||
#include <ripple/rpc/impl/TransactionSign.h>
|
|
||||||
#include <ripple/rpc/impl/Tuning.h>
|
#include <ripple/rpc/impl/Tuning.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
@@ -99,109 +95,7 @@ public:
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
// TxnSignApiFacade methods
|
static error_code_i acctMatchesPubKey (
|
||||||
|
|
||||||
void TxnSignApiFacade::snapshotAccountState (AccountID const& accountID)
|
|
||||||
{
|
|
||||||
if (!netOPs_) // Unit testing.
|
|
||||||
return;
|
|
||||||
|
|
||||||
ledger_ = getApp().getLedgerMaster ().getCurrentLedger ();
|
|
||||||
accountID_ = accountID;
|
|
||||||
sle_ = cachedRead(*ledger_,
|
|
||||||
keylet::account(accountID_).key, ltACCOUNT_ROOT);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TxnSignApiFacade::isValidAccount () const
|
|
||||||
{
|
|
||||||
if (!ledger_) // Unit testing.
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return static_cast <bool> (sle_);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::uint32_t TxnSignApiFacade::getSeq () const
|
|
||||||
{
|
|
||||||
if (!ledger_) // Unit testing.
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return sle_->getFieldU32(sfSequence);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TxnSignApiFacade::processTransaction (
|
|
||||||
Transaction::pointer& transaction,
|
|
||||||
bool bAdmin,
|
|
||||||
bool bLocal,
|
|
||||||
NetworkOPs::FailHard failType)
|
|
||||||
{
|
|
||||||
if (!netOPs_) // Unit testing.
|
|
||||||
return;
|
|
||||||
|
|
||||||
netOPs_->processTransaction(transaction, bAdmin, bLocal, failType);
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::optional<STPathSet>
|
|
||||||
TxnSignApiFacade::findPathsForOneIssuer (
|
|
||||||
AccountID const& dstAccountID,
|
|
||||||
Issue const& srcIssue,
|
|
||||||
STAmount const& dstAmount,
|
|
||||||
int searchLevel,
|
|
||||||
unsigned int const maxPaths,
|
|
||||||
STPathSet const& paths,
|
|
||||||
STPath& fullLiquidityPath) const
|
|
||||||
{
|
|
||||||
if (! ledger_) // Unit testing.
|
|
||||||
{
|
|
||||||
// Note that unit tests don't (yet) need paths or fullLiquidityPath.
|
|
||||||
boost::optional<STPathSet> result;
|
|
||||||
result.emplace();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cache = std::make_shared<RippleLineCache> (ledger_);
|
|
||||||
return ripple::findPathsForOneIssuer(
|
|
||||||
cache,
|
|
||||||
accountID_,
|
|
||||||
dstAccountID,
|
|
||||||
srcIssue,
|
|
||||||
dstAmount,
|
|
||||||
searchLevel,
|
|
||||||
maxPaths,
|
|
||||||
paths,
|
|
||||||
fullLiquidityPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::uint64_t TxnSignApiFacade::scaleFeeBase (std::uint64_t fee) const
|
|
||||||
{
|
|
||||||
if (!ledger_) // Unit testing.
|
|
||||||
return fee;
|
|
||||||
|
|
||||||
// VFALCO Audit
|
|
||||||
return getApp().getFeeTrack().scaleFeeBase(
|
|
||||||
fee, ledger_->fees().base, ledger_->fees().units);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::uint64_t
|
|
||||||
TxnSignApiFacade::scaleFeeLoad (std::uint64_t fee, bool bAdmin) const
|
|
||||||
{
|
|
||||||
if (!ledger_) // Unit testing.
|
|
||||||
return fee;
|
|
||||||
|
|
||||||
// VFALCO Audit
|
|
||||||
return getApp().getFeeTrack().scaleFeeLoad(
|
|
||||||
fee, ledger_->fees().base, ledger_->fees().units,
|
|
||||||
bAdmin);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TxnSignApiFacade::hasAccountRoot () const
|
|
||||||
{
|
|
||||||
if (!netOPs_) // Unit testing.
|
|
||||||
return true;
|
|
||||||
return ledger_->exists(
|
|
||||||
keylet::account(accountID_));
|
|
||||||
}
|
|
||||||
|
|
||||||
error_code_i acctMatchesPubKey (
|
|
||||||
std::shared_ptr<SLE const> accountState,
|
std::shared_ptr<SLE const> accountState,
|
||||||
AccountID const& accountID,
|
AccountID const& accountID,
|
||||||
RippleAddress const& publicKey)
|
RippleAddress const& publicKey)
|
||||||
@@ -236,134 +130,13 @@ error_code_i acctMatchesPubKey (
|
|||||||
return rpcBAD_SECRET;
|
return rpcBAD_SECRET;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_code_i TxnSignApiFacade::singleAcctMatchesPubKey (
|
|
||||||
RippleAddress const& publicKey) const
|
|
||||||
{
|
|
||||||
if (!netOPs_) // Unit testing.
|
|
||||||
return rpcSUCCESS;
|
|
||||||
|
|
||||||
return acctMatchesPubKey (sle_, accountID_, publicKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
error_code_i TxnSignApiFacade::multiAcctMatchesPubKey (
|
|
||||||
AccountID const& accountID,
|
|
||||||
RippleAddress const& publicKey) const
|
|
||||||
{
|
|
||||||
std::shared_ptr<SLE const> accountState;
|
|
||||||
// VFALCO Do we need to check netOPs_?
|
|
||||||
if (netOPs_ && ledger_)
|
|
||||||
{
|
|
||||||
// If it's available, get the account root for the multi-signer's
|
|
||||||
// accountID. It's okay if the account root is not available,
|
|
||||||
// since they might be signing with a phantom (unfunded) account.
|
|
||||||
accountState = cachedRead(*ledger_,
|
|
||||||
keylet::account(accountID).key, ltACCOUNT_ROOT);
|
|
||||||
}
|
|
||||||
|
|
||||||
return acctMatchesPubKey (accountState, accountID, publicKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
int TxnSignApiFacade::getValidatedLedgerAge () const
|
|
||||||
{
|
|
||||||
if (!netOPs_) // Unit testing.
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return getApp().getLedgerMaster ().getValidatedLedgerAge ();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TxnSignApiFacade::isLoadedCluster () const
|
|
||||||
{
|
|
||||||
if (!netOPs_) // Unit testing.
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return getApp().getFeeTrack().isLoadedCluster();
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Fill in the fee on behalf of the client.
|
|
||||||
This is called when the client does not explicitly specify the fee.
|
|
||||||
The client may also put a ceiling on the amount of the fee. This ceiling
|
|
||||||
is expressed as a multiplier based on the current ledger's fee schedule.
|
|
||||||
|
|
||||||
JSON fields
|
|
||||||
|
|
||||||
"Fee" The fee paid by the transaction. Omitted when the client
|
|
||||||
wants the fee filled in.
|
|
||||||
|
|
||||||
"fee_mult_max" A multiplier applied to the current ledger's transaction
|
|
||||||
fee that caps the maximum the fee server should auto fill.
|
|
||||||
If this optional field is not specified, then a default
|
|
||||||
multiplier is used.
|
|
||||||
|
|
||||||
@param tx The JSON corresponding to the transaction to fill in.
|
|
||||||
@param ledger A ledger for retrieving the current fee schedule.
|
|
||||||
@param roll Identifies if this is called by an administrative endpoint.
|
|
||||||
|
|
||||||
@return A JSON object containing the error results, if any
|
|
||||||
*/
|
|
||||||
|
|
||||||
Json::Value checkFee (
|
|
||||||
Json::Value& request,
|
|
||||||
TxnSignApiFacade& apiFacade,
|
|
||||||
Role const role,
|
|
||||||
AutoFill const doAutoFill)
|
|
||||||
{
|
|
||||||
Json::Value& tx (request[jss::tx_json]);
|
|
||||||
if (tx.isMember (jss::Fee))
|
|
||||||
return Json::Value();
|
|
||||||
|
|
||||||
if (doAutoFill == AutoFill::dont)
|
|
||||||
return RPC::missing_field_error ("tx_json.Fee");
|
|
||||||
|
|
||||||
int mult = Tuning::defaultAutoFillFeeMultiplier;
|
|
||||||
if (request.isMember (jss::fee_mult_max))
|
|
||||||
{
|
|
||||||
if (request[jss::fee_mult_max].isNumeric ())
|
|
||||||
{
|
|
||||||
mult = request[jss::fee_mult_max].asInt();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return RPC::make_error (rpcHIGH_FEE,
|
|
||||||
RPC::expected_field_message (jss::fee_mult_max, "a number"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default fee in fee units.
|
|
||||||
std::uint64_t const feeDefault = getConfig().TRANSACTION_FEE_BASE;
|
|
||||||
|
|
||||||
// Administrative endpoints are exempt from local fees.
|
|
||||||
std::uint64_t const fee =
|
|
||||||
apiFacade.scaleFeeLoad (feeDefault, role == Role::ADMIN);
|
|
||||||
|
|
||||||
std::uint64_t const limit = mult * apiFacade.scaleFeeBase (feeDefault);
|
|
||||||
|
|
||||||
if (fee > limit)
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "Fee of " << fee
|
|
||||||
<< " exceeds the requested tx limit of " << limit;
|
|
||||||
return RPC::make_error (rpcHIGH_FEE, ss.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
tx [jss::Fee] = static_cast<int>(fee);
|
|
||||||
return Json::Value();
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class PathFind : unsigned char
|
|
||||||
{
|
|
||||||
dont,
|
|
||||||
might
|
|
||||||
};
|
|
||||||
|
|
||||||
static Json::Value checkPayment(
|
static Json::Value checkPayment(
|
||||||
Json::Value const& params,
|
Json::Value const& params,
|
||||||
Json::Value& tx_json,
|
Json::Value& tx_json,
|
||||||
AccountID const& srcAddressID,
|
AccountID const& srcAddressID,
|
||||||
TxnSignApiFacade const& apiFacade,
|
|
||||||
Role const role,
|
Role const role,
|
||||||
PathFind const doPath)
|
std::shared_ptr<ReadView const>& ledger,
|
||||||
|
bool doPath)
|
||||||
{
|
{
|
||||||
// Only path find for Payments.
|
// Only path find for Payments.
|
||||||
if (tx_json[jss::TransactionType].asString () != "Payment")
|
if (tx_json[jss::TransactionType].asString () != "Payment")
|
||||||
@@ -385,7 +158,7 @@ static Json::Value checkPayment(
|
|||||||
if (! dstAccountID)
|
if (! dstAccountID)
|
||||||
return RPC::invalid_field_error ("tx_json.Destination");
|
return RPC::invalid_field_error ("tx_json.Destination");
|
||||||
|
|
||||||
if ((doPath == PathFind::dont) && params.isMember (jss::build_path))
|
if ((doPath == false) && params.isMember (jss::build_path))
|
||||||
return RPC::make_error (rpcINVALID_PARAMS,
|
return RPC::make_error (rpcINVALID_PARAMS,
|
||||||
"Field 'build_path' not allowed in this context.");
|
"Field 'build_path' not allowed in this context.");
|
||||||
|
|
||||||
@@ -419,11 +192,14 @@ static Json::Value checkPayment(
|
|||||||
return rpcError (rpcTOO_BUSY);
|
return rpcError (rpcTOO_BUSY);
|
||||||
|
|
||||||
STPath fullLiquidityPath;
|
STPath fullLiquidityPath;
|
||||||
auto result = apiFacade.findPathsForOneIssuer (
|
auto cache = std::make_shared<RippleLineCache> (ledger);
|
||||||
|
auto result = findPathsForOneIssuer (
|
||||||
|
cache,
|
||||||
|
srcAddressID,
|
||||||
*dstAccountID,
|
*dstAccountID,
|
||||||
sendMax.issue (),
|
sendMax.issue(),
|
||||||
amount,
|
amount,
|
||||||
getConfig ().PATH_SEARCH_OLD,
|
getConfig().PATH_SEARCH_OLD,
|
||||||
4, // iMaxPaths
|
4, // iMaxPaths
|
||||||
{},
|
{},
|
||||||
fullLiquidityPath);
|
fullLiquidityPath);
|
||||||
@@ -458,9 +234,10 @@ static Json::Value checkPayment(
|
|||||||
static std::pair<Json::Value, AccountID>
|
static std::pair<Json::Value, AccountID>
|
||||||
checkTxJsonFields (
|
checkTxJsonFields (
|
||||||
Json::Value const& tx_json,
|
Json::Value const& tx_json,
|
||||||
TxnSignApiFacade const& apiFacade,
|
|
||||||
Role const role,
|
Role const role,
|
||||||
bool const verify)
|
bool const verify,
|
||||||
|
int validatedLedgerAge,
|
||||||
|
LoadFeeTrack const& feeTrack)
|
||||||
{
|
{
|
||||||
std::pair<Json::Value, AccountID> ret;
|
std::pair<Json::Value, AccountID> ret;
|
||||||
|
|
||||||
@@ -495,15 +272,14 @@ checkTxJsonFields (
|
|||||||
|
|
||||||
// Check for current ledger.
|
// Check for current ledger.
|
||||||
if (verify && !getConfig ().RUN_STANDALONE &&
|
if (verify && !getConfig ().RUN_STANDALONE &&
|
||||||
(apiFacade.getValidatedLedgerAge() >
|
(validatedLedgerAge > Tuning::maxValidatedLedgerAge))
|
||||||
Tuning::maxValidatedLedgerAge))
|
|
||||||
{
|
{
|
||||||
ret.first = rpcError (rpcNO_CURRENT);
|
ret.first = rpcError (rpcNO_CURRENT);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for load.
|
// Check for load.
|
||||||
if (apiFacade.isLoadedCluster() && (role != Role::ADMIN))
|
if (feeTrack.isLoadedCluster() && (role != Role::ADMIN))
|
||||||
{
|
{
|
||||||
ret.first = rpcError (rpcTOO_BUSY);
|
ret.first = rpcError (rpcTOO_BUSY);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -550,9 +326,11 @@ static
|
|||||||
transactionPreProcessResult
|
transactionPreProcessResult
|
||||||
transactionPreProcessImpl (
|
transactionPreProcessImpl (
|
||||||
Json::Value& params,
|
Json::Value& params,
|
||||||
TxnSignApiFacade& apiFacade,
|
|
||||||
Role role,
|
Role role,
|
||||||
SigningForParams& signingArgs)
|
SigningForParams& signingArgs,
|
||||||
|
int validatedLedgerAge,
|
||||||
|
LoadFeeTrack const& feeTrack,
|
||||||
|
std::shared_ptr<ReadView const> ledger)
|
||||||
{
|
{
|
||||||
KeyPair keypair;
|
KeyPair keypair;
|
||||||
{
|
{
|
||||||
@@ -571,7 +349,8 @@ transactionPreProcessImpl (
|
|||||||
Json::Value& tx_json (params [jss::tx_json]);
|
Json::Value& tx_json (params [jss::tx_json]);
|
||||||
|
|
||||||
// Check tx_json fields, but don't add any.
|
// Check tx_json fields, but don't add any.
|
||||||
auto txJsonResult = checkTxJsonFields (tx_json, apiFacade, role, verify);
|
auto txJsonResult =
|
||||||
|
checkTxJsonFields (tx_json, role, verify, validatedLedgerAge, feeTrack);
|
||||||
if (RPC::contains_error (txJsonResult.first))
|
if (RPC::contains_error (txJsonResult.first))
|
||||||
return std::move (txJsonResult.first);
|
return std::move (txJsonResult.first);
|
||||||
|
|
||||||
@@ -583,10 +362,10 @@ transactionPreProcessImpl (
|
|||||||
if (!verify && !tx_json.isMember (jss::Sequence))
|
if (!verify && !tx_json.isMember (jss::Sequence))
|
||||||
return RPC::missing_field_error ("tx_json.Sequence");
|
return RPC::missing_field_error ("tx_json.Sequence");
|
||||||
|
|
||||||
apiFacade.snapshotAccountState (srcAddressID);
|
std::shared_ptr<SLE const> sle = cachedRead(*ledger,
|
||||||
|
keylet::account(srcAddressID).key, ltACCOUNT_ROOT);
|
||||||
|
|
||||||
if (verify) {
|
if (verify && !sle)
|
||||||
if (!apiFacade.isValidAccount())
|
|
||||||
{
|
{
|
||||||
// If not offline and did not find account, error.
|
// If not offline and did not find account, error.
|
||||||
WriteLog (lsDEBUG, RPCHandler)
|
WriteLog (lsDEBUG, RPCHandler)
|
||||||
@@ -596,14 +375,14 @@ transactionPreProcessImpl (
|
|||||||
|
|
||||||
return rpcError (rpcSRC_ACT_NOT_FOUND);
|
return rpcError (rpcSRC_ACT_NOT_FOUND);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
Json::Value err = checkFee (
|
Json::Value err = checkFee (
|
||||||
params,
|
params,
|
||||||
apiFacade,
|
|
||||||
role,
|
role,
|
||||||
signingArgs.editFields() ? AutoFill::might : AutoFill::dont);
|
signingArgs.editFields(),
|
||||||
|
feeTrack,
|
||||||
|
ledger);
|
||||||
|
|
||||||
if (RPC::contains_error (err))
|
if (RPC::contains_error (err))
|
||||||
return std::move (err);
|
return std::move (err);
|
||||||
@@ -612,9 +391,9 @@ transactionPreProcessImpl (
|
|||||||
params,
|
params,
|
||||||
tx_json,
|
tx_json,
|
||||||
srcAddressID,
|
srcAddressID,
|
||||||
apiFacade,
|
|
||||||
role,
|
role,
|
||||||
signingArgs.editFields() ? PathFind::might : PathFind::dont);
|
ledger,
|
||||||
|
signingArgs.editFields());
|
||||||
|
|
||||||
if (RPC::contains_error(err))
|
if (RPC::contains_error(err))
|
||||||
return std::move (err);
|
return std::move (err);
|
||||||
@@ -623,7 +402,18 @@ transactionPreProcessImpl (
|
|||||||
if (signingArgs.editFields())
|
if (signingArgs.editFields())
|
||||||
{
|
{
|
||||||
if (!tx_json.isMember (jss::Sequence))
|
if (!tx_json.isMember (jss::Sequence))
|
||||||
tx_json[jss::Sequence] = apiFacade.getSeq();
|
{
|
||||||
|
if (! sle)
|
||||||
|
{
|
||||||
|
WriteLog (lsDEBUG, RPCHandler)
|
||||||
|
<< "transactionSign: Failed to find source account "
|
||||||
|
<< "in current ledger: "
|
||||||
|
<< toBase58(srcAddressID);
|
||||||
|
|
||||||
|
return rpcError (rpcSRC_ACT_NOT_FOUND);
|
||||||
|
}
|
||||||
|
tx_json[jss::Sequence] = (*sle)[sfSequence];
|
||||||
|
}
|
||||||
|
|
||||||
if (!tx_json.isMember (jss::Flags))
|
if (!tx_json.isMember (jss::Flags))
|
||||||
tx_json[jss::Flags] = tfFullyCanonicalSig;
|
tx_json[jss::Flags] = tfFullyCanonicalSig;
|
||||||
@@ -631,7 +421,7 @@ transactionPreProcessImpl (
|
|||||||
|
|
||||||
if (verify)
|
if (verify)
|
||||||
{
|
{
|
||||||
if (!apiFacade.hasAccountRoot())
|
if (! sle)
|
||||||
// XXX Ignore transactions for accounts not created.
|
// XXX Ignore transactions for accounts not created.
|
||||||
return rpcError (rpcSRC_ACT_NOT_FOUND);
|
return rpcError (rpcSRC_ACT_NOT_FOUND);
|
||||||
|
|
||||||
@@ -648,7 +438,7 @@ transactionPreProcessImpl (
|
|||||||
{
|
{
|
||||||
// Make sure the account and secret belong together.
|
// Make sure the account and secret belong together.
|
||||||
error_code_i const err =
|
error_code_i const err =
|
||||||
apiFacade.singleAcctMatchesPubKey (keypair.publicKey);
|
acctMatchesPubKey (sle, srcAddressID, keypair.publicKey);
|
||||||
|
|
||||||
if (err != rpcSUCCESS)
|
if (err != rpcSUCCESS)
|
||||||
return rpcError (err);
|
return rpcError (err);
|
||||||
@@ -763,7 +553,7 @@ transactionConstructImpl (STTx::pointer stpTrans)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Json::Value transactionFormatResultImpl (Transaction::pointer tpTrans)
|
static Json::Value transactionFormatResultImpl (Transaction::pointer tpTrans)
|
||||||
{
|
{
|
||||||
Json::Value jvResult;
|
Json::Value jvResult;
|
||||||
try
|
try
|
||||||
@@ -796,12 +586,67 @@ Json::Value transactionFormatResultImpl (Transaction::pointer tpTrans)
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Json::Value checkFee (
|
||||||
|
Json::Value& request,
|
||||||
|
Role const role,
|
||||||
|
bool doAutoFill,
|
||||||
|
LoadFeeTrack const& feeTrack,
|
||||||
|
std::shared_ptr<ReadView const>& ledger)
|
||||||
|
{
|
||||||
|
Json::Value& tx (request[jss::tx_json]);
|
||||||
|
if (tx.isMember (jss::Fee))
|
||||||
|
return Json::Value();
|
||||||
|
|
||||||
|
if (! doAutoFill)
|
||||||
|
return RPC::missing_field_error ("tx_json.Fee");
|
||||||
|
|
||||||
|
int mult = Tuning::defaultAutoFillFeeMultiplier;
|
||||||
|
if (request.isMember (jss::fee_mult_max))
|
||||||
|
{
|
||||||
|
if (request[jss::fee_mult_max].isNumeric ())
|
||||||
|
{
|
||||||
|
mult = request[jss::fee_mult_max].asInt();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return RPC::make_error (rpcHIGH_FEE,
|
||||||
|
RPC::expected_field_message (jss::fee_mult_max, "a number"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default fee in fee units.
|
||||||
|
std::uint64_t const feeDefault = getConfig().TRANSACTION_FEE_BASE;
|
||||||
|
|
||||||
|
// Administrative endpoints are exempt from local fees.
|
||||||
|
std::uint64_t const fee =
|
||||||
|
feeTrack.scaleFeeLoad (feeDefault,
|
||||||
|
ledger->fees().base, ledger->fees().units, role == Role::ADMIN);
|
||||||
|
|
||||||
|
std::uint64_t const limit = mult * feeTrack.scaleFeeBase (
|
||||||
|
feeDefault, ledger->fees().base, ledger->fees().units);
|
||||||
|
|
||||||
|
if (fee > limit)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "Fee of " << fee
|
||||||
|
<< " exceeds the requested tx limit of " << limit;
|
||||||
|
return RPC::make_error (rpcHIGH_FEE, ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
tx [jss::Fee] = static_cast<int>(fee);
|
||||||
|
return Json::Value();
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
/** Returns a Json::objectValue. */
|
/** Returns a Json::objectValue. */
|
||||||
Json::Value transactionSign (
|
Json::Value transactionSign (
|
||||||
Json::Value jvRequest,
|
Json::Value jvRequest,
|
||||||
NetworkOPs::FailHard failType,
|
NetworkOPs::FailHard failType,
|
||||||
detail::TxnSignApiFacade& apiFacade,
|
Role role,
|
||||||
Role role)
|
int validatedLedgerAge,
|
||||||
|
LoadFeeTrack const& feeTrack,
|
||||||
|
std::shared_ptr<ReadView const> ledger)
|
||||||
{
|
{
|
||||||
WriteLog (lsDEBUG, RPCHandler) << "transactionSign: " << jvRequest;
|
WriteLog (lsDEBUG, RPCHandler) << "transactionSign: " << jvRequest;
|
||||||
|
|
||||||
@@ -809,8 +654,8 @@ Json::Value transactionSign (
|
|||||||
|
|
||||||
// Add and amend fields based on the transaction type.
|
// Add and amend fields based on the transaction type.
|
||||||
SigningForParams signForParams;
|
SigningForParams signForParams;
|
||||||
transactionPreProcessResult preprocResult =
|
transactionPreProcessResult preprocResult = transactionPreProcessImpl (
|
||||||
transactionPreProcessImpl (jvRequest, apiFacade, role, signForParams);
|
jvRequest, role, signForParams, validatedLedgerAge, feeTrack, ledger);
|
||||||
|
|
||||||
if (!preprocResult.second)
|
if (!preprocResult.second)
|
||||||
return preprocResult.first;
|
return preprocResult.first;
|
||||||
@@ -829,8 +674,11 @@ Json::Value transactionSign (
|
|||||||
Json::Value transactionSubmit (
|
Json::Value transactionSubmit (
|
||||||
Json::Value jvRequest,
|
Json::Value jvRequest,
|
||||||
NetworkOPs::FailHard failType,
|
NetworkOPs::FailHard failType,
|
||||||
detail::TxnSignApiFacade& apiFacade,
|
Role role,
|
||||||
Role role)
|
int validatedLedgerAge,
|
||||||
|
LoadFeeTrack const& feeTrack,
|
||||||
|
std::shared_ptr<ReadView const> ledger,
|
||||||
|
ProcessTransactionFn const& processTransaction)
|
||||||
{
|
{
|
||||||
WriteLog (lsDEBUG, RPCHandler) << "transactionSubmit: " << jvRequest;
|
WriteLog (lsDEBUG, RPCHandler) << "transactionSubmit: " << jvRequest;
|
||||||
|
|
||||||
@@ -838,8 +686,8 @@ Json::Value transactionSubmit (
|
|||||||
|
|
||||||
// Add and amend fields based on the transaction type.
|
// Add and amend fields based on the transaction type.
|
||||||
SigningForParams signForParams;
|
SigningForParams signForParams;
|
||||||
transactionPreProcessResult preprocResult =
|
transactionPreProcessResult preprocResult = transactionPreProcessImpl (
|
||||||
transactionPreProcessImpl (jvRequest, apiFacade, role, signForParams);
|
jvRequest, role, signForParams, validatedLedgerAge, feeTrack, ledger);
|
||||||
|
|
||||||
if (!preprocResult.second)
|
if (!preprocResult.second)
|
||||||
return preprocResult.first;
|
return preprocResult.first;
|
||||||
@@ -855,7 +703,7 @@ Json::Value transactionSubmit (
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// FIXME: For performance, should use asynch interface
|
// FIXME: For performance, should use asynch interface
|
||||||
apiFacade.processTransaction (
|
processTransaction (
|
||||||
txn.second, role == Role::ADMIN, true, failType);
|
txn.second, role == Role::ADMIN, true, failType);
|
||||||
}
|
}
|
||||||
catch (std::exception&)
|
catch (std::exception&)
|
||||||
@@ -900,8 +748,10 @@ Json::Value checkMultiSignFields (Json::Value const& jvRequest)
|
|||||||
Json::Value transactionSignFor (
|
Json::Value transactionSignFor (
|
||||||
Json::Value jvRequest,
|
Json::Value jvRequest,
|
||||||
NetworkOPs::FailHard failType,
|
NetworkOPs::FailHard failType,
|
||||||
detail::TxnSignApiFacade& apiFacade,
|
Role role,
|
||||||
Role role)
|
int validatedLedgerAge,
|
||||||
|
LoadFeeTrack const& feeTrack,
|
||||||
|
std::shared_ptr<ReadView const> ledger)
|
||||||
{
|
{
|
||||||
WriteLog (lsDEBUG, RPCHandler) << "transactionSignFor: " << jvRequest;
|
WriteLog (lsDEBUG, RPCHandler) << "transactionSignFor: " << jvRequest;
|
||||||
|
|
||||||
@@ -935,20 +785,25 @@ Json::Value transactionSignFor (
|
|||||||
SigningForParams signForParams(
|
SigningForParams signForParams(
|
||||||
*signerAccountID, multiSignPubKey, multiSignature);
|
*signerAccountID, multiSignPubKey, multiSignature);
|
||||||
|
|
||||||
transactionPreProcessResult preprocResult =
|
transactionPreProcessResult preprocResult = transactionPreProcessImpl (
|
||||||
transactionPreProcessImpl (
|
|
||||||
jvRequest,
|
jvRequest,
|
||||||
apiFacade,
|
|
||||||
role,
|
role,
|
||||||
signForParams);
|
signForParams,
|
||||||
|
validatedLedgerAge,
|
||||||
|
feeTrack,
|
||||||
|
ledger);
|
||||||
|
|
||||||
if (!preprocResult.second)
|
if (!preprocResult.second)
|
||||||
return preprocResult.first;
|
return preprocResult.first;
|
||||||
|
|
||||||
// Make sure the multiSignAddrID can legitimately multi-sign.
|
// Make sure the multiSignAddrID can legitimately multi-sign.
|
||||||
{
|
{
|
||||||
|
// Make sure the account and secret belong together.
|
||||||
|
std::shared_ptr<SLE const> sle = cachedRead(*ledger,
|
||||||
|
keylet::account(*signerAccountID).key, ltACCOUNT_ROOT);
|
||||||
|
|
||||||
error_code_i const err =
|
error_code_i const err =
|
||||||
apiFacade.multiAcctMatchesPubKey (*signerAccountID, multiSignPubKey);
|
acctMatchesPubKey (sle, *signerAccountID, multiSignPubKey);
|
||||||
|
|
||||||
if (err != rpcSUCCESS)
|
if (err != rpcSUCCESS)
|
||||||
return rpcError (err);
|
return rpcError (err);
|
||||||
@@ -993,8 +848,11 @@ Json::Value transactionSignFor (
|
|||||||
Json::Value transactionSubmitMultiSigned (
|
Json::Value transactionSubmitMultiSigned (
|
||||||
Json::Value jvRequest,
|
Json::Value jvRequest,
|
||||||
NetworkOPs::FailHard failType,
|
NetworkOPs::FailHard failType,
|
||||||
detail::TxnSignApiFacade& apiFacade,
|
Role role,
|
||||||
Role role)
|
int validatedLedgerAge,
|
||||||
|
LoadFeeTrack const& feeTrack,
|
||||||
|
std::shared_ptr<ReadView const> ledger,
|
||||||
|
ProcessTransactionFn const& processTransaction)
|
||||||
{
|
{
|
||||||
WriteLog (lsDEBUG, RPCHandler)
|
WriteLog (lsDEBUG, RPCHandler)
|
||||||
<< "transactionSubmitMultiSigned: " << jvRequest;
|
<< "transactionSubmitMultiSigned: " << jvRequest;
|
||||||
@@ -1010,16 +868,19 @@ Json::Value transactionSubmitMultiSigned (
|
|||||||
|
|
||||||
Json::Value& tx_json (jvRequest ["tx_json"]);
|
Json::Value& tx_json (jvRequest ["tx_json"]);
|
||||||
|
|
||||||
auto const txJsonResult = checkTxJsonFields(tx_json, apiFacade, role, true);
|
auto const txJsonResult =
|
||||||
|
checkTxJsonFields (tx_json, role, true, validatedLedgerAge, feeTrack);
|
||||||
if (RPC::contains_error (txJsonResult.first))
|
if (RPC::contains_error (txJsonResult.first))
|
||||||
return std::move (txJsonResult.first);
|
return std::move (txJsonResult.first);
|
||||||
|
|
||||||
auto const srcAddressID = txJsonResult.second;
|
auto const srcAddressID = txJsonResult.second;
|
||||||
|
|
||||||
apiFacade.snapshotAccountState (srcAddressID);
|
std::shared_ptr<SLE const> sle = cachedRead(*ledger,
|
||||||
if (!apiFacade.isValidAccount ())
|
keylet::account(srcAddressID).key, ltACCOUNT_ROOT);
|
||||||
|
|
||||||
|
if (!sle)
|
||||||
{
|
{
|
||||||
// If not offline and did not find account, error.
|
// If did not find account, error.
|
||||||
WriteLog (lsDEBUG, RPCHandler)
|
WriteLog (lsDEBUG, RPCHandler)
|
||||||
<< "transactionSubmitMultiSigned: Failed to find source account "
|
<< "transactionSubmitMultiSigned: Failed to find source account "
|
||||||
<< "in current ledger: "
|
<< "in current ledger: "
|
||||||
@@ -1029,7 +890,8 @@ Json::Value transactionSubmitMultiSigned (
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Json::Value err = checkFee (jvRequest, apiFacade, role, AutoFill::dont);
|
Json::Value err = checkFee (jvRequest, role, false, feeTrack, ledger);
|
||||||
|
|
||||||
if (RPC::contains_error(err))
|
if (RPC::contains_error(err))
|
||||||
return std::move (err);
|
return std::move (err);
|
||||||
|
|
||||||
@@ -1037,9 +899,9 @@ Json::Value transactionSubmitMultiSigned (
|
|||||||
jvRequest,
|
jvRequest,
|
||||||
tx_json,
|
tx_json,
|
||||||
srcAddressID,
|
srcAddressID,
|
||||||
apiFacade,
|
|
||||||
role,
|
role,
|
||||||
PathFind::dont);
|
ledger,
|
||||||
|
false);
|
||||||
|
|
||||||
if (RPC::contains_error(err))
|
if (RPC::contains_error(err))
|
||||||
return std::move (err);
|
return std::move (err);
|
||||||
@@ -1121,7 +983,7 @@ Json::Value transactionSubmitMultiSigned (
|
|||||||
{
|
{
|
||||||
std::ostringstream err;
|
std::ostringstream err;
|
||||||
err << "Expected "
|
err << "Expected "
|
||||||
<< signersArrayName << " to be an array";
|
<< signersArrayName << " to be an array.";
|
||||||
return RPC::make_param_error (err.str ());
|
return RPC::make_param_error (err.str ());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1160,8 +1022,7 @@ Json::Value transactionSubmitMultiSigned (
|
|||||||
{
|
{
|
||||||
std::ostringstream err;
|
std::ostringstream err;
|
||||||
err << "Duplicate Signers:Signer:Account entries ("
|
err << "Duplicate Signers:Signer:Account entries ("
|
||||||
<< getApp().accountIDCache().toBase58(
|
<< toBase58(dupIter->getAccountID(sfAccount))
|
||||||
dupIter->getAccountID(sfAccount))
|
|
||||||
<< ") are not allowed.";
|
<< ") are not allowed.";
|
||||||
return RPC::make_param_error(err.str ());
|
return RPC::make_param_error(err.str ());
|
||||||
}
|
}
|
||||||
@@ -1175,7 +1036,7 @@ Json::Value transactionSubmitMultiSigned (
|
|||||||
{
|
{
|
||||||
std::ostringstream err;
|
std::ostringstream err;
|
||||||
err << "A Signer may not be the transaction's Account ("
|
err << "A Signer may not be the transaction's Account ("
|
||||||
<< getApp().accountIDCache().toBase58(srcAddressID) << ").";
|
<< toBase58(srcAddressID) << ").";
|
||||||
return RPC::make_param_error(err.str ());
|
return RPC::make_param_error(err.str ());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1193,7 +1054,7 @@ Json::Value transactionSubmitMultiSigned (
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// FIXME: For performance, should use asynch interface
|
// FIXME: For performance, should use asynch interface
|
||||||
apiFacade.processTransaction (
|
processTransaction (
|
||||||
txn.second, role == Role::ADMIN, true, failType);
|
txn.second, role == Role::ADMIN, true, failType);
|
||||||
}
|
}
|
||||||
catch (std::exception&)
|
catch (std::exception&)
|
||||||
|
|||||||
@@ -21,180 +21,94 @@
|
|||||||
#define RIPPLE_RPC_TRANSACTIONSIGN_H_INCLUDED
|
#define RIPPLE_RPC_TRANSACTIONSIGN_H_INCLUDED
|
||||||
|
|
||||||
#include <ripple/app/misc/NetworkOPs.h>
|
#include <ripple/app/misc/NetworkOPs.h>
|
||||||
#include <ripple/protocol/ErrorCodes.h>
|
|
||||||
#include <ripple/server/Role.h>
|
#include <ripple/server/Role.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
class LoadFeeTrack;
|
||||||
|
|
||||||
namespace RPC {
|
namespace RPC {
|
||||||
|
|
||||||
namespace detail {
|
/** Fill in the fee on behalf of the client.
|
||||||
|
This is called when the client does not explicitly specify the fee.
|
||||||
|
The client may also put a ceiling on the amount of the fee. This ceiling
|
||||||
|
is expressed as a multiplier based on the current ledger's fee schedule.
|
||||||
|
|
||||||
// A class that allows these methods to be called with or without a
|
JSON fields
|
||||||
// real NetworkOPs instance. This allows for unit testing.
|
|
||||||
class TxnSignApiFacade
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
NetworkOPs* const netOPs_;
|
|
||||||
std::shared_ptr<ReadView const> ledger_;
|
|
||||||
AccountID accountID_;
|
|
||||||
std::shared_ptr<SLE const> sle_;
|
|
||||||
|
|
||||||
public:
|
"Fee" The fee paid by the transaction. Omitted when the client
|
||||||
// Enum used to construct a Facade for unit tests.
|
wants the fee filled in.
|
||||||
enum NoNetworkOPs{
|
|
||||||
noNetOPs
|
|
||||||
};
|
|
||||||
|
|
||||||
TxnSignApiFacade () = delete;
|
"fee_mult_max" A multiplier applied to the current ledger's transaction
|
||||||
TxnSignApiFacade (TxnSignApiFacade const&) = delete;
|
fee that caps the maximum the fee server should auto fill.
|
||||||
TxnSignApiFacade& operator= (TxnSignApiFacade const&) = delete;
|
If this optional field is not specified, then a default
|
||||||
|
multiplier is used.
|
||||||
|
|
||||||
// For use in non unit testing circumstances.
|
@param tx The JSON corresponding to the transaction to fill in.
|
||||||
explicit TxnSignApiFacade (NetworkOPs& netOPs)
|
@param ledger A ledger for retrieving the current fee schedule.
|
||||||
: netOPs_ (&netOPs)
|
@param roll Identifies if this is called by an administrative endpoint.
|
||||||
{ }
|
|
||||||
|
|
||||||
// For testTransactionRPC unit tests.
|
|
||||||
explicit TxnSignApiFacade (NoNetworkOPs noOPs)
|
|
||||||
: netOPs_ (nullptr) { }
|
|
||||||
|
|
||||||
// For testAutoFillFees unit tests.
|
|
||||||
TxnSignApiFacade (NoNetworkOPs noOPs, std::shared_ptr<ReadView const> ledger)
|
|
||||||
: netOPs_ (nullptr)
|
|
||||||
, ledger_ (ledger)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void snapshotAccountState (AccountID const& accountID);
|
|
||||||
|
|
||||||
bool isValidAccount () const;
|
|
||||||
|
|
||||||
std::uint32_t getSeq () const;
|
|
||||||
|
|
||||||
boost::optional<STPathSet>
|
|
||||||
findPathsForOneIssuer (
|
|
||||||
AccountID const& dstAccountID,
|
|
||||||
Issue const& srcIssue,
|
|
||||||
STAmount const& dstAmount,
|
|
||||||
int searchLevel,
|
|
||||||
unsigned int const maxPaths,
|
|
||||||
STPathSet const& paths,
|
|
||||||
STPath& fullLiquidityPath) const;
|
|
||||||
|
|
||||||
void processTransaction (
|
|
||||||
Transaction::pointer& transaction,
|
|
||||||
bool bAdmin,
|
|
||||||
bool bLocal,
|
|
||||||
NetworkOPs::FailHard failType);
|
|
||||||
|
|
||||||
std::uint64_t scaleFeeBase (std::uint64_t fee) const;
|
|
||||||
|
|
||||||
std::uint64_t scaleFeeLoad (std::uint64_t fee, bool bAdmin) const;
|
|
||||||
|
|
||||||
bool hasAccountRoot () const;
|
|
||||||
|
|
||||||
error_code_i singleAcctMatchesPubKey (
|
|
||||||
RippleAddress const& publicKey) const;
|
|
||||||
|
|
||||||
error_code_i multiAcctMatchesPubKey (
|
|
||||||
AccountID const& acctID,
|
|
||||||
RippleAddress const& publicKey) const;
|
|
||||||
|
|
||||||
int getValidatedLedgerAge () const;
|
|
||||||
|
|
||||||
bool isLoadedCluster () const;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A function to auto-fill fees.
|
|
||||||
enum class AutoFill : unsigned char
|
|
||||||
{
|
|
||||||
dont,
|
|
||||||
might
|
|
||||||
};
|
|
||||||
|
|
||||||
|
@return A JSON object containing the error results, if any
|
||||||
|
*/
|
||||||
Json::Value checkFee (
|
Json::Value checkFee (
|
||||||
Json::Value& request,
|
Json::Value& request,
|
||||||
TxnSignApiFacade& apiFacade,
|
|
||||||
Role const role,
|
Role const role,
|
||||||
AutoFill const doAutoFill);
|
bool doAutoFill,
|
||||||
|
LoadFeeTrack const& feeTrack,
|
||||||
|
std::shared_ptr<ReadView const>& ledger);
|
||||||
|
|
||||||
} // namespace detail
|
// Return a std::function<> that calls NetworkOPs::processTransaction.
|
||||||
|
using ProcessTransactionFn =
|
||||||
|
std::function<void (Transaction::pointer& transaction,
|
||||||
|
bool bAdmin, bool bLocal, NetworkOPs::FailHard failType)>;
|
||||||
|
|
||||||
|
inline ProcessTransactionFn getProcessTxnFn (NetworkOPs& netOPs)
|
||||||
|
{
|
||||||
|
return [&netOPs](Transaction::pointer& transaction,
|
||||||
|
bool bAdmin, bool bLocal, NetworkOPs::FailHard failType)
|
||||||
|
{
|
||||||
|
netOPs.processTransaction(transaction, bAdmin, bLocal, failType);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns a Json::objectValue. */
|
/** Returns a Json::objectValue. */
|
||||||
Json::Value transactionSign (
|
Json::Value transactionSign (
|
||||||
Json::Value params, // Passed by value so it can be modified locally.
|
Json::Value params, // Passed by value so it can be modified locally.
|
||||||
NetworkOPs::FailHard failType,
|
NetworkOPs::FailHard failType,
|
||||||
detail::TxnSignApiFacade& apiFacade,
|
Role role,
|
||||||
Role role);
|
int validatedLedgerAge,
|
||||||
|
LoadFeeTrack const& feeTrack,
|
||||||
/** Returns a Json::objectValue. */
|
std::shared_ptr<ReadView const> ledger);
|
||||||
inline
|
|
||||||
Json::Value transactionSign (
|
|
||||||
Json::Value const& params,
|
|
||||||
NetworkOPs::FailHard failType,
|
|
||||||
NetworkOPs& netOPs,
|
|
||||||
Role role)
|
|
||||||
{
|
|
||||||
detail::TxnSignApiFacade apiFacade (netOPs);
|
|
||||||
return transactionSign (params, failType, apiFacade, role);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns a Json::objectValue. */
|
/** Returns a Json::objectValue. */
|
||||||
Json::Value transactionSubmit (
|
Json::Value transactionSubmit (
|
||||||
Json::Value params, // Passed by value so it can be modified locally.
|
Json::Value params, // Passed by value so it can be modified locally.
|
||||||
NetworkOPs::FailHard failType,
|
NetworkOPs::FailHard failType,
|
||||||
detail::TxnSignApiFacade& apiFacade,
|
Role role,
|
||||||
Role role);
|
int validatedLedgerAge,
|
||||||
|
LoadFeeTrack const& feeTrack,
|
||||||
/** Returns a Json::objectValue. */
|
std::shared_ptr<ReadView const> ledger,
|
||||||
inline
|
ProcessTransactionFn const& processTransaction);
|
||||||
Json::Value transactionSubmit (
|
|
||||||
Json::Value const& params,
|
|
||||||
NetworkOPs::FailHard failType,
|
|
||||||
NetworkOPs& netOPs,
|
|
||||||
Role role)
|
|
||||||
{
|
|
||||||
detail::TxnSignApiFacade apiFacade (netOPs);
|
|
||||||
return transactionSubmit (params, failType, apiFacade, role);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns a Json::objectValue. */
|
/** Returns a Json::objectValue. */
|
||||||
Json::Value transactionSignFor (
|
Json::Value transactionSignFor (
|
||||||
Json::Value params, // Passed by value so it can be modified locally.
|
Json::Value params, // Passed by value so it can be modified locally.
|
||||||
NetworkOPs::FailHard failType,
|
NetworkOPs::FailHard failType,
|
||||||
detail::TxnSignApiFacade& apiFacade,
|
Role role,
|
||||||
Role role);
|
int validatedLedgerAge,
|
||||||
|
LoadFeeTrack const& feeTrack,
|
||||||
/** Returns a Json::objectValue. */
|
std::shared_ptr<ReadView const> ledger);
|
||||||
inline
|
|
||||||
Json::Value transactionSignFor (
|
|
||||||
Json::Value const& params,
|
|
||||||
NetworkOPs::FailHard failType,
|
|
||||||
NetworkOPs& netOPs,
|
|
||||||
Role role)
|
|
||||||
{
|
|
||||||
detail::TxnSignApiFacade apiFacade (netOPs);
|
|
||||||
return transactionSignFor (params, failType, apiFacade, role);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns a Json::objectValue. */
|
/** Returns a Json::objectValue. */
|
||||||
Json::Value transactionSubmitMultiSigned (
|
Json::Value transactionSubmitMultiSigned (
|
||||||
Json::Value params, // Passed by value so it can be modified locally.
|
Json::Value params, // Passed by value so it can be modified locally.
|
||||||
NetworkOPs::FailHard failType,
|
NetworkOPs::FailHard failType,
|
||||||
detail::TxnSignApiFacade& apiFacade,
|
Role role,
|
||||||
Role role);
|
int validatedLedgerAge,
|
||||||
|
LoadFeeTrack const& feeTrack,
|
||||||
/** Returns a Json::objectValue. */
|
std::shared_ptr<ReadView const> ledger,
|
||||||
inline
|
ProcessTransactionFn const& processTransaction);
|
||||||
Json::Value transactionSubmitMultiSigned (
|
|
||||||
Json::Value const& params,
|
|
||||||
NetworkOPs::FailHard failType,
|
|
||||||
NetworkOPs& netOPs,
|
|
||||||
Role role)
|
|
||||||
{
|
|
||||||
detail::TxnSignApiFacade apiFacade (netOPs);
|
|
||||||
return transactionSubmitMultiSigned (params, failType, apiFacade, role);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // RPC
|
} // RPC
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|||||||
@@ -18,12 +18,11 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <BeastConfig.h>
|
#include <BeastConfig.h>
|
||||||
#include <ripple/app/paths/FindPaths.h>
|
#include <ripple/core/LoadFeeTrack.h>
|
||||||
#include <ripple/basics/StringUtilities.h>
|
|
||||||
#include <ripple/json/json_reader.h>
|
#include <ripple/json/json_reader.h>
|
||||||
#include <ripple/protocol/SecretKey.h>
|
#include <ripple/protocol/ErrorCodes.h>
|
||||||
#include <ripple/protocol/TxFlags.h>
|
|
||||||
#include <ripple/rpc/impl/TransactionSign.h>
|
#include <ripple/rpc/impl/TransactionSign.h>
|
||||||
|
#include <ripple/test/jtx.h>
|
||||||
#include <beast/unit_test/suite.h>
|
#include <beast/unit_test/suite.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
@@ -303,7 +302,7 @@ R"({
|
|||||||
"Amount": {
|
"Amount": {
|
||||||
"value": "10",
|
"value": "10",
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"issuer": "0123456789012345678901234567890123456789"
|
"issuer": "rLPwWB1itaUGMV8kbMLLysjGkEpTM2Soy4"
|
||||||
},
|
},
|
||||||
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
"TransactionType": "Payment"
|
"TransactionType": "Payment"
|
||||||
@@ -326,7 +325,7 @@ R"({
|
|||||||
"Amount": {
|
"Amount": {
|
||||||
"value": "10",
|
"value": "10",
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"issuer": "0123456789012345678901234567890123456789"
|
"issuer": "rLPwWB1itaUGMV8kbMLLysjGkEpTM2Soy4"
|
||||||
},
|
},
|
||||||
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
"Paths": "",
|
"Paths": "",
|
||||||
@@ -350,12 +349,12 @@ R"({
|
|||||||
"Amount": {
|
"Amount": {
|
||||||
"value": "10",
|
"value": "10",
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"issuer": "0123456789012345678901234567890123456789"
|
"issuer": "rLPwWB1itaUGMV8kbMLLysjGkEpTM2Soy4"
|
||||||
},
|
},
|
||||||
"SendMax": {
|
"SendMax": {
|
||||||
"value": "5",
|
"value": "5",
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"issuer": "0123456789012345678901234567890123456789"
|
"issuer": "rLPwWB1itaUGMV8kbMLLysjGkEpTM2Soy4"
|
||||||
},
|
},
|
||||||
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
"TransactionType": "Payment"
|
"TransactionType": "Payment"
|
||||||
@@ -378,7 +377,7 @@ R"({
|
|||||||
"Amount": {
|
"Amount": {
|
||||||
"value": "10",
|
"value": "10",
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"issuer": "0123456789012345678901234567890123456789"
|
"issuer": "rLPwWB1itaUGMV8kbMLLysjGkEpTM2Soy4"
|
||||||
},
|
},
|
||||||
"SendMax": 10000,
|
"SendMax": 10000,
|
||||||
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
@@ -663,8 +662,8 @@ R"({
|
|||||||
}
|
}
|
||||||
})",
|
})",
|
||||||
{
|
{
|
||||||
"",
|
"Secret does not match account.",
|
||||||
"",
|
"Secret does not match account.",
|
||||||
"",
|
"",
|
||||||
"Missing field 'Signers'."}},
|
"Missing field 'Signers'."}},
|
||||||
|
|
||||||
@@ -743,8 +742,8 @@ R"({
|
|||||||
}
|
}
|
||||||
})",
|
})",
|
||||||
{
|
{
|
||||||
"",
|
"Secret does not match account.",
|
||||||
"",
|
"Secret does not match account.",
|
||||||
"Missing field 'tx_json.Fee'.",
|
"Missing field 'tx_json.Fee'.",
|
||||||
"Missing field 'tx_json.Fee'."}},
|
"Missing field 'tx_json.Fee'."}},
|
||||||
|
|
||||||
@@ -763,8 +762,8 @@ R"({
|
|||||||
}
|
}
|
||||||
})",
|
})",
|
||||||
{
|
{
|
||||||
"",
|
"Secret does not match account.",
|
||||||
"",
|
"Secret does not match account.",
|
||||||
"Missing field 'tx_json.Sequence'.",
|
"Missing field 'tx_json.Sequence'.",
|
||||||
"Missing field 'tx_json.Sequence'."}},
|
"Missing field 'tx_json.Sequence'."}},
|
||||||
|
|
||||||
@@ -783,8 +782,8 @@ R"({
|
|||||||
}
|
}
|
||||||
})",
|
})",
|
||||||
{
|
{
|
||||||
"",
|
"Secret does not match account.",
|
||||||
"",
|
"Secret does not match account.",
|
||||||
"Missing field 'tx_json.SigningPubKey'.",
|
"Missing field 'tx_json.SigningPubKey'.",
|
||||||
"Missing field 'tx_json.SigningPubKey'."}},
|
"Missing field 'tx_json.SigningPubKey'."}},
|
||||||
|
|
||||||
@@ -804,8 +803,8 @@ R"({
|
|||||||
}
|
}
|
||||||
})",
|
})",
|
||||||
{
|
{
|
||||||
"",
|
"Secret does not match account.",
|
||||||
"",
|
"Secret does not match account.",
|
||||||
"When multi-signing 'tx_json.SigningPubKey' must be empty.",
|
"When multi-signing 'tx_json.SigningPubKey' must be empty.",
|
||||||
"When multi-signing 'tx_json.SigningPubKey' must be empty."}},
|
"When multi-signing 'tx_json.SigningPubKey' must be empty."}},
|
||||||
|
|
||||||
@@ -857,6 +856,538 @@ R"({
|
|||||||
"Missing field 'account'.",
|
"Missing field 'account'.",
|
||||||
""}},
|
""}},
|
||||||
|
|
||||||
|
{ "Missing tx_json in submit_multisigned.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"Signers": [
|
||||||
|
{
|
||||||
|
"Signer": {
|
||||||
|
"Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
|
||||||
|
"TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"Missing field 'tx_json'."}},
|
||||||
|
|
||||||
|
{ "Missing sequence in submit_multisigned.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"Signers": [
|
||||||
|
{
|
||||||
|
"Signer": {
|
||||||
|
"Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
|
||||||
|
"TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||||
|
"Amount": "1000000000",
|
||||||
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
|
"Fee": 50,
|
||||||
|
"SigningPubKey": "",
|
||||||
|
"TransactionType": "Payment"
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"Missing field 'tx_json.Sequence'."}},
|
||||||
|
|
||||||
|
{ "Missing SigningPubKey in submit_multisigned.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"Signers": [
|
||||||
|
{
|
||||||
|
"Signer": {
|
||||||
|
"Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
|
||||||
|
"TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||||
|
"Amount": "1000000000",
|
||||||
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
|
"Fee": 50,
|
||||||
|
"Sequence": 0,
|
||||||
|
"TransactionType": "Payment"
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"Missing field 'tx_json.SigningPubKey'."}},
|
||||||
|
|
||||||
|
{ "Non-empty SigningPubKey in submit_multisigned.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"Signers": [
|
||||||
|
{
|
||||||
|
"Signer": {
|
||||||
|
"Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
|
||||||
|
"TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||||
|
"Amount": "1000000000",
|
||||||
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
|
"Fee": 50,
|
||||||
|
"Sequence": 0,
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8",
|
||||||
|
"TransactionType": "Payment"
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"When multi-signing 'tx_json.SigningPubKey' must be empty."}},
|
||||||
|
|
||||||
|
{ "Missing TransactionType in submit_multisigned.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"Signers": [
|
||||||
|
{
|
||||||
|
"Signer": {
|
||||||
|
"Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
|
||||||
|
"TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||||
|
"Amount": "1000000000",
|
||||||
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
|
"Fee": 50,
|
||||||
|
"Sequence": 0,
|
||||||
|
"SigningPubKey": "",
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"Missing field 'tx_json.TransactionType'."}},
|
||||||
|
|
||||||
|
{ "Missing Account in submit_multisigned.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"Signers": [
|
||||||
|
{
|
||||||
|
"Signer": {
|
||||||
|
"Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
|
||||||
|
"TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tx_json": {
|
||||||
|
"Amount": "1000000000",
|
||||||
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
|
"Fee": 50,
|
||||||
|
"Sequence": 0,
|
||||||
|
"SigningPubKey": "",
|
||||||
|
"TransactionType": "Payment"
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"Missing field 'tx_json.Account'."}},
|
||||||
|
|
||||||
|
{ "Malformed Account in submit_multisigned.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"Signers": [
|
||||||
|
{
|
||||||
|
"Signer": {
|
||||||
|
"Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
|
||||||
|
"TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "NotAnAccount",
|
||||||
|
"Amount": "1000000000",
|
||||||
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
|
"Fee": 50,
|
||||||
|
"Sequence": 0,
|
||||||
|
"SigningPubKey": "",
|
||||||
|
"TransactionType": "Payment"
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"Invalid field 'tx_json.Account'."}},
|
||||||
|
|
||||||
|
{ "Account not in ledger in submit_multisigned.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"Signers": [
|
||||||
|
{
|
||||||
|
"Signer": {
|
||||||
|
"Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
|
||||||
|
"TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rDg53Haik2475DJx8bjMDSDPj4VX7htaMd",
|
||||||
|
"Amount": "1000000000",
|
||||||
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
|
"Fee": 50,
|
||||||
|
"Sequence": 0,
|
||||||
|
"SigningPubKey": "",
|
||||||
|
"TransactionType": "Payment"
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"Source account not found."}},
|
||||||
|
|
||||||
|
{ "Missing Fee in submit_multisigned.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"Signers": [
|
||||||
|
{
|
||||||
|
"Signer": {
|
||||||
|
"Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
|
||||||
|
"TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||||
|
"Amount": "1000000000",
|
||||||
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
|
"Sequence": 0,
|
||||||
|
"SigningPubKey": "",
|
||||||
|
"TransactionType": "Payment"
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"Missing field 'tx_json.Fee'."}},
|
||||||
|
|
||||||
|
{ "Non-numeric Fee in submit_multisigned.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"Signers": [
|
||||||
|
{
|
||||||
|
"Signer": {
|
||||||
|
"Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
|
||||||
|
"TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||||
|
"Amount": "1000000000",
|
||||||
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
|
"Fee": 50.1,
|
||||||
|
"Sequence": 0,
|
||||||
|
"SigningPubKey": "",
|
||||||
|
"TransactionType": "Payment"
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"Field 'tx_json.Fee' has invalid data."}},
|
||||||
|
|
||||||
|
{ "Missing Amount in submit_multisigned Payment.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"Signers": [
|
||||||
|
{
|
||||||
|
"Signer": {
|
||||||
|
"Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
|
||||||
|
"TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||||
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
|
"Fee": 50000000,
|
||||||
|
"Sequence": 0,
|
||||||
|
"SigningPubKey": "",
|
||||||
|
"TransactionType": "Payment"
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"Missing field 'tx_json.Amount'."}},
|
||||||
|
|
||||||
|
{ "Invalid Amount in submit_multisigned Payment.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"Signers": [
|
||||||
|
{
|
||||||
|
"Signer": {
|
||||||
|
"Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
|
||||||
|
"TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||||
|
"Amount": "NotANumber",
|
||||||
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
|
"Fee": 50,
|
||||||
|
"Sequence": 0,
|
||||||
|
"SigningPubKey": "",
|
||||||
|
"TransactionType": "Payment"
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"Invalid field 'tx_json.Amount'."}},
|
||||||
|
|
||||||
|
{ "No build_path in submit_multisigned.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"build_path": 1,
|
||||||
|
"Signers": [
|
||||||
|
{
|
||||||
|
"Signer": {
|
||||||
|
"Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
|
||||||
|
"TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||||
|
"Amount": "1000000000",
|
||||||
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
|
"Fee": 50,
|
||||||
|
"Sequence": 0,
|
||||||
|
"SigningPubKey": "",
|
||||||
|
"TransactionType": "Payment"
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"Field 'build_path' not allowed in this context."}},
|
||||||
|
|
||||||
|
{ "Missing Destination in submit_multisigned Payment.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"Signers": [
|
||||||
|
{
|
||||||
|
"Signer": {
|
||||||
|
"Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
|
||||||
|
"TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||||
|
"Amount": "1000000000",
|
||||||
|
"Fee": 50,
|
||||||
|
"Sequence": 0,
|
||||||
|
"SigningPubKey": "",
|
||||||
|
"TransactionType": "Payment"
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"Missing field 'tx_json.Destination'."}},
|
||||||
|
|
||||||
|
{ "Malformed Destination in submit_multisigned Payment.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"Signers": [
|
||||||
|
{
|
||||||
|
"Signer": {
|
||||||
|
"Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
|
||||||
|
"TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||||
|
"Amount": "1000000000",
|
||||||
|
"Destination": "NotADestination",
|
||||||
|
"Fee": 50,
|
||||||
|
"Sequence": 0,
|
||||||
|
"SigningPubKey": "",
|
||||||
|
"TransactionType": "Payment"
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"Invalid field 'tx_json.Destination'."}},
|
||||||
|
|
||||||
|
{ "Missing Signers field in submit_multisigned.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||||
|
"Amount": "1000000000",
|
||||||
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
|
"Fee": 50,
|
||||||
|
"Sequence": 0,
|
||||||
|
"SigningPubKey": "",
|
||||||
|
"TransactionType": "Payment"
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"Missing field 'Signers'."}},
|
||||||
|
|
||||||
|
{ "Signers not an array in submit_multisigned.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"Signers": {
|
||||||
|
"Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
|
||||||
|
"TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
|
||||||
|
},
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||||
|
"Amount": "1000000000",
|
||||||
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
|
"Fee": 50,
|
||||||
|
"Sequence": 0,
|
||||||
|
"SigningPubKey": "",
|
||||||
|
"TransactionType": "Payment"
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"Expected Signers to be an array."}},
|
||||||
|
|
||||||
|
{ "Empty Signers array in submit_multisigned.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"Signers": [
|
||||||
|
],
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||||
|
"Amount": "1000000000",
|
||||||
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
|
"Fee": 50,
|
||||||
|
"Sequence": 0,
|
||||||
|
"SigningPubKey": "",
|
||||||
|
"TransactionType": "Payment"
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"Signers array may not be empty."}},
|
||||||
|
|
||||||
|
{ "Duplicate Signer in submit_multisigned.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"Signers": [
|
||||||
|
{
|
||||||
|
"Signer": {
|
||||||
|
"Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
|
||||||
|
"TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Signer": {
|
||||||
|
"Account": "rPcNzota6B8YBokhYtcTNqQVCngtbnWfux",
|
||||||
|
"TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||||
|
"Amount": "1000000000",
|
||||||
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
|
"Fee": 50,
|
||||||
|
"Sequence": 0,
|
||||||
|
"SigningPubKey": "",
|
||||||
|
"TransactionType": "Payment"
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"Duplicate Signers:Signer:Account entries (rPcNzota6B8YBokhYtcTNqQVCngtbnWfux) are not allowed."}},
|
||||||
|
|
||||||
|
{ "Signer is tx_json Account in submit_multisigned.",
|
||||||
|
R"({
|
||||||
|
"command": "submit_multisigned",
|
||||||
|
"Signers": [
|
||||||
|
{
|
||||||
|
"Signer": {
|
||||||
|
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||||
|
"TxnSignature": "3045022100F9ED357606932697A4FAB2BE7F222C21DD93CA4CFDD90357AADD07465E8457D6022038173193E3DFFFB5D78DD738CC0905395F885DA65B98FDB9793901FE3FD26ECE",
|
||||||
|
"SigningPubKey": "02FE36A690D6973D55F88553F5D2C4202DE75F2CF8A6D0E17C70AC223F044501F8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh",
|
||||||
|
"Amount": "1000000000",
|
||||||
|
"Destination": "rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA",
|
||||||
|
"Fee": 50,
|
||||||
|
"Sequence": 0,
|
||||||
|
"SigningPubKey": "",
|
||||||
|
"TransactionType": "Payment"
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
{
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'secret'.",
|
||||||
|
"Missing field 'account'.",
|
||||||
|
"A Signer may not be the transaction's Account (rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh)."}},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -866,19 +1397,16 @@ public:
|
|||||||
void testAutoFillFees ()
|
void testAutoFillFees ()
|
||||||
{
|
{
|
||||||
Config const config;
|
Config const config;
|
||||||
auto const ledger =
|
std::shared_ptr<const ReadView> ledger =
|
||||||
std::make_shared<Ledger>(
|
std::make_shared<Ledger>(create_genesis, config);
|
||||||
create_genesis, config);
|
LoadFeeTrack const feeTrack;
|
||||||
|
|
||||||
using namespace detail;
|
|
||||||
TxnSignApiFacade apiFacade (TxnSignApiFacade::noNetOPs, ledger);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
Json::Value req;
|
Json::Value req;
|
||||||
Json::Reader ().parse (
|
Json::Reader ().parse (
|
||||||
"{ \"fee_mult_max\" : 1, \"tx_json\" : { } } ", req);
|
"{ \"fee_mult_max\" : 1, \"tx_json\" : { } } ", req);
|
||||||
Json::Value result =
|
Json::Value result =
|
||||||
checkFee (req, apiFacade, Role::ADMIN, AutoFill::might);
|
checkFee (req, Role::ADMIN, true, feeTrack, ledger);
|
||||||
|
|
||||||
expect (! RPC::contains_error (result), "Legal checkFee");
|
expect (! RPC::contains_error (result), "Legal checkFee");
|
||||||
}
|
}
|
||||||
@@ -888,30 +1416,72 @@ public:
|
|||||||
Json::Reader ().parse (
|
Json::Reader ().parse (
|
||||||
"{ \"fee_mult_max\" : 0, \"tx_json\" : { } } ", req);
|
"{ \"fee_mult_max\" : 0, \"tx_json\" : { } } ", req);
|
||||||
Json::Value result =
|
Json::Value result =
|
||||||
checkFee (req, apiFacade, Role::ADMIN, AutoFill::might);
|
checkFee (req, Role::ADMIN, true, feeTrack, ledger);
|
||||||
|
|
||||||
expect (RPC::contains_error (result), "Invalid checkFee");
|
expect (RPC::contains_error (result), "Invalid checkFee");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A function that can be called as though it would process a transaction.
|
||||||
|
static void fakeProcessTransaction (
|
||||||
|
Transaction::pointer&, bool, bool, NetworkOPs::FailHard)
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
void testTransactionRPC ()
|
void testTransactionRPC ()
|
||||||
{
|
{
|
||||||
// A list of all the functions we want to test and their fail bits.
|
// Use jtx to set up a ledger so the tests will do the right thing.
|
||||||
using transactionFunc = Json::Value (*) (
|
test::jtx::Account const a {"a"}; // rnUy2SHTrB9DubsPmkJZUXTf5FcNDGrYEA
|
||||||
|
test::jtx::Account const g {"g"}; // rLPwWB1itaUGMV8kbMLLysjGkEpTM2Soy4
|
||||||
|
auto const USD = g["USD"];
|
||||||
|
// master is rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh.
|
||||||
|
// "b" (not in the ledger) is rDg53Haik2475DJx8bjMDSDPj4VX7htaMd.
|
||||||
|
// "c" (phantom signer) is rPcNzota6B8YBokhYtcTNqQVCngtbnWfux.
|
||||||
|
|
||||||
|
test::jtx::Env env(*this);
|
||||||
|
env.fund(test::jtx::XRP(100000), a, g);
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
env(trust(a, USD(1000)));
|
||||||
|
env(trust(env.master, USD(1000)));
|
||||||
|
env(pay(g, a, USD(50)));
|
||||||
|
env(pay(g, env.master, USD(50)));
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
auto const ledger = env.open();
|
||||||
|
|
||||||
|
LoadFeeTrack const feeTrack;
|
||||||
|
|
||||||
|
ProcessTransactionFn processTxn = fakeProcessTransaction;
|
||||||
|
|
||||||
|
// A list of all the functions we want to test.
|
||||||
|
using signFunc = Json::Value (*) (
|
||||||
Json::Value params,
|
Json::Value params,
|
||||||
NetworkOPs::FailHard failType,
|
NetworkOPs::FailHard failType,
|
||||||
detail::TxnSignApiFacade& apiFacade,
|
Role role,
|
||||||
Role role);
|
int validatedLedgerAge,
|
||||||
|
LoadFeeTrack const& feeTrack,
|
||||||
|
std::shared_ptr<ReadView const> ledger);
|
||||||
|
|
||||||
|
using submitFunc = Json::Value (*) (
|
||||||
|
Json::Value params,
|
||||||
|
NetworkOPs::FailHard failType,
|
||||||
|
Role role,
|
||||||
|
int validatedLedgerAge,
|
||||||
|
LoadFeeTrack const& feeTrack,
|
||||||
|
std::shared_ptr<ReadView const> ledger,
|
||||||
|
ProcessTransactionFn const& processTransaction);
|
||||||
|
|
||||||
using TestStuff =
|
using TestStuff =
|
||||||
std::tuple <transactionFunc, char const*, unsigned int>;
|
std::tuple <signFunc, submitFunc, char const*, unsigned int>;
|
||||||
|
|
||||||
static TestStuff const testFuncs [] =
|
static TestStuff const testFuncs [] =
|
||||||
{
|
{
|
||||||
TestStuff {transactionSign, "sign", 0},
|
TestStuff {transactionSign, nullptr, "sign", 0},
|
||||||
TestStuff {transactionSubmit, "submit", 1},
|
TestStuff {nullptr, transactionSubmit, "submit", 1},
|
||||||
TestStuff {transactionSignFor, "sign_for", 2},
|
TestStuff {transactionSignFor, nullptr, "sign_for", 2},
|
||||||
TestStuff {transactionSubmitMultiSigned, "submit_multisigned", 3}
|
TestStuff {nullptr, transactionSubmitMultiSigned, "submit_multisigned", 3}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto testFunc : testFuncs)
|
for (auto testFunc : testFuncs)
|
||||||
@@ -930,24 +1500,41 @@ public:
|
|||||||
|
|
||||||
for (Role testRole : testedRoles)
|
for (Role testRole : testedRoles)
|
||||||
{
|
{
|
||||||
// Mock so we can run without a ledger.
|
Json::Value result;
|
||||||
detail::TxnSignApiFacade apiFacade (
|
auto const signFn = get<0>(testFunc);
|
||||||
detail::TxnSignApiFacade::noNetOPs);
|
if (signFn != nullptr)
|
||||||
|
{
|
||||||
Json::Value result = get<0>(testFunc) (
|
assert (get<1>(testFunc) == nullptr);
|
||||||
|
result = signFn (
|
||||||
req,
|
req,
|
||||||
NetworkOPs::FailHard::yes,
|
NetworkOPs::FailHard::yes,
|
||||||
apiFacade,
|
testRole,
|
||||||
testRole);
|
1,
|
||||||
|
feeTrack,
|
||||||
|
ledger);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto const submitFn = get<1>(testFunc);
|
||||||
|
assert (submitFn != nullptr);
|
||||||
|
result = submitFn (
|
||||||
|
req,
|
||||||
|
NetworkOPs::FailHard::yes,
|
||||||
|
testRole,
|
||||||
|
1,
|
||||||
|
feeTrack,
|
||||||
|
ledger,
|
||||||
|
processTxn);
|
||||||
|
}
|
||||||
|
|
||||||
std::string errStr;
|
std::string errStr;
|
||||||
if (RPC::contains_error (result))
|
if (RPC::contains_error (result))
|
||||||
errStr = result["error_message"].asString ();
|
errStr = result["error_message"].asString ();
|
||||||
|
|
||||||
std::string const expStr (txnTest.expMsg[get<2>(testFunc)]);
|
std::string const expStr (txnTest.expMsg[get<3>(testFunc)]);
|
||||||
expect (errStr == expStr,
|
expect (errStr == expStr,
|
||||||
"Expected: \"" + expStr + "\"\n Got: \"" + errStr +
|
"Expected: \"" + expStr + "\"\n Got: \"" + errStr +
|
||||||
"\"\nIn " + std::string (get<1>(testFunc)) +
|
"\"\nIn " + std::string (get<2>(testFunc)) +
|
||||||
": " + txnTest.description);
|
": " + txnTest.description);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user