diff --git a/Builds/CMake/RippledCore.cmake b/Builds/CMake/RippledCore.cmake index 835772aee9..46f217e3f3 100644 --- a/Builds/CMake/RippledCore.cmake +++ b/Builds/CMake/RippledCore.cmake @@ -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 @@ -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 @@ -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 @@ -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 #[===============================[ diff --git a/src/ripple/app/main/Application.h b/src/ripple/app/main/Application.h index 9c8b03561c..5ffa87552d 100644 --- a/src/ripple/app/main/Application.h +++ b/src/ripple/app/main/Application.h @@ -53,6 +53,7 @@ class AcceptedLedger; class LedgerMaster; class LoadManager; class ManifestCache; +class ValidatorKeys; class NetworkOPs; class OpenLedger; class OrderBookDB; diff --git a/src/ripple/app/misc/Manifest.h b/src/ripple/app/misc/Manifest.h index 67530fc0dc..c1ddb92327 100644 --- a/src/ripple/app/misc/Manifest.h +++ b/src/ripple/app/misc/Manifest.h @@ -257,6 +257,30 @@ public: 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 + 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 + 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 + getManifest (PublicKey const& pk) const; + /** Returns `true` if master key has been revoked in a manifest. @param pk Master public key diff --git a/src/ripple/app/misc/impl/Manifest.cpp b/src/ripple/app/misc/impl/Manifest.cpp index 123254d2bf..2b8cdbd9b0 100644 --- a/src/ripple/app/misc/impl/Manifest.cpp +++ b/src/ripple/app/misc/impl/Manifest.cpp @@ -309,6 +309,42 @@ ManifestCache::getMasterKey (PublicKey const& pk) const return pk; } +boost::optional +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 +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 +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 { diff --git a/src/ripple/net/impl/RPCCall.cpp b/src/ripple/net/impl/RPCCall.cpp index 96ded73d53..1601f7ce9d 100644 --- a/src/ripple/net/impl/RPCCall.cpp +++ b/src/ripple/net/impl/RPCCall.cpp @@ -145,6 +145,21 @@ private: } } + static bool validPublicKey (std::string const& strPk) + { + if (parseBase58 (TokenType::AccountPublic, strPk)) + return true; + + auto pkHex = strUnHex (strPk); + if (!pkHex) + return false; + + if (!publicKeyType(makeSlice(*pkHex))) + return false; + + return true; + } + private: using parseFuncPtr = Json::Value (RPCParser::*) (Json::Value const& jvParams); @@ -203,6 +218,24 @@ private: 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) { @@ -764,21 +797,7 @@ private: { std::string const strPk = jvParams[0u].asString (); - bool const validPublicKey = [&strPk]{ - if (parseBase58 (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); @@ -1171,6 +1190,7 @@ public: { "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 }, @@ -1195,6 +1215,7 @@ public: { "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 }, diff --git a/src/ripple/protocol/ErrorCodes.h b/src/ripple/protocol/ErrorCodes.h index c6c2f1d020..9cbed28f3b 100644 --- a/src/ripple/protocol/ErrorCodes.h +++ b/src/ripple/protocol/ErrorCodes.h @@ -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. */ diff --git a/src/ripple/protocol/jss.h b/src/ripple/protocol/jss.h index 4af0aebb5a..f6d4c4c014 100644 --- a/src/ripple/protocol/jss.h +++ b/src/ripple/protocol/jss.h @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/src/ripple/rpc/handlers/Handlers.h b/src/ripple/rpc/handlers/Handlers.h index bbcf07ac77..127e8cfd15 100644 --- a/src/ripple/rpc/handlers/Handlers.h +++ b/src/ripple/rpc/handlers/Handlers.h @@ -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&); @@ -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 diff --git a/src/ripple/rpc/handlers/Manifest.cpp b/src/ripple/rpc/handlers/Manifest.cpp new file mode 100644 index 0000000000..913c81f28d --- /dev/null +++ b/src/ripple/rpc/handlers/Manifest.cpp @@ -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 +#include +#include +#include +#include +#include + +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(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 diff --git a/src/ripple/rpc/handlers/ValidatorInfo.cpp b/src/ripple/rpc/handlers/ValidatorInfo.cpp new file mode 100644 index 0000000000..3809bff886 --- /dev/null +++ b/src/ripple/rpc/handlers/ValidatorInfo.cpp @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +/* + 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 +#include +#include +#include +#include +#include +#include + +namespace ripple { +Json::Value doValidatorInfo (RPC::JsonContext& context) +{ + // return error if not configured as validator + if (context.app.getValidationPublicKey().empty()) + return RPC::not_validator_error (); + + Json::Value ret; + + auto const pk = context.app.getValidationPublicKey(); + + // assume pk is ephemeral key, get master key + auto const mk = context.app.validatorManifests().getMasterKey(pk); + ret[jss::master_key] = toBase58(TokenType::NodePublic, mk); + + // pk is maskter key, eg no ephemeral key, eg no manifest, just return + if (mk == pk) + return ret; + + // lookup ephemeral key + auto const ek = context.app.validatorManifests().getSigningKey(mk); + ret[jss::ephemeral_key] = toBase58(TokenType::NodePublic, ek); + + if (auto const manifest = context.app.validatorManifests().getManifest(mk)) + ret[jss::manifest] = base64_encode(*manifest); + + if (auto const seq = context.app.validatorManifests().getSequence(mk)) + ret[jss::seq] = *seq; + + if (auto const domain = context.app.validatorManifests().getDomain(mk)) + ret[jss::domain] = *domain; + + return ret; +} +} // ripple diff --git a/src/ripple/rpc/impl/Handler.cpp b/src/ripple/rpc/impl/Handler.cpp index 69b2a3e627..06325247ed 100644 --- a/src/ripple/rpc/impl/Handler.cpp +++ b/src/ripple/rpc/impl/Handler.cpp @@ -90,6 +90,7 @@ Handler const handlerArray[] { { "ledger_request", byRef (&doLedgerRequest), Role::ADMIN, NO_CONDITION }, { "log_level", byRef (&doLogLevel), Role::ADMIN, NO_CONDITION }, { "logrotate", byRef (&doLogRotate), Role::ADMIN, NO_CONDITION }, + { "manifest", byRef (&doManifest), Role::ADMIN, NO_CONDITION }, { "noripple_check", byRef (&doNoRippleCheck), Role::USER, NO_CONDITION }, { "owner_info", byRef (&doOwnerInfo), Role::USER, NEEDS_CURRENT_LEDGER }, { "peers", byRef (&doPeers), Role::ADMIN, NO_CONDITION }, @@ -117,6 +118,7 @@ Handler const handlerArray[] { { "validation_create", byRef (&doValidationCreate), Role::ADMIN, NO_CONDITION }, { "validators", byRef (&doValidators), Role::ADMIN, NO_CONDITION }, { "validator_list_sites", byRef (&doValidatorListSites), Role::ADMIN, NO_CONDITION }, + { "validator_info", byRef (&doValidatorInfo), Role::ADMIN, NO_CONDITION }, { "wallet_propose", byRef (&doWalletPropose), Role::ADMIN, NO_CONDITION }, // Evented methods diff --git a/src/ripple/unity/rpcx1.cpp b/src/ripple/unity/rpcx1.cpp index 0bff6b93b7..8593b656f8 100644 --- a/src/ripple/unity/rpcx1.cpp +++ b/src/ripple/unity/rpcx1.cpp @@ -58,5 +58,7 @@ #include #include #include +#include #include #include +#include diff --git a/src/test/rpc/ManifestRPC_test.cpp b/src/test/rpc/ManifestRPC_test.cpp new file mode 100644 index 0000000000..ac508191ea --- /dev/null +++ b/src/test/rpc/ManifestRPC_test.cpp @@ -0,0 +1,85 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2020 Dev Null Productions, LLC + + 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 +#include +#include +#include + +#include + +namespace ripple { +namespace test { + +class ManifestRPC_test : public beast::unit_test::suite +{ +public: + void testErrors() + { + testcase ("Errors"); + + using namespace jtx; + Env env(*this); + { + // manifest with no public key + auto const info = env.rpc ("json", "manifest", "{ }"); + BEAST_EXPECT(info[jss::result][jss::error_message] == + "Missing field 'public_key'."); + } + { + // manifest with manlformed public key + auto const info = env.rpc ("json", "manifest", "{ \"public_key\": " + "\"abcdef12345\"}"); + BEAST_EXPECT(info[jss::result][jss::error_message] == + "Invalid parameters."); + } + } + + void testLookup() + { + testcase ("Lookup"); + + using namespace jtx; + std::string const key = + "n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7"; + Env env{ + *this, + envconfig([&key](std::unique_ptr cfg) { + cfg->section(SECTION_VALIDATORS).append(key); + return cfg; + }) + }; + { + auto const info = env.rpc ("json", "manifest", "{ \"public_key\": " + "\"" + key + "\"}"); + BEAST_EXPECT(info[jss::result][jss::requested] == key); + BEAST_EXPECT(info[jss::result][jss::status] == "success"); + } + } + + void run() override + { + testErrors(); + testLookup(); + } +}; + +BEAST_DEFINE_TESTSUITE(ManifestRPC,rpc,ripple); +} +} diff --git a/src/test/rpc/ValidatorInfo_test.cpp b/src/test/rpc/ValidatorInfo_test.cpp new file mode 100644 index 0000000000..82c2f6b2cf --- /dev/null +++ b/src/test/rpc/ValidatorInfo_test.cpp @@ -0,0 +1,108 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2020 Dev Null Productions, LLC + + 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 +#include +#include +#include + +#include +#include + +namespace ripple { +namespace test { + +class ValidatorInfo_test : public beast::unit_test::suite +{ +public: + void testErrors() + { + testcase ("Errors"); + + using namespace jtx; + { + Env env(*this); + auto const info = env.rpc ("validator_info"); + BEAST_EXPECT(info[jss::result][jss::error_message] == + "not a validator"); + } + } + + void + testPrivileges() + { + using namespace test::jtx; + Env env{*this, envconfig(no_admin)}; + auto const info = env.rpc ("validator_info")[jss::result]; + BEAST_EXPECT(info.isNull()); + } + + void testLookup() + { + testcase ("Lookup"); + + using namespace jtx; + const std::vector tokenBlob = { + " " + "eyJ2YWxpZGF0aW9uX3NlY3JldF9rZXkiOiI5ZWQ0NWY4NjYyNDFjYzE4YTI3NDdiNT\n", + " \tQzODdjMDYyNTkwNzk3MmY0ZTcxOTAyMzFmYWE5Mzc0NTdmYTlkYWY2IiwibWFuaWZl " + " \n", + "\tc3QiOiJKQUFBQUFGeEllMUZ0d21pbXZHdEgyaUNjTUpxQzlnVkZLaWxHZncxL3ZDeE" + "\n", + "\t " + "hYWExwbGMyR25NaEFrRTFhZ3FYeEJ3RHdEYklENk9NU1l1TTBGREFscEFnTms4U0tG\t " + "\t\n", + "bjdNTzJmZGtjd1JRSWhBT25ndTlzQUtxWFlvdUorbDJWMFcrc0FPa1ZCK1pSUzZQU2\n", + "hsSkFmVXNYZkFpQnNWSkdlc2FhZE9KYy9hQVpva1MxdnltR21WcmxIUEtXWDNZeXd1\n", + "NmluOEhBU1FLUHVnQkQ2N2tNYVJGR3ZtcEFUSGxHS0pkdkRGbFdQWXk1QXFEZWRGdj\n", + "VUSmEydzBpMjFlcTNNWXl3TFZKWm5GT3I3QzBrdzJBaVR6U0NqSXpkaXRROD0ifQ==\n"}; + + std::string const master_key = "nHBt9fsb4849WmZiCds4r5TXyBeQjqnH5kzPtqgMAQMgi39YZRPa"; + std::string const ephemeral_key = "n9KsDYGKhABVc4wK5u3MnVhgPinyJimyKGpr9VJYuBaY8EnJXR2x"; + std::string const manifest = "JAAAAAFxIe1FtwmimvGtH2iCcMJqC9gVFKilGfw1/vCxHXXLplc2GnMhAkE1agqXxBwDwDbID6OMSYuM0FDAlpAgNk8SKFn7MO2fdkcwRQIhAOngu9sAKqXYouJ+l2V0W+sAOkVB+ZRS6PShlJAfUsXfAiBsVJGesaadOJc/aAZokS1vymGmVrlHPKWX3Yywu6in8HASQKPugBD67kMaRFGvmpATHlGKJdvDFlWPYy5AqDedFv5TJa2w0i21eq3MYywLVJZnFOr7C0kw2AiTzSCjIzditQ8="; + + Env env{ + *this, + envconfig([&tokenBlob](std::unique_ptr cfg) { + cfg->section(SECTION_VALIDATOR_TOKEN).append(tokenBlob); + return cfg; + }) + }; + { + auto const info = env.rpc ("validator_info"); + BEAST_EXPECT(info[jss::result][jss::status] == "success"); + BEAST_EXPECT(info[jss::result][jss::seq] == 1); + BEAST_EXPECT(info[jss::result][jss::master_key] == master_key); + BEAST_EXPECT(info[jss::result][jss::manifest] == manifest); + BEAST_EXPECT(info[jss::result][jss::ephemeral_key] == ephemeral_key); + BEAST_EXPECT(info[jss::result][jss::domain] == ""); + } + } + + void run() override + { + testErrors(); + testPrivileges(); + testLookup(); + } +}; + +BEAST_DEFINE_TESTSUITE(ValidatorInfo,rpc,ripple); +} +} diff --git a/src/test/unity/rpc_test_unity.cpp b/src/test/unity/rpc_test_unity.cpp index 4aed870c8f..25a7d31746 100644 --- a/src/test/unity/rpc_test_unity.cpp +++ b/src/test/unity/rpc_test_unity.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,7 @@ #include #include #include +#include #include #include #include