mirror of
https://github.com/XRPLF/clio.git
synced 2025-12-06 17:27:58 +00:00
@@ -165,6 +165,7 @@ target_sources (clio PRIVATE
|
||||
src/util/Random.cpp
|
||||
src/util/Taggable.cpp
|
||||
src/util/TerminationHandler.cpp
|
||||
src/util/TxUtil.cpp
|
||||
)
|
||||
|
||||
# Clio server
|
||||
@@ -190,6 +191,7 @@ if (tests)
|
||||
unittests/util/TestGlobals.cpp
|
||||
unittests/util/AssertTests.cpp
|
||||
unittests/util/BatchingTests.cpp
|
||||
unittests/util/TxUtilTests.cpp
|
||||
unittests/util/TestObject.cpp
|
||||
unittests/util/StringUtils.cpp
|
||||
unittests/util/prometheus/CounterTests.cpp
|
||||
|
||||
@@ -39,68 +39,17 @@
|
||||
#include <ripple/protocol/AccountID.h>
|
||||
#include <ripple/protocol/ErrorCodes.h>
|
||||
#include <ripple/protocol/LedgerHeader.h>
|
||||
#include <ripple/protocol/TxFormats.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
|
||||
namespace rpc {
|
||||
|
||||
// found here : https://xrpl.org/transaction-types.html
|
||||
std::unordered_map<std::string, ripple::TxType> const AccountTxHandler::TYPESMAP{
|
||||
{JSL(AccountSet), ripple::ttACCOUNT_SET},
|
||||
{JSL(AccountDelete), ripple::ttACCOUNT_DELETE},
|
||||
{JSL(AMMBid), ripple::ttAMM_BID},
|
||||
{JSL(AMMCreate), ripple::ttAMM_CREATE},
|
||||
{JSL(AMMDelete), ripple::ttAMM_DELETE},
|
||||
{JSL(AMMDeposit), ripple::ttAMM_DEPOSIT},
|
||||
{JSL(AMMVote), ripple::ttAMM_VOTE},
|
||||
{JSL(AMMWithdraw), ripple::ttAMM_WITHDRAW},
|
||||
{JSL(CheckCancel), ripple::ttCHECK_CANCEL},
|
||||
{JSL(CheckCash), ripple::ttCHECK_CASH},
|
||||
{JSL(CheckCreate), ripple::ttCHECK_CREATE},
|
||||
{JSL(Clawback), ripple::ttCLAWBACK},
|
||||
{JSL(DepositPreauth), ripple::ttDEPOSIT_PREAUTH},
|
||||
{JSL(EscrowCancel), ripple::ttESCROW_CANCEL},
|
||||
{JSL(EscrowCreate), ripple::ttESCROW_CREATE},
|
||||
{JSL(EscrowFinish), ripple::ttESCROW_FINISH},
|
||||
{JSL(NFTokenAcceptOffer), ripple::ttNFTOKEN_ACCEPT_OFFER},
|
||||
{JSL(NFTokenBurn), ripple::ttNFTOKEN_BURN},
|
||||
{JSL(NFTokenCancelOffer), ripple::ttNFTOKEN_CANCEL_OFFER},
|
||||
{JSL(NFTokenCreateOffer), ripple::ttNFTOKEN_CREATE_OFFER},
|
||||
{JSL(NFTokenMint), ripple::ttNFTOKEN_MINT},
|
||||
{JSL(OfferCancel), ripple::ttOFFER_CANCEL},
|
||||
{JSL(OfferCreate), ripple::ttOFFER_CREATE},
|
||||
{JSL(Payment), ripple::ttPAYMENT},
|
||||
{JSL(PaymentChannelClaim), ripple::ttPAYCHAN_CLAIM},
|
||||
{JSL(PaymentChannelCreate), ripple::ttCHECK_CREATE},
|
||||
{JSL(PaymentChannelFund), ripple::ttPAYCHAN_FUND},
|
||||
{JSL(SetRegularKey), ripple::ttREGULAR_KEY_SET},
|
||||
{JSL(SignerListSet), ripple::ttSIGNER_LIST_SET},
|
||||
{JSL(TicketCreate), ripple::ttTICKET_CREATE},
|
||||
{JSL(TrustSet), ripple::ttTRUST_SET},
|
||||
{JSL(DIDSet), ripple::ttDID_SET},
|
||||
{JSL(DIDDelete), ripple::ttDID_DELETE},
|
||||
};
|
||||
|
||||
// TODO: should be std::views::keys when clang supports it
|
||||
std::unordered_set<std::string> const AccountTxHandler::TYPES_KEYS = [] {
|
||||
std::unordered_set<std::string> keys;
|
||||
std::transform(TYPESMAP.begin(), TYPESMAP.end(), std::inserter(keys, keys.begin()), [](auto const& pair) {
|
||||
return pair.first;
|
||||
});
|
||||
return keys;
|
||||
}();
|
||||
|
||||
// TODO: this is currently very similar to nft_history but its own copy for time
|
||||
// being. we should aim to reuse common logic in some way in the future.
|
||||
AccountTxHandler::Result
|
||||
@@ -197,19 +146,13 @@ AccountTxHandler::process(AccountTxHandler::Input input, Context const& ctx) con
|
||||
|
||||
boost::json::object obj;
|
||||
|
||||
// if binary is true or transactionType is specified, we need to expand the transaction
|
||||
if (!input.binary || input.transactionType.has_value()) {
|
||||
// if binary is false or transactionType is specified, we need to expand the transaction
|
||||
if (!input.binary || input.transactionTypeInLowercase.has_value()) {
|
||||
auto [txn, meta] = toExpandedJson(txnPlusMeta, ctx.apiVersion, NFTokenjson::ENABLE);
|
||||
|
||||
if (txn.contains(JS(TransactionType))) {
|
||||
auto const objTransactionType = txn[JS(TransactionType)];
|
||||
auto const strType = util::toLower(objTransactionType.as_string().c_str());
|
||||
|
||||
// if transactionType does not match
|
||||
if (input.transactionType.has_value() && AccountTxHandler::TYPESMAP.contains(strType) &&
|
||||
AccountTxHandler::TYPESMAP.at(strType) != input.transactionType.value())
|
||||
continue;
|
||||
}
|
||||
if (txn.contains(JS(TransactionType)) && input.transactionTypeInLowercase.has_value() &&
|
||||
util::toLower(txn[JS(TransactionType)].as_string().c_str()) != input.transactionTypeInLowercase.value())
|
||||
continue;
|
||||
|
||||
if (!input.binary) {
|
||||
auto const txKey = ctx.apiVersion < 2u ? JS(tx) : JS(tx_json);
|
||||
@@ -324,10 +267,8 @@ tag_invoke(boost::json::value_to_tag<AccountTxHandler::Input>, boost::json::valu
|
||||
};
|
||||
}
|
||||
|
||||
if (jsonObject.contains("tx_type")) {
|
||||
auto objTransactionType = jsonObject.at("tx_type");
|
||||
input.transactionType = AccountTxHandler::TYPESMAP.at(objTransactionType.as_string().c_str());
|
||||
}
|
||||
if (jsonObject.contains("tx_type"))
|
||||
input.transactionTypeInLowercase = jsonObject.at("tx_type").as_string().c_str();
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
@@ -20,14 +20,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "data/BackendInterface.h"
|
||||
#include "rpc/RPCHelpers.h"
|
||||
#include "rpc/Errors.h"
|
||||
#include "rpc/JS.h"
|
||||
#include "rpc/common/JsonBool.h"
|
||||
#include "rpc/common/MetaProcessors.h"
|
||||
#include "rpc/common/Modifiers.h"
|
||||
#include "rpc/common/Types.h"
|
||||
#include "rpc/common/Validators.h"
|
||||
#include "util/TxUtil.h"
|
||||
#include "util/log/Logger.h"
|
||||
|
||||
#include <boost/json/array.hpp>
|
||||
#include <boost/json/conversion.hpp>
|
||||
#include <boost/json/object.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
#include <ripple/protocol/ErrorCodes.h>
|
||||
#include <ripple/protocol/TxFormats.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace rpc {
|
||||
|
||||
/**
|
||||
@@ -39,9 +56,6 @@ class AccountTxHandler {
|
||||
util::Logger log_{"RPC"};
|
||||
std::shared_ptr<BackendInterface> sharedPtrBackend_;
|
||||
|
||||
static std::unordered_map<std::string, ripple::TxType> const TYPESMAP;
|
||||
static std::unordered_set<std::string> const TYPES_KEYS;
|
||||
|
||||
public:
|
||||
// no max limit
|
||||
static auto constexpr LIMIT_MIN = 1;
|
||||
@@ -77,7 +91,7 @@ public:
|
||||
JsonBool forward{false};
|
||||
std::optional<uint32_t> limit;
|
||||
std::optional<Marker> marker;
|
||||
std::optional<ripple::TxType> transactionType;
|
||||
std::optional<std::string> transactionTypeInLowercase;
|
||||
};
|
||||
|
||||
using Result = HandlerReturnType<Output>;
|
||||
@@ -89,6 +103,7 @@ public:
|
||||
static RpcSpecConstRef
|
||||
spec([[maybe_unused]] uint32_t apiVersion)
|
||||
{
|
||||
auto const& typesKeysInLowercase = util::getTxTypesInLowercase();
|
||||
static auto const rpcSpecForV1 = RpcSpec{
|
||||
{JS(account), validation::Required{}, validation::AccountValidator},
|
||||
{JS(ledger_hash), validation::Uint256HexStringValidator},
|
||||
@@ -112,7 +127,7 @@ public:
|
||||
"tx_type",
|
||||
validation::Type<std::string>{},
|
||||
modifiers::ToLower{},
|
||||
validation::OneOf<std::string>(TYPES_KEYS.cbegin(), TYPES_KEYS.cend()),
|
||||
validation::OneOf<std::string>(typesKeysInLowercase.cbegin(), typesKeysInLowercase.cend()),
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
47
src/util/TxUtil.cpp
Normal file
47
src/util/TxUtil.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of clio: https://github.com/XRPLF/clio
|
||||
Copyright (c) 2024, the clio developers.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include "util/JsonUtils.h"
|
||||
|
||||
#include <ripple/protocol/TxFormats.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace util {
|
||||
|
||||
std::unordered_set<std::string> const&
|
||||
getTxTypesInLowercase()
|
||||
{
|
||||
static std::unordered_set<std::string> const typesKeysInLowercase = []() {
|
||||
std::unordered_set<std::string> keys;
|
||||
std::transform(
|
||||
ripple::TxFormats::getInstance().begin(),
|
||||
ripple::TxFormats::getInstance().end(),
|
||||
std::inserter(keys, keys.begin()),
|
||||
[](auto const& pair) { return util::toLower(pair.getName()); }
|
||||
);
|
||||
return keys;
|
||||
}();
|
||||
|
||||
return typesKeysInLowercase;
|
||||
}
|
||||
} // namespace util
|
||||
28
src/util/TxUtil.h
Normal file
28
src/util/TxUtil.h
Normal file
@@ -0,0 +1,28 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of clio: https://github.com/XRPLF/clio
|
||||
Copyright (c) 2024, the clio developers.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace util {
|
||||
std::unordered_set<std::string> const&
|
||||
getTxTypesInLowercase();
|
||||
} // namespace util
|
||||
@@ -81,88 +81,88 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
},
|
||||
AccountTxParamTestCaseBundle{
|
||||
"BinaryNotBool",
|
||||
R"({"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "binary": 1})",
|
||||
R"({"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "binary": 1})",
|
||||
"invalidParams",
|
||||
"Invalid parameters."
|
||||
},
|
||||
AccountTxParamTestCaseBundle{
|
||||
"BinaryNotBool_API_v1",
|
||||
R"({"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "binary": 1})",
|
||||
R"({"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "binary": 1})",
|
||||
std::nullopt,
|
||||
std::nullopt,
|
||||
1u
|
||||
},
|
||||
AccountTxParamTestCaseBundle{
|
||||
"ForwardNotBool",
|
||||
R"({"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "forward": 1})",
|
||||
R"({"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "forward": 1})",
|
||||
"invalidParams",
|
||||
"Invalid parameters."
|
||||
},
|
||||
AccountTxParamTestCaseBundle{
|
||||
"ForwardNotBool_API_v1",
|
||||
R"({"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "forward": 1})",
|
||||
R"({"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "forward": 1})",
|
||||
std::nullopt,
|
||||
std::nullopt,
|
||||
1u
|
||||
},
|
||||
AccountTxParamTestCaseBundle{
|
||||
"ledger_index_minNotInt",
|
||||
R"({"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "ledger_index_min": "x"})",
|
||||
R"({"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "ledger_index_min": "x"})",
|
||||
"invalidParams",
|
||||
"Invalid parameters."
|
||||
},
|
||||
AccountTxParamTestCaseBundle{
|
||||
"ledger_index_maxNotInt",
|
||||
R"({"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "ledger_index_max": "x"})",
|
||||
R"({"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "ledger_index_max": "x"})",
|
||||
"invalidParams",
|
||||
"Invalid parameters."
|
||||
},
|
||||
AccountTxParamTestCaseBundle{
|
||||
"ledger_indexInvalid",
|
||||
R"({"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "ledger_index": "x"})",
|
||||
R"({"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "ledger_index": "x"})",
|
||||
"invalidParams",
|
||||
"ledgerIndexMalformed"
|
||||
},
|
||||
AccountTxParamTestCaseBundle{
|
||||
"ledger_hashInvalid",
|
||||
R"({"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "ledger_hash": "x"})",
|
||||
R"({"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "ledger_hash": "x"})",
|
||||
"invalidParams",
|
||||
"ledger_hashMalformed"
|
||||
},
|
||||
AccountTxParamTestCaseBundle{
|
||||
"ledger_hashNotString",
|
||||
R"({"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "ledger_hash": 123})",
|
||||
R"({"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "ledger_hash": 123})",
|
||||
"invalidParams",
|
||||
"ledger_hashNotString"
|
||||
},
|
||||
AccountTxParamTestCaseBundle{
|
||||
"limitNotInt",
|
||||
R"({"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "limit": "123"})",
|
||||
R"({"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "limit": "123"})",
|
||||
"invalidParams",
|
||||
"Invalid parameters."
|
||||
},
|
||||
AccountTxParamTestCaseBundle{
|
||||
"limitNegative",
|
||||
R"({"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "limit": -1})",
|
||||
R"({"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "limit": -1})",
|
||||
"invalidParams",
|
||||
"Invalid parameters."
|
||||
},
|
||||
AccountTxParamTestCaseBundle{
|
||||
"limitZero",
|
||||
R"({"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "limit": 0})",
|
||||
R"({"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "limit": 0})",
|
||||
"invalidParams",
|
||||
"Invalid parameters."
|
||||
},
|
||||
AccountTxParamTestCaseBundle{
|
||||
"MarkerNotObject",
|
||||
R"({"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "marker": 101})",
|
||||
R"({"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "marker": 101})",
|
||||
"invalidParams",
|
||||
"invalidMarker"
|
||||
},
|
||||
AccountTxParamTestCaseBundle{
|
||||
"MarkerMissingSeq",
|
||||
R"({
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"marker": {"ledger": 123}
|
||||
})",
|
||||
"invalidParams",
|
||||
@@ -171,8 +171,8 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
AccountTxParamTestCaseBundle{
|
||||
"MarkerMissingLedger",
|
||||
R"({
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"marker":{"seq": 123}
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"marker": {"seq": 123}
|
||||
})",
|
||||
"invalidParams",
|
||||
"Required field 'ledger' missing"
|
||||
@@ -180,7 +180,7 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
AccountTxParamTestCaseBundle{
|
||||
"MarkerLedgerNotInt",
|
||||
R"({
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"marker":
|
||||
{
|
||||
"seq": "string",
|
||||
@@ -193,7 +193,7 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
AccountTxParamTestCaseBundle{
|
||||
"MarkerSeqNotInt",
|
||||
R"({
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"marker":
|
||||
{
|
||||
"ledger": "string",
|
||||
@@ -206,7 +206,7 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
AccountTxParamTestCaseBundle{
|
||||
"LedgerIndexMinLessThanMinSeq",
|
||||
R"({
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index_min": 9
|
||||
})",
|
||||
"lgrIdxMalformed",
|
||||
@@ -215,7 +215,7 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
AccountTxParamTestCaseBundle{
|
||||
"LedgerIndexMaxLargeThanMaxSeq",
|
||||
R"({
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index_max": 31
|
||||
})",
|
||||
"lgrIdxMalformed",
|
||||
@@ -224,7 +224,7 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
AccountTxParamTestCaseBundle{
|
||||
"LedgerIndexMaxLargeThanMaxSeq_API_v1",
|
||||
R"({
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index_max": 31
|
||||
})",
|
||||
std::nullopt,
|
||||
@@ -234,7 +234,7 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
AccountTxParamTestCaseBundle{
|
||||
"LedgerIndexMaxSmallerThanMinSeq",
|
||||
R"({
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index_max": 9
|
||||
})",
|
||||
"lgrIdxMalformed",
|
||||
@@ -243,7 +243,7 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
AccountTxParamTestCaseBundle{
|
||||
"LedgerIndexMaxSmallerThanMinSeq_API_v1",
|
||||
R"({
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index_max": 9
|
||||
})",
|
||||
"lgrIdxsInvalid",
|
||||
@@ -253,7 +253,7 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
AccountTxParamTestCaseBundle{
|
||||
"LedgerIndexMinSmallerThanMinSeq",
|
||||
R"({
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index_min": 9
|
||||
})",
|
||||
"lgrIdxMalformed",
|
||||
@@ -262,7 +262,7 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
AccountTxParamTestCaseBundle{
|
||||
"LedgerIndexMinSmallerThanMinSeq_API_v1",
|
||||
R"({
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index_min": 9
|
||||
})",
|
||||
std::nullopt,
|
||||
@@ -272,7 +272,7 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
AccountTxParamTestCaseBundle{
|
||||
"LedgerIndexMinLargerThanMaxSeq",
|
||||
R"({
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index_min": 31
|
||||
})",
|
||||
"lgrIdxMalformed",
|
||||
@@ -281,7 +281,7 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
AccountTxParamTestCaseBundle{
|
||||
"LedgerIndexMinLargerThanMaxSeq_API_v1",
|
||||
R"({
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index_min": 31
|
||||
})",
|
||||
"lgrIdxsInvalid",
|
||||
@@ -291,7 +291,7 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
AccountTxParamTestCaseBundle{
|
||||
"LedgerIndexMaxLessThanLedgerIndexMin",
|
||||
R"({
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index_max": 11,
|
||||
"ledger_index_min": 20
|
||||
})",
|
||||
@@ -301,7 +301,7 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
AccountTxParamTestCaseBundle{
|
||||
"LedgerIndexMaxLessThanLedgerIndexMin_API_v1",
|
||||
R"({
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index_max": 11,
|
||||
"ledger_index_min": 20
|
||||
})",
|
||||
@@ -312,7 +312,7 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
AccountTxParamTestCaseBundle{
|
||||
"LedgerIndexMaxMinAndLedgerIndex",
|
||||
R"({
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index_max": 20,
|
||||
"ledger_index_min": 11,
|
||||
"ledger_index": 10
|
||||
@@ -323,7 +323,7 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
AccountTxParamTestCaseBundle{
|
||||
"LedgerIndexMaxMinAndLedgerIndexValidated",
|
||||
R"({
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index_max": 20,
|
||||
"ledger_index_min": 11,
|
||||
"ledger_index": "validated"
|
||||
@@ -334,7 +334,7 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
AccountTxParamTestCaseBundle{
|
||||
"LedgerIndexMaxMinAndLedgerIndex_API_v1",
|
||||
R"({
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index_max": 20,
|
||||
"ledger_index_min": 11,
|
||||
"ledger_index": 10
|
||||
@@ -347,7 +347,7 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
"LedgerIndexMaxMinAndLedgerHash",
|
||||
fmt::format(
|
||||
R"({{
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index_max": 20,
|
||||
"ledger_index_min": 11,
|
||||
"ledger_hash": "{}"
|
||||
@@ -361,7 +361,7 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
"LedgerIndexMaxMinAndLedgerHash_API_v1",
|
||||
fmt::format(
|
||||
R"({{
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index_max": 20,
|
||||
"ledger_index_min": 11,
|
||||
"ledger_hash": "{}"
|
||||
@@ -375,7 +375,7 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
AccountTxParamTestCaseBundle{
|
||||
"LedgerIndexMaxMinAndLedgerIndexValidated_API_v1",
|
||||
R"({
|
||||
"account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index_max": 20,
|
||||
"ledger_index_min": 11,
|
||||
"ledger_index": "validated"
|
||||
@@ -384,6 +384,15 @@ struct AccountTxParameterTest : public RPCAccountTxHandlerTest,
|
||||
std::nullopt,
|
||||
1u
|
||||
},
|
||||
AccountTxParamTestCaseBundle{
|
||||
"InvalidTxType",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"tx_type": "unknow"
|
||||
})",
|
||||
"invalidParams",
|
||||
"Invalid field 'tx_type'."
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -1839,6 +1848,58 @@ generateTransactionTypeTestValues()
|
||||
])",
|
||||
1u
|
||||
},
|
||||
AccountTxTransactionBundle{
|
||||
"Lowercase_Payment",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "payment"
|
||||
})",
|
||||
R"([
|
||||
{
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Balance": "22"
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||
"Balance": "23"
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot"
|
||||
}
|
||||
}],
|
||||
"TransactionIndex": 0,
|
||||
"TransactionResult": "tesSUCCESS",
|
||||
"delivered_amount": "unavailable"
|
||||
},
|
||||
"tx": {
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Amount": "1",
|
||||
"DeliverMax": "1",
|
||||
"Destination": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||
"Fee": "1",
|
||||
"Sequence": 32,
|
||||
"SigningPubKey": "74657374",
|
||||
"TransactionType": "Payment",
|
||||
"hash": "51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2",
|
||||
"ledger_index": 30,
|
||||
"inLedger": 30,
|
||||
"date": 1
|
||||
},
|
||||
"validated": true
|
||||
}
|
||||
])",
|
||||
1u
|
||||
},
|
||||
AccountTxTransactionBundle{
|
||||
"Payment_API_v2",
|
||||
R"({
|
||||
|
||||
43
unittests/util/TxUtilTests.cpp
Normal file
43
unittests/util/TxUtilTests.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of clio: https://github.com/XRPLF/clio
|
||||
Copyright (c) 2024, the clio developers.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include "util/JsonUtils.h"
|
||||
#include "util/TxUtil.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ripple/protocol/TxFormats.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
|
||||
TEST(TxUtilTests, txTypesInLowercase)
|
||||
{
|
||||
auto const& types = util::getTxTypesInLowercase();
|
||||
ASSERT_TRUE(
|
||||
std::size_t(std::distance(ripple::TxFormats::getInstance().begin(), ripple::TxFormats::getInstance().end())) ==
|
||||
types.size()
|
||||
);
|
||||
|
||||
std::for_each(
|
||||
ripple::TxFormats::getInstance().begin(),
|
||||
ripple::TxFormats::getInstance().end(),
|
||||
[&](auto const& pair) { EXPECT_TRUE(types.find(util::toLower(pair.getName())) != types.end()); }
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user