Skip to content

New validator_info and manifest RPC methods #3197

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Builds/CMake/RippledCore.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,7 @@ else ()
src/ripple/rpc/handlers/LedgerRequest.cpp
src/ripple/rpc/handlers/LogLevel.cpp
src/ripple/rpc/handlers/LogRotate.cpp
src/ripple/rpc/handlers/Manifest.cpp
src/ripple/rpc/handlers/NoRippleCheck.cpp
src/ripple/rpc/handlers/OwnerInfo.cpp
src/ripple/rpc/handlers/PathFind.cpp
Expand All @@ -676,6 +677,7 @@ else ()
src/ripple/rpc/handlers/ValidationCreate.cpp
src/ripple/rpc/handlers/ValidatorListSites.cpp
src/ripple/rpc/handlers/Validators.cpp
src/ripple/rpc/handlers/ValidatorInfo.cpp
src/ripple/rpc/handlers/WalletPropose.cpp
src/ripple/rpc/impl/DeliveredAmount.cpp
src/ripple/rpc/impl/Handler.cpp
Expand Down Expand Up @@ -967,6 +969,7 @@ else ()
src/test/rpc/LedgerData_test.cpp
src/test/rpc/LedgerRPC_test.cpp
src/test/rpc/LedgerRequestRPC_test.cpp
src/test/rpc/ManifestRPC_test.cpp
src/test/rpc/NoRippleCheck_test.cpp
src/test/rpc/NoRipple_test.cpp
src/test/rpc/OwnerInfo_test.cpp
Expand All @@ -983,6 +986,7 @@ else ()
src/test/rpc/TransactionEntry_test.cpp
src/test/rpc/TransactionHistory_test.cpp
src/test/rpc/Tx_test.cpp
src/test/rpc/ValidatorInfo_test.cpp
src/test/rpc/ValidatorRPC_test.cpp
src/test/rpc/Version_test.cpp
#[===============================[
Expand Down
1 change: 1 addition & 0 deletions src/ripple/app/main/Application.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class AcceptedLedger;
class LedgerMaster;
class LoadManager;
class ManifestCache;
class ValidatorKeys;
class NetworkOPs;
class OpenLedger;
class OrderBookDB;
Expand Down
24 changes: 24 additions & 0 deletions src/ripple/app/misc/Manifest.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,30 @@ class ManifestCache
PublicKey
getMasterKey (PublicKey const& pk) const;

/** Returns master key's current manifest sequence.

@return sequence corresponding to Master public key
if configured or boost::none otherwise
*/
boost::optional<std::uint32_t>
getSequence (PublicKey const& pk) const;

/** Returns domain claimed by a given public key

@return domain corresponding to Master public key
if present, otherwise boost::none
*/
boost::optional<std::string>
getDomain (PublicKey const& pk) const;

/** Returns mainfest corresponding to a given public key

@return manifest corresponding to Master public key
if present, otherwise boost::none
*/
boost::optional<std::string>
getManifest (PublicKey const& pk) const;

/** Returns `true` if master key has been revoked in a manifest.

@param pk Master public key
Expand Down
36 changes: 36 additions & 0 deletions src/ripple/app/misc/impl/Manifest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,42 @@ ManifestCache::getMasterKey (PublicKey const& pk) const
return pk;
}

boost::optional<std::uint32_t>
ManifestCache::getSequence (PublicKey const& pk) const
{
std::lock_guard lock{read_mutex_};
auto const iter = map_.find (pk);

if (iter != map_.end () && !iter->second.revoked ())
return iter->second.sequence;

return boost::none;
}

boost::optional<std::string>
ManifestCache::getDomain (PublicKey const& pk) const
{
std::lock_guard lock{read_mutex_};
auto const iter = map_.find (pk);

if (iter != map_.end () && !iter->second.revoked ())
return iter->second.domain;

return boost::none;
}

boost::optional<std::string>
ManifestCache::getManifest (PublicKey const& pk) const
{
std::lock_guard lock{read_mutex_};
auto const iter = map_.find (pk);

if (iter != map_.end () && !iter->second.revoked ())
return iter->second.serialized;

return boost::none;
}

bool
ManifestCache::revoked (PublicKey const& pk) const
{
Expand Down
51 changes: 36 additions & 15 deletions src/ripple/net/impl/RPCCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,21 @@ class RPCParser
}
}

static bool validPublicKey (std::string const& strPk)
{
if (parseBase58<PublicKey> (TokenType::AccountPublic, strPk))
return true;

auto pkHex = strUnHex (strPk);
if (!pkHex)
return false;

if (!publicKeyType(makeSlice(*pkHex)))
return false;

return true;
Comment on lines +153 to +160
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An alternative here is this:

if (auto k = strUnHex(strPk))
    return static_cast<bool>(publicKeyType(makeSlice(*k)));
return false;

Note that this rewrite returns true from the branch that positively identifies a key as being of a given type, instead of by default. I think that's a net positive. Apart from that, I don't know if it's better; it is shorter, but that isn't always a positive.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nbougalis do you mind if we leave this as is for this patch? The reason I suggest this is that this method is simply extracted verbatim from the parseFetchInfo method below. This way we can just focus on extracting the common logic here, and refactoring / cleaning this up in a separate PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not at all. Whether review comments should be "resolved" is typically up to the PR author. Obviously, exceptions for bugs/problems exist, but this wasn't that. I'm fine with leaving this as is.

}

private:
using parseFuncPtr = Json::Value (RPCParser::*) (Json::Value const& jvParams);

Expand Down Expand Up @@ -203,6 +218,24 @@ class RPCParser
return v;
}

Json::Value parseManifest (Json::Value const& jvParams)
{
if (jvParams.size () == 1)
{
Json::Value jvRequest (Json::objectValue);

std::string const strPk = jvParams[0u].asString ();
if (!validPublicKey (strPk))
return rpcError (rpcPUBLIC_MALFORMED);

jvRequest[jss::public_key] = strPk;

return jvRequest;
}

return rpcError (rpcINVALID_PARAMS);
}

// fetch_info [clear]
Json::Value parseFetchInfo (Json::Value const& jvParams)
{
Expand Down Expand Up @@ -764,21 +797,7 @@ class RPCParser
{
std::string const strPk = jvParams[0u].asString ();

bool const validPublicKey = [&strPk]{
if (parseBase58<PublicKey> (TokenType::AccountPublic, strPk))
return true;

auto pkHex = strUnHex (strPk);
if (!pkHex)
return false;

if (!publicKeyType(makeSlice(*pkHex)))
return false;

return true;
}();

if (!validPublicKey)
if (!validPublicKey(strPk))
return rpcError (rpcPUBLIC_MALFORMED);

Json::Value jvRequest (Json::objectValue);
Expand Down Expand Up @@ -1171,6 +1190,7 @@ class RPCParser
{ "ledger_request", &RPCParser::parseLedgerId, 1, 1 },
{ "log_level", &RPCParser::parseLogLevel, 0, 2 },
{ "logrotate", &RPCParser::parseAsIs, 0, 0 },
{ "manifest", &RPCParser::parseManifest, 1, 1 },
{ "owner_info", &RPCParser::parseAccountItems, 1, 2 },
{ "peers", &RPCParser::parseAsIs, 0, 0 },
{ "ping", &RPCParser::parseAsIs, 0, 0 },
Expand All @@ -1195,6 +1215,7 @@ class RPCParser
{ "tx_history", &RPCParser::parseTxHistory, 1, 1 },
{ "unl_list", &RPCParser::parseAsIs, 0, 0 },
{ "validation_create", &RPCParser::parseValidationCreate, 0, 1 },
{ "validator_info", &RPCParser::parseAsIs, 0, 0 },
{ "version", &RPCParser::parseAsIs, 0, 0 },
{ "wallet_propose", &RPCParser::parseWalletPropose, 0, 1 },
{ "internal", &RPCParser::parseInternal, 1, -1 },
Expand Down
5 changes: 5 additions & 0 deletions src/ripple/protocol/ErrorCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,11 @@ inline Json::Value expected_field_error (
return expected_field_error (std::string (name), type);
}

inline Json::Value not_validator_error ()
{
return make_param_error ("not a validator");
}

/** @} */

/** Returns `true` if the json contains an rpc error specification. */
Expand Down
16 changes: 13 additions & 3 deletions src/ripple/protocol/jss.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,16 +202,20 @@ JSS ( destination_amount ); // in: PathRequest, RipplePathFind
JSS ( destination_currencies ); // in: PathRequest, RipplePathFind
JSS ( destination_tag ); // in: PathRequest
// out: AccountChannels
JSS ( details ); // out: Manifest
JSS ( dir_entry ); // out: DirectoryEntryIterator
JSS ( dir_index ); // out: DirectoryEntryIterator
JSS ( dir_root ); // out: DirectoryEntryIterator
JSS ( directory ); // in: LedgerEntry
JSS ( domain ); // out: ValidatorInfo, Manifest
JSS ( drops ); // out: TxQ
JSS ( duration_us ); // out: NetworkOPs
JSS ( enabled ); // out: AmendmentTable
JSS ( engine_result ); // out: NetworkOPs, TransactionSign, Submit
JSS ( engine_result_code ); // out: NetworkOPs, TransactionSign, Submit
JSS ( engine_result_message ); // out: NetworkOPs, TransactionSign, Submit
JSS ( ephemeral_key ); // out: ValidatorInfo
// in/out: Manifest
JSS ( error ); // out: error
JSS ( errored );
JSS ( error_code ); // out: error
Expand Down Expand Up @@ -331,11 +335,14 @@ JSS ( local_txs ); // out: GetCounts
JSS ( local_static_keys ); // out: ValidatorList
JSS ( lowest_sequence ); // out: AccountInfo
JSS ( majority ); // out: RPC feature
JSS ( manifest ); // out: ValidatorInfo, Manifest
JSS ( marker ); // in/out: AccountTx, AccountOffers,
// AccountLines, AccountObjects,
// LedgerData
// in: BookOffers
JSS ( master_key ); // out: WalletPropose, NetworkOPs
JSS ( master_key ); // out: WalletPropose, NetworkOPs,
// ValidatorInfo
// in/out: Manifest
JSS ( master_seed ); // out: WalletPropose
JSS ( master_seed_hex ); // out: WalletPropose
JSS ( master_signature ); // out: pubManifest
Expand Down Expand Up @@ -412,7 +419,9 @@ JSS ( proxied ); // out: RPC ping
JSS ( pubkey_node ); // out: NetworkOPs
JSS ( pubkey_publisher ); // out: ValidatorList
JSS ( pubkey_validator ); // out: NetworkOPs, ValidatorList
JSS ( public_key ); // out: OverlayImpl, PeerImp, WalletPropose
JSS ( public_key ); // out: OverlayImpl, PeerImp, WalletPropose,
// ValidatorInfo
// in/out: Manifest
JSS ( public_key_hex ); // out: WalletPropose
JSS ( published_ledger ); // out: NetworkOPs
JSS ( publisher_lists ); // out: ValidatorList
Expand All @@ -431,6 +440,7 @@ JSS ( refresh_interval_min ); // out: ValidatorSites
JSS ( regular_seed ); // in/out: LedgerEntry
JSS ( remote ); // out: Logic.h
JSS ( request ); // RPC
JSS ( requested ); // out: Manifest
JSS ( reservations ); // out: Reservations
JSS ( reserve_base ); // out: NetworkOPs
JSS ( reserve_base_xrp ); // out: NetworkOPs
Expand All @@ -457,7 +467,7 @@ JSS ( send_currencies ); // out: AccountCurrencies
JSS ( send_max ); // in: PathRequest, RipplePathFind
JSS ( seq ); // in: LedgerEntry;
// out: NetworkOPs, RPCSub, AccountOffers,
// ValidatorList
// ValidatorList, ValidatorInfo, Manifest
JSS ( seqNum ); // out: LedgerToJson
JSS ( server_state ); // out: NetworkOPs
JSS ( server_state_duration_us ); // out: NetworkOPs
Expand Down
2 changes: 2 additions & 0 deletions src/ripple/rpc/handlers/Handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Json::Value doLedgerHeader (RPC::JsonContext&);
Json::Value doLedgerRequest (RPC::JsonContext&);
Json::Value doLogLevel (RPC::JsonContext&);
Json::Value doLogRotate (RPC::JsonContext&);
Json::Value doManifest (RPC::JsonContext&);
Json::Value doNoRippleCheck (RPC::JsonContext&);
Json::Value doOwnerInfo (RPC::JsonContext&);
Json::Value doPathFind (RPC::JsonContext&);
Expand Down Expand Up @@ -86,6 +87,7 @@ Json::Value doValidationCreate (RPC::JsonContext&);
Json::Value doWalletPropose (RPC::JsonContext&);
Json::Value doValidators (RPC::JsonContext&);
Json::Value doValidatorListSites (RPC::JsonContext&);
Json::Value doValidatorInfo (RPC::JsonContext&);
} // ripple

#endif
75 changes: 75 additions & 0 deletions src/ripple/rpc/handlers/Manifest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2019 Dev Null Productions

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/basics/base64.h>
#include <ripple/json/json_value.h>
#include <ripple/protocol/ErrorCodes.h>
#include <ripple/protocol/jss.h>
#include <ripple/rpc/Context.h>

namespace ripple {
Json::Value doManifest (RPC::JsonContext& context)
{
auto& params = context.params;

if (!params.isMember(jss::public_key))
return RPC::missing_field_error (jss::public_key);

auto const requested = params[jss::public_key].asString();

Json::Value ret;
ret[jss::requested] = requested;

auto const pk = parseBase58<PublicKey>(TokenType::NodePublic, requested);
if (!pk)
{
RPC::inject_error(rpcINVALID_PARAMS, ret);
return ret;
}

// first attempt to use params as ephemeral key,
// if this lookup succeeds master key will be returned,
// else pk will just be returned and we will assume that
// is master key anyways
auto const mk = context.app.validatorManifests().getMasterKey(*pk);

auto const ek = context.app.validatorManifests().getSigningKey(mk);

// if ephemeral key not found, we don't have specified manifest
if (ek == mk)
return ret;

if (auto const manifest = context.app.validatorManifests().getManifest(mk))
ret[jss::manifest] = base64_encode(*manifest);
Json::Value details;

details[jss::master_key] = toBase58(TokenType::NodePublic, mk);
details[jss::ephemeral_key] = toBase58(TokenType::NodePublic, ek);

if (auto const seq = context.app.validatorManifests().getSequence(mk))
details[jss::seq] = *seq;

if (auto const domain = context.app.validatorManifests().getDomain(mk))
details[jss::domain] = *domain;

ret[jss::details] = details;
return ret;
}
} // ripple
Loading