mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-19 18:15:50 +00:00
add account_namespace rpc call for iterating hook state objects
This commit is contained in:
@@ -573,6 +573,7 @@ target_sources (rippled PRIVATE
|
||||
src/ripple/rpc/handlers/AccountLines.cpp
|
||||
src/ripple/rpc/handlers/AccountObjects.cpp
|
||||
src/ripple/rpc/handlers/AccountOffers.cpp
|
||||
src/ripple/rpc/handlers/AccountNamespace.cpp
|
||||
src/ripple/rpc/handlers/AccountTx.cpp
|
||||
src/ripple/rpc/handlers/AccountTxOld.cpp
|
||||
src/ripple/rpc/handlers/BlackList.cpp
|
||||
|
||||
@@ -785,6 +785,13 @@ private:
|
||||
return parseAccountRaw2(jvParams, jss::peer);
|
||||
}
|
||||
|
||||
// account_namespace <account> <namespace hex> [<ledger>]
|
||||
Json::Value
|
||||
parseAccountNamespace(Json::Value const& jvParams)
|
||||
{
|
||||
return parseAccountNamespaceRaw(jvParams);
|
||||
}
|
||||
|
||||
// account_channels <account> <account>|"" [<ledger>]
|
||||
Json::Value
|
||||
parseAccountChannels(Json::Value const& jvParams)
|
||||
@@ -865,6 +872,61 @@ private:
|
||||
return jvRequest;
|
||||
}
|
||||
|
||||
Json::Value
|
||||
parseAccountNamespaceRaw(Json::Value const& jvParams)
|
||||
{
|
||||
auto const nParams = jvParams.size();
|
||||
Json::Value jvRequest(Json::objectValue);
|
||||
|
||||
for (auto i = 0; i < nParams; ++i)
|
||||
{
|
||||
std::string strParam = jvParams[i].asString();
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
// account
|
||||
if (parseBase58<PublicKey>(
|
||||
TokenType::AccountPublic, strParam) ||
|
||||
parseBase58<AccountID>(strParam) ||
|
||||
parseGenericSeed(strParam))
|
||||
{
|
||||
jvRequest[jss::account] = std::move(strParam);
|
||||
}
|
||||
else
|
||||
{
|
||||
return rpcError(rpcACT_MALFORMED);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == 1)
|
||||
{
|
||||
// namespace hex
|
||||
uint256 namespaceId;
|
||||
if (!namespaceId.parseHex(strParam))
|
||||
return rpcError(rpcNAMESPACE_MALFORMED);
|
||||
jvRequest[jss::namespace_id] = to_string(namespaceId);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == 2)
|
||||
{
|
||||
// ledger index (optional)
|
||||
if (strParam.empty())
|
||||
break;
|
||||
|
||||
if (jvParseLedger(jvRequest, strParam))
|
||||
break;
|
||||
else
|
||||
return rpcError(rpcLGR_IDX_MALFORMED);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return jvRequest;
|
||||
}
|
||||
|
||||
Json::Value
|
||||
parseAccountRaw2(Json::Value const& jvParams, char const* const acc2Field)
|
||||
{
|
||||
@@ -1237,6 +1299,7 @@ public:
|
||||
{"account_currencies", &RPCParser::parseAccountCurrencies, 1, 3},
|
||||
{"account_info", &RPCParser::parseAccountItems, 1, 3},
|
||||
{"account_lines", &RPCParser::parseAccountLines, 1, 5},
|
||||
{"account_namespace", &RPCParser::parseAccountNamespace, 2, 3},
|
||||
{"account_channels", &RPCParser::parseAccountChannels, 1, 3},
|
||||
{"account_objects", &RPCParser::parseAccountItems, 1, 5},
|
||||
{"account_offers", &RPCParser::parseAccountItems, 1, 4},
|
||||
|
||||
@@ -68,7 +68,8 @@ enum error_code_i {
|
||||
|
||||
// Ledger state
|
||||
rpcACT_NOT_FOUND = 19,
|
||||
// unused 20,
|
||||
rpcNAMESPACE_NOT_FOUND = 20,
|
||||
|
||||
rpcLGR_NOT_FOUND = 21,
|
||||
rpcLGR_NOT_VALIDATED = 22,
|
||||
rpcMASTER_DISABLED = 23,
|
||||
@@ -90,7 +91,7 @@ enum error_code_i {
|
||||
rpcACT_MALFORMED = 35,
|
||||
rpcALREADY_MULTISIG = 36,
|
||||
rpcALREADY_SINGLE_SIG = 37,
|
||||
// unused 38,
|
||||
rpcNAMESPACE_MALFORMED = 38,
|
||||
// unused 39,
|
||||
rpcBAD_FEATURE = 40,
|
||||
rpcBAD_ISSUER = 41,
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace detail {
|
||||
constexpr static ErrorInfo unorderedErrorInfos[]{
|
||||
{rpcACT_MALFORMED, "actMalformed", "Account malformed."},
|
||||
{rpcACT_NOT_FOUND, "actNotFound", "Account not found."},
|
||||
{rpcNAMESPACE_NOT_FOUND, "nsNotFound", "Namespace not found."},
|
||||
{rpcALREADY_MULTISIG, "alreadyMultisig", "Already multisigned."},
|
||||
{rpcALREADY_SINGLE_SIG, "alreadySingleSig", "Already single-signed."},
|
||||
{rpcAMENDMENT_BLOCKED,
|
||||
@@ -87,6 +88,7 @@ constexpr static ErrorInfo unorderedErrorInfos[]{
|
||||
{rpcLGR_NOT_FOUND, "lgrNotFound", "Ledger not found."},
|
||||
{rpcLGR_NOT_VALIDATED, "lgrNotValidated", "Ledger not validated."},
|
||||
{rpcMASTER_DISABLED, "masterDisabled", "Master key is disabled."},
|
||||
{rpcNAMESPACE_MALFORMED, "namespaceMalformed", "Namespace identifier is malformed."},
|
||||
{rpcNOT_ENABLED, "notEnabled", "Not enabled in configuration."},
|
||||
{rpcNOT_IMPL, "notImpl", "Not implemented."},
|
||||
{rpcNOT_READY, "notReady", "Not ready to handle this request."},
|
||||
|
||||
@@ -392,6 +392,8 @@ JSS(minimum_fee); // out: TxQ
|
||||
JSS(minimum_level); // out: TxQ
|
||||
JSS(missingCommand); // error
|
||||
JSS(name); // out: AmendmentTableImpl, PeerImp
|
||||
JSS(namespace_entries); // out: AccountNamespace
|
||||
JSS(namespace_id); // in/out: AccountNamespace
|
||||
JSS(needed_state_hashes); // out: InboundLedger
|
||||
JSS(needed_transaction_hashes); // out: InboundLedger
|
||||
JSS(network_id); // out: NetworkOPs
|
||||
|
||||
135
src/ripple/rpc/handlers/AccountNamespace.cpp
Normal file
135
src/ripple/rpc/handlers/AccountNamespace.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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/app/main/Application.h>
|
||||
#include <ripple/json/json_writer.h>
|
||||
#include <ripple/ledger/ReadView.h>
|
||||
#include <ripple/net/RPCErr.h>
|
||||
#include <ripple/protocol/ErrorCodes.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/LedgerFormats.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <ripple/resource/Fees.h>
|
||||
#include <ripple/rpc/Context.h>
|
||||
#include <ripple/rpc/impl/RPCHelpers.h>
|
||||
#include <ripple/rpc/impl/Tuning.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
/** RPC command that retreives hook state objects from a particular namespace in a particular account.
|
||||
{
|
||||
account: <account>|<account_public_key>
|
||||
namespace_id: <namespace hex>
|
||||
ledger_hash: <string> // optional
|
||||
ledger_index: <string | unsigned integer> // optional
|
||||
type: <string> // optional, defaults to all account objects types
|
||||
limit: <integer> // optional
|
||||
marker: <opaque> // optional, resume previous query
|
||||
}
|
||||
*/
|
||||
|
||||
Json::Value
|
||||
doAccountNamespace(RPC::JsonContext& context)
|
||||
{
|
||||
auto const& params = context.params;
|
||||
if (!params.isMember(jss::account))
|
||||
return RPC::missing_field_error(jss::account);
|
||||
|
||||
if (!params.isMember(jss::namespace_id))
|
||||
return RPC::missing_field_error(jss::namespace_id);
|
||||
|
||||
std::shared_ptr<ReadView const> ledger;
|
||||
auto result = RPC::lookupLedger(ledger, context);
|
||||
if (ledger == nullptr)
|
||||
return result;
|
||||
|
||||
AccountID accountID;
|
||||
{
|
||||
auto const strIdent = params[jss::account].asString();
|
||||
if (auto jv = RPC::accountFromString(accountID, strIdent))
|
||||
{
|
||||
for (auto it = jv.begin(); it != jv.end(); ++it)
|
||||
result[it.memberName()] = *it;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
auto const ns = params[jss::namespace_id].asString();
|
||||
|
||||
uint256 nsID = beast::zero;
|
||||
|
||||
if (!nsID.parseHex(ns))
|
||||
return rpcError(rpcINVALID_PARAMS);
|
||||
|
||||
if (!ledger->exists(keylet::account(accountID)))
|
||||
return rpcError(rpcACT_NOT_FOUND);
|
||||
|
||||
if (!ledger->exists(keylet::hookStateDir(accountID, nsID)))
|
||||
return rpcError(rpcNAMESPACE_NOT_FOUND);
|
||||
|
||||
unsigned int limit;
|
||||
if (auto err = readLimitField(limit, RPC::Tuning::accountObjects, context))
|
||||
return *err;
|
||||
|
||||
uint256 dirIndex;
|
||||
uint256 entryIndex;
|
||||
if (params.isMember(jss::marker))
|
||||
{
|
||||
auto const& marker = params[jss::marker];
|
||||
if (!marker.isString())
|
||||
return RPC::expected_field_error(jss::marker, "string");
|
||||
|
||||
std::stringstream ss(marker.asString());
|
||||
std::string s;
|
||||
if (!std::getline(ss, s, ','))
|
||||
return RPC::invalid_field_error(jss::marker);
|
||||
|
||||
if (!dirIndex.parseHex(s))
|
||||
return RPC::invalid_field_error(jss::marker);
|
||||
|
||||
if (!std::getline(ss, s, ','))
|
||||
return RPC::invalid_field_error(jss::marker);
|
||||
|
||||
if (!entryIndex.parseHex(s))
|
||||
return RPC::invalid_field_error(jss::marker);
|
||||
}
|
||||
|
||||
if (!RPC::getAccountNamespace(
|
||||
*ledger,
|
||||
accountID,
|
||||
nsID,
|
||||
dirIndex,
|
||||
entryIndex,
|
||||
limit,
|
||||
result))
|
||||
{
|
||||
result[jss::account_objects] = Json::arrayValue;
|
||||
}
|
||||
|
||||
result[jss::account] = context.app.accountIDCache().toBase58(accountID);
|
||||
result[jss::namespace_id] = ns;
|
||||
context.loadType = Resource::feeMediumBurdenRPC;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
@@ -37,6 +37,8 @@ doAccountObjects(RPC::JsonContext&);
|
||||
Json::Value
|
||||
doAccountOffers(RPC::JsonContext&);
|
||||
Json::Value
|
||||
doAccountNamespace(RPC::JsonContext&);
|
||||
Json::Value
|
||||
doAccountTxJson(RPC::JsonContext&);
|
||||
Json::Value
|
||||
doBookOffers(RPC::JsonContext&);
|
||||
|
||||
@@ -66,6 +66,7 @@ Handler const handlerArray[]{
|
||||
Role::USER,
|
||||
NO_CONDITION},
|
||||
{"account_lines", byRef(&doAccountLines), Role::USER, NO_CONDITION},
|
||||
{"account_namespace", byRef(&doAccountNamespace), Role::USER, NO_CONDITION},
|
||||
{"account_channels", byRef(&doAccountChannels), Role::USER, NO_CONDITION},
|
||||
{"account_objects", byRef(&doAccountObjects), Role::USER, NO_CONDITION},
|
||||
{"account_offers", byRef(&doAccountOffers), Role::USER, NO_CONDITION},
|
||||
|
||||
@@ -226,6 +226,89 @@ getAccountObjects(
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
getAccountNamespace(
|
||||
ReadView const& ledger,
|
||||
AccountID const& account,
|
||||
uint256 const& ns,
|
||||
uint256 dirIndex,
|
||||
uint256 const& entryIndex,
|
||||
std::uint32_t const limit,
|
||||
Json::Value& jvResult)
|
||||
{
|
||||
auto const root = keylet::hookStateDir(account, ns);
|
||||
auto found = false;
|
||||
|
||||
if (dirIndex.isZero())
|
||||
{
|
||||
dirIndex = root.key;
|
||||
found = true;
|
||||
}
|
||||
|
||||
auto dir = ledger.read({ltDIR_NODE, dirIndex});
|
||||
if (!dir)
|
||||
return false;
|
||||
|
||||
std::uint32_t i = 0;
|
||||
auto& jvObjects = (jvResult[jss::namespace_entries] = Json::arrayValue);
|
||||
for (;;)
|
||||
{
|
||||
auto const& entries = dir->getFieldV256(sfIndexes);
|
||||
auto iter = entries.begin();
|
||||
|
||||
if (!found)
|
||||
{
|
||||
iter = std::find(iter, entries.end(), entryIndex);
|
||||
if (iter == entries.end())
|
||||
return false;
|
||||
|
||||
found = true;
|
||||
}
|
||||
|
||||
for (; iter != entries.end(); ++iter)
|
||||
{
|
||||
auto const sleNode = ledger.read(keylet::child(*iter));
|
||||
|
||||
jvObjects.append(sleNode->getJson(JsonOptions::none));
|
||||
|
||||
if (++i == limit)
|
||||
{
|
||||
if (++iter != entries.end())
|
||||
{
|
||||
jvResult[jss::limit] = limit;
|
||||
jvResult[jss::marker] =
|
||||
to_string(dirIndex) + ',' + to_string(*iter);
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto const nodeIndex = dir->getFieldU64(sfIndexNext);
|
||||
if (nodeIndex == 0)
|
||||
return true;
|
||||
|
||||
dirIndex = keylet::page(root, nodeIndex).key;
|
||||
dir = ledger.read({ltDIR_NODE, dirIndex});
|
||||
if (!dir)
|
||||
return true;
|
||||
|
||||
if (i == limit)
|
||||
{
|
||||
auto const& e = dir->getFieldV256(sfIndexes);
|
||||
if (!e.empty())
|
||||
{
|
||||
jvResult[jss::limit] = limit;
|
||||
jvResult[jss::marker] =
|
||||
to_string(dirIndex) + ',' + to_string(*e.begin());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool
|
||||
|
||||
@@ -109,6 +109,25 @@ getAccountObjects(
|
||||
std::uint32_t const limit,
|
||||
Json::Value& jvResult);
|
||||
|
||||
/** Gathers all hook state objects for an account namespace in a ledger.
|
||||
@param ledger Ledger to search account objects.
|
||||
@param account AccountID to find objects for.
|
||||
@param ns Namespace ID to find objects for.
|
||||
@param dirIndex Begin gathering account objects from this directory.
|
||||
@param entryIndex Begin gathering objects from this directory node.
|
||||
@param limit Maximum number of objects to find.
|
||||
@param jvResult A JSON result that holds the request objects.
|
||||
*/
|
||||
bool
|
||||
getAccountNamespace(
|
||||
ReadView const& ledger,
|
||||
AccountID const& account,
|
||||
uint256 const& ns,
|
||||
uint256 dirIndex,
|
||||
uint256 const& entryIndex,
|
||||
std::uint32_t const limit,
|
||||
Json::Value& jvResult);
|
||||
|
||||
/** Get ledger by hash
|
||||
If there is no error in the return value, the ledger pointer will have
|
||||
been filled
|
||||
|
||||
Reference in New Issue
Block a user