mirror of
https://github.com/XRPLF/clio.git
synced 2025-11-23 05:05:54 +00:00
Implement paychannel verify/authorize
This commit is contained in:
@@ -76,6 +76,8 @@ target_sources(reporting PRIVATE
|
|||||||
handlers/AccountCurrencies.cpp
|
handlers/AccountCurrencies.cpp
|
||||||
handlers/AccountOffers.cpp
|
handlers/AccountOffers.cpp
|
||||||
handlers/AccountObjects.cpp)
|
handlers/AccountObjects.cpp)
|
||||||
|
handlers/ChannelAuthorize.cpp
|
||||||
|
handlers/ChannelVerify.cpp)
|
||||||
|
|
||||||
|
|
||||||
message(${Boost_LIBRARIES})
|
message(${Boost_LIBRARIES})
|
||||||
|
|||||||
109
handlers/ChannelAuthorize.cpp
Normal file
109
handlers/ChannelAuthorize.cpp
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012-2014 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or 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 <ripple/basics/StringUtilities.h>
|
||||||
|
#include <ripple/protocol/ErrorCodes.h>
|
||||||
|
#include <ripple/protocol/PayChan.h>
|
||||||
|
#include <ripple/protocol/STAccount.h>
|
||||||
|
#include <ripple/protocol/jss.h>
|
||||||
|
#include <ripple/resource/Fees.h>
|
||||||
|
#include <handlers/RPCHelpers.h>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
void
|
||||||
|
serializePayChanAuthorization(
|
||||||
|
ripple::Serializer& msg,
|
||||||
|
ripple::uint256 const& key,
|
||||||
|
ripple::XRPAmount const& amt)
|
||||||
|
{
|
||||||
|
msg.add32(ripple::HashPrefix::paymentChannelClaim);
|
||||||
|
msg.addBitString(key);
|
||||||
|
msg.add64(amt.drops());
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::json::object
|
||||||
|
doChannelAuthorize(boost::json::object const& request)
|
||||||
|
{
|
||||||
|
boost::json::object response;
|
||||||
|
if(!request.contains("channel_id"))
|
||||||
|
{
|
||||||
|
response["error"] = "missing field channel_id";
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!request.contains("amount"))
|
||||||
|
{
|
||||||
|
response["error"] = "missing field amount";
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!request.contains("key_type") && !request.contains("secret"))
|
||||||
|
{
|
||||||
|
response["error"] = "missing field secret";
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::json::value error = nullptr;
|
||||||
|
auto const [pk, sk] = keypairFromRequst(request, error);
|
||||||
|
if (!error.is_null())
|
||||||
|
{
|
||||||
|
response["error"] = error;
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
ripple::uint256 channelId;
|
||||||
|
if (!channelId.parseHex(request.at("channel_id").as_string().c_str()))
|
||||||
|
{
|
||||||
|
response["error"] = "channel id malformed";
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!request.at("amount").is_string())
|
||||||
|
{
|
||||||
|
response["error"] = "channel amount malformed";
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto optDrops =
|
||||||
|
ripple::to_uint64(request.at("amount").as_string().c_str());
|
||||||
|
|
||||||
|
if (!optDrops)
|
||||||
|
{
|
||||||
|
response["error"] = "could not parse channel amount";
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint64_t drops = *optDrops;
|
||||||
|
|
||||||
|
ripple::Serializer msg;
|
||||||
|
ripple::serializePayChanAuthorization(msg, channelId, ripple::XRPAmount(drops));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto const buf = ripple::sign(pk, sk, msg.slice());
|
||||||
|
response["signature"] = ripple::strHex(buf);
|
||||||
|
}
|
||||||
|
catch (std::exception&)
|
||||||
|
{
|
||||||
|
response["error"] = "Exception occurred during signing.";
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
119
handlers/ChannelVerify.cpp
Normal file
119
handlers/ChannelVerify.cpp
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2012-2014 Ripple Labs Inc.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or 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 <ripple/basics/StringUtilities.h>
|
||||||
|
#include <ripple/protocol/ErrorCodes.h>
|
||||||
|
#include <ripple/protocol/PayChan.h>
|
||||||
|
#include <ripple/protocol/STAccount.h>
|
||||||
|
#include <ripple/protocol/jss.h>
|
||||||
|
#include <ripple/resource/Fees.h>
|
||||||
|
#include <handlers/RPCHelpers.h>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
boost::json::object
|
||||||
|
doChannelVerify(boost::json::object const& request)
|
||||||
|
{
|
||||||
|
boost::json::object response;
|
||||||
|
if(!request.contains("channel_id"))
|
||||||
|
{
|
||||||
|
response["error"] = "missing field channel_id";
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!request.contains("amount"))
|
||||||
|
{
|
||||||
|
response["error"] = "missing field amount";
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!request.contains("signature"))
|
||||||
|
{
|
||||||
|
response["error"] = "missing field signature";
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!request.contains("public_key"))
|
||||||
|
{
|
||||||
|
response["error"] = "missing field public_key";
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<ripple::PublicKey> pk;
|
||||||
|
{
|
||||||
|
std::string const strPk = request.at("public_key").as_string().c_str();
|
||||||
|
pk = ripple::parseBase58<ripple::PublicKey>(ripple::TokenType::AccountPublic, strPk);
|
||||||
|
|
||||||
|
if (!pk)
|
||||||
|
{
|
||||||
|
auto pkHex = ripple::strUnHex(strPk);
|
||||||
|
if (!pkHex)
|
||||||
|
{
|
||||||
|
response["error"] = "malformed public key";
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
auto const pkType = ripple::publicKeyType(ripple::makeSlice(*pkHex));
|
||||||
|
if (!pkType)
|
||||||
|
{
|
||||||
|
response["error"] = "invalid key type";
|
||||||
|
}
|
||||||
|
|
||||||
|
pk.emplace(ripple::makeSlice(*pkHex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ripple::uint256 channelId;
|
||||||
|
if (!channelId.parseHex(request.at("channel_id").as_string().c_str()))
|
||||||
|
{
|
||||||
|
response["error"] = "channel id malformed";
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto optDrops =
|
||||||
|
ripple::to_uint64(request.at("amount").as_string().c_str());
|
||||||
|
|
||||||
|
if (!optDrops)
|
||||||
|
{
|
||||||
|
response["error"] = "could not parse channel amount";
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint64_t drops = *optDrops;
|
||||||
|
|
||||||
|
if (!request.at("signature").is_string())
|
||||||
|
{
|
||||||
|
response["error"] = "signature must be type string";
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sig = ripple::strUnHex(request.at("signature").as_string().c_str());
|
||||||
|
|
||||||
|
if (!sig || !sig->size())
|
||||||
|
{
|
||||||
|
response["error"] = "Invalid signature";
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
ripple::Serializer msg;
|
||||||
|
ripple::serializePayChanAuthorization(msg, channelId, ripple::XRPAmount(drops));
|
||||||
|
|
||||||
|
response["signature_verified"] =
|
||||||
|
ripple::verify(*pk, msg.slice(), ripple::makeSlice(*sig), true);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
@@ -174,3 +174,163 @@ traverseOwnedNodes(
|
|||||||
|
|
||||||
return nextCursor;
|
return nextCursor;
|
||||||
}
|
}
|
||||||
|
boost::optional<ripple::Seed>
|
||||||
|
parseRippleLibSeed(boost::json::value const& value)
|
||||||
|
{
|
||||||
|
// ripple-lib encodes seed used to generate an Ed25519 wallet in a
|
||||||
|
// non-standard way. While rippled never encode seeds that way, we
|
||||||
|
// try to detect such keys to avoid user confusion.
|
||||||
|
if (!value.is_string())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto const result =
|
||||||
|
ripple::decodeBase58Token(value.as_string().c_str(), ripple::TokenType::None);
|
||||||
|
|
||||||
|
if (result.size() == 18 &&
|
||||||
|
static_cast<std::uint8_t>(result[0]) == std::uint8_t(0xE1) &&
|
||||||
|
static_cast<std::uint8_t>(result[1]) == std::uint8_t(0x4B))
|
||||||
|
return ripple::Seed(ripple::makeSlice(result.substr(2)));
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<ripple::PublicKey, ripple::SecretKey>
|
||||||
|
keypairFromRequst(boost::json::object const& request, boost::json::value& error)
|
||||||
|
{
|
||||||
|
bool const has_key_type = request.contains("key_type");
|
||||||
|
|
||||||
|
// All of the secret types we allow, but only one at a time.
|
||||||
|
// The array should be constexpr, but that makes Visual Studio unhappy.
|
||||||
|
static std::string const secretTypes[]{
|
||||||
|
"passphrase",
|
||||||
|
"secret",
|
||||||
|
"seed",
|
||||||
|
"seed_hex"};
|
||||||
|
|
||||||
|
// Identify which secret type is in use.
|
||||||
|
std::string secretType = "";
|
||||||
|
int count = 0;
|
||||||
|
for (auto t : secretTypes)
|
||||||
|
{
|
||||||
|
if (request.contains(t))
|
||||||
|
{
|
||||||
|
++count;
|
||||||
|
secretType = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
error = "missing field secret";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 1)
|
||||||
|
{
|
||||||
|
error = "Exactly one of the following must be specified: "
|
||||||
|
" passphrase, secret, seed, or seed_hex";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<ripple::KeyType> keyType;
|
||||||
|
boost::optional<ripple::Seed> seed;
|
||||||
|
|
||||||
|
if (has_key_type)
|
||||||
|
{
|
||||||
|
if (!request.at("key_type").is_string())
|
||||||
|
{
|
||||||
|
error = "key_type must be string";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string key_type = request.at("key_type").as_string().c_str();
|
||||||
|
keyType = ripple::keyTypeFromString(key_type);
|
||||||
|
|
||||||
|
if (!keyType)
|
||||||
|
{
|
||||||
|
error = "Invalid field key_type";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (secretType == "secret")
|
||||||
|
{
|
||||||
|
error = "The secret field is not allowed if key_type is used.";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ripple-lib encodes seed used to generate an Ed25519 wallet in a
|
||||||
|
// non-standard way. While we never encode seeds that way, we try
|
||||||
|
// to detect such keys to avoid user confusion.
|
||||||
|
if (secretType != "seed_hex")
|
||||||
|
{
|
||||||
|
seed = parseRippleLibSeed(request.at(secretType));
|
||||||
|
|
||||||
|
if (seed)
|
||||||
|
{
|
||||||
|
// If the user passed in an Ed25519 seed but *explicitly*
|
||||||
|
// requested another key type, return an error.
|
||||||
|
if (keyType.value_or(ripple::KeyType::ed25519) != ripple::KeyType::ed25519)
|
||||||
|
{
|
||||||
|
error = "Specified seed is for an Ed25519 wallet.";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
keyType = ripple::KeyType::ed25519;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!keyType)
|
||||||
|
keyType = ripple::KeyType::secp256k1;
|
||||||
|
|
||||||
|
if (!seed)
|
||||||
|
{
|
||||||
|
if (has_key_type)
|
||||||
|
{
|
||||||
|
if (!request.at(secretType).is_string())
|
||||||
|
{
|
||||||
|
error = "secret value must be string";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string key = request.at(secretType).as_string().c_str();
|
||||||
|
|
||||||
|
if (secretType == "seed")
|
||||||
|
seed = ripple::parseBase58<ripple::Seed>(key);
|
||||||
|
else if (secretType == "passphrase")
|
||||||
|
seed = ripple::parseGenericSeed(key);
|
||||||
|
else if (secretType == "seed_hex")
|
||||||
|
{
|
||||||
|
ripple::uint128 s;
|
||||||
|
if (s.parseHex(key))
|
||||||
|
seed.emplace(ripple::Slice(s.data(), s.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!request.at("secret").is_string())
|
||||||
|
{
|
||||||
|
error = "field secret should be a string";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string secret = request.at("secret").as_string().c_str();
|
||||||
|
seed = ripple::parseGenericSeed(secret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!seed)
|
||||||
|
{
|
||||||
|
error = "Bad Seed: invalid field message secretType";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyType != ripple::KeyType::secp256k1
|
||||||
|
&& keyType != ripple::KeyType::ed25519)
|
||||||
|
{
|
||||||
|
error = "keypairForSignature: invalid key type";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return generateKeyPair(*keyType, *seed);
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <ripple/protocol/STTx.h>
|
#include <ripple/protocol/STTx.h>
|
||||||
#include <boost/json.hpp>
|
#include <boost/json.hpp>
|
||||||
#include <reporting/BackendInterface.h>
|
#include <reporting/BackendInterface.h>
|
||||||
|
|
||||||
std::optional<ripple::AccountID>
|
std::optional<ripple::AccountID>
|
||||||
accountFromStringStrict(std::string const& account);
|
accountFromStringStrict(std::string const& account);
|
||||||
|
|
||||||
@@ -32,5 +33,9 @@ traverseOwnedNodes(
|
|||||||
std::uint32_t sequence,
|
std::uint32_t sequence,
|
||||||
ripple::uint256 const& cursor,
|
ripple::uint256 const& cursor,
|
||||||
std::function<bool(ripple::SLE)> atOwnedNode);
|
std::function<bool(ripple::SLE)> atOwnedNode);
|
||||||
|
std::pair<ripple::PublicKey, ripple::SecretKey>
|
||||||
|
keypairFromRequst(
|
||||||
|
boost::json::object const& request,
|
||||||
|
boost::json::value& error);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1346,9 +1346,9 @@ CassandraBackend::open(bool readOnly)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
query.str("");
|
query.str("");
|
||||||
query << "CREATE TABLE IF NOT EXISTS " << tablePrefix << "transactions"
|
query
|
||||||
<< " ( hash blob PRIMARY KEY, ledger_sequence bigint, "
|
<< "CREATE TABLE IF NOT EXISTS " << tablePrefix << "transactions"
|
||||||
"transaction "
|
<< " ( hash blob PRIMARY KEY, ledger_sequence bigint, transaction "
|
||||||
"blob, metadata blob)";
|
"blob, metadata blob)";
|
||||||
if (!executeSimpleStatement(query.str()))
|
if (!executeSimpleStatement(query.str()))
|
||||||
continue;
|
continue;
|
||||||
@@ -1383,7 +1383,6 @@ CassandraBackend::open(bool readOnly)
|
|||||||
<< " LIMIT 1";
|
<< " LIMIT 1";
|
||||||
if (!executeSimpleStatement(query.str()))
|
if (!executeSimpleStatement(query.str()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
query.str("");
|
query.str("");
|
||||||
query << "CREATE TABLE IF NOT EXISTS " << tablePrefix << "books"
|
query << "CREATE TABLE IF NOT EXISTS " << tablePrefix << "books"
|
||||||
<< " ( book blob, sequence bigint, quality_key tuple<blob, blob>, PRIMARY KEY "
|
<< " ( book blob, sequence bigint, quality_key tuple<blob, blob>, PRIMARY KEY "
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ enum RPCCommand {
|
|||||||
account_currencies,
|
account_currencies,
|
||||||
account_offers,
|
account_offers,
|
||||||
account_objects
|
account_objects
|
||||||
|
channel_authorize,
|
||||||
|
channel_verify
|
||||||
};
|
};
|
||||||
std::unordered_map<std::string, RPCCommand> commandMap{
|
std::unordered_map<std::string, RPCCommand> commandMap{
|
||||||
{"tx", tx},
|
{"tx", tx},
|
||||||
@@ -63,7 +65,9 @@ std::unordered_map<std::string, RPCCommand> commandMap{
|
|||||||
{"account_lines", account_lines},
|
{"account_lines", account_lines},
|
||||||
{"account_currencies", account_currencies},
|
{"account_currencies", account_currencies},
|
||||||
{"account_offers", account_offers},
|
{"account_offers", account_offers},
|
||||||
{"account_objects", account_objects}};
|
{"account_objects", account_objects},
|
||||||
|
{"channel_authorize", channel_authorize},
|
||||||
|
{"channel_verify", channel_verify}};
|
||||||
|
|
||||||
boost::json::object
|
boost::json::object
|
||||||
doAccountInfo(
|
doAccountInfo(
|
||||||
@@ -113,6 +117,9 @@ boost::json::object
|
|||||||
doAccountObjects(
|
doAccountObjects(
|
||||||
boost::json::object const& request,
|
boost::json::object const& request,
|
||||||
BackendInterface const& backend);
|
BackendInterface const& backend);
|
||||||
|
doChannelAuthorize(boost::json::object const& request);
|
||||||
|
boost::json::object
|
||||||
|
doChannelVerify(boost::json::object const& request);
|
||||||
|
|
||||||
boost::json::object
|
boost::json::object
|
||||||
buildResponse(
|
buildResponse(
|
||||||
@@ -126,42 +133,34 @@ buildResponse(
|
|||||||
{
|
{
|
||||||
case tx:
|
case tx:
|
||||||
return doTx(request, backend);
|
return doTx(request, backend);
|
||||||
break;
|
|
||||||
case account_tx:
|
case account_tx:
|
||||||
return doAccountTx(request, backend);
|
return doAccountTx(request, backend);
|
||||||
break;
|
|
||||||
case ledger:
|
case ledger:
|
||||||
return doLedger(request, backend);
|
return doLedger(request, backend);
|
||||||
break;
|
|
||||||
case ledger_entry:
|
case ledger_entry:
|
||||||
return doLedgerEntry(request, backend);
|
return doLedgerEntry(request, backend);
|
||||||
break;
|
|
||||||
case ledger_range:
|
case ledger_range:
|
||||||
return doLedgerRange(request, backend);
|
return doLedgerRange(request, backend);
|
||||||
break;
|
|
||||||
case ledger_data:
|
case ledger_data:
|
||||||
return doLedgerData(request, backend);
|
return doLedgerData(request, backend);
|
||||||
break;
|
|
||||||
case account_info:
|
case account_info:
|
||||||
return doAccountInfo(request, backend);
|
return doAccountInfo(request, backend);
|
||||||
break;
|
|
||||||
case book_offers:
|
case book_offers:
|
||||||
return doBookOffers(request, backend);
|
return doBookOffers(request, backend);
|
||||||
break;
|
|
||||||
case account_channels:
|
case account_channels:
|
||||||
return doAccountChannels(request, backend);
|
return doAccountChannels(request, backend);
|
||||||
break;
|
|
||||||
case account_lines:
|
case account_lines:
|
||||||
return doAccountLines(request, backend);
|
return doAccountLines(request, backend);
|
||||||
break;
|
|
||||||
case account_currencies:
|
case account_currencies:
|
||||||
return doAccountCurrencies(request, backend);
|
return doAccountCurrencies(request, backend);
|
||||||
break;
|
|
||||||
case account_offers:
|
case account_offers:
|
||||||
return doAccountOffers(request, backend);
|
return doAccountOffers(request, backend);
|
||||||
break;
|
|
||||||
case account_objects:
|
case account_objects:
|
||||||
return doAccountObjects(request, backend);
|
return doAccountObjects(request, backend);
|
||||||
|
case channel_authorize:
|
||||||
|
return doChannelAuthorize(request);
|
||||||
|
case channel_verify:
|
||||||
|
return doChannelVerify(request);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BOOST_LOG_TRIVIAL(error) << "Unknown command: " << command;
|
BOOST_LOG_TRIVIAL(error) << "Unknown command: " << command;
|
||||||
|
|||||||
Reference in New Issue
Block a user