mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-21 19:45:53 +00:00
Warn operators about upcoming unknown amendments:
* When an unknown amendment reaches majority, log an error-level message, and return a `warnings` array on all successful admin-level RPC calls to `server_info` and `server_state` with a message describing the problem, and the expected deadline. * In addition to the `amendment_blocked` flag returned by `server_info` and `server_state`, return a warning with a more verbose description when the server is amendment blocked. * Check on every flag ledger to see if the amendment(s) lose majority. Logs again if they don't, resumes normal operations if they did. The intention is to give operators earlier warning that their instances are in danger of being amendment blocked, which will hopefully motivate them to update ahead of time.
This commit is contained in:
committed by
Manoj doshi
parent
4315913a5d
commit
5ff23f8f31
@@ -308,13 +308,39 @@ LedgerMaster::setValidLedger(
|
|||||||
app_.getSHAMapStore().onLedgerClosed (getValidatedLedger());
|
app_.getSHAMapStore().onLedgerClosed (getValidatedLedger());
|
||||||
mLedgerHistory.validatedLedger (l, consensusHash);
|
mLedgerHistory.validatedLedger (l, consensusHash);
|
||||||
app_.getAmendmentTable().doValidatedLedger (l);
|
app_.getAmendmentTable().doValidatedLedger (l);
|
||||||
if (!app_.getOPs().isAmendmentBlocked() &&
|
if (!app_.getOPs().isAmendmentBlocked())
|
||||||
app_.getAmendmentTable().hasUnsupportedEnabled ())
|
|
||||||
{
|
{
|
||||||
JLOG (m_journal.error()) <<
|
if (app_.getAmendmentTable().hasUnsupportedEnabled())
|
||||||
"One or more unsupported amendments activated: server blocked.";
|
{
|
||||||
|
JLOG(m_journal.error()) << "One or more unsupported amendments "
|
||||||
|
"activated: server blocked.";
|
||||||
app_.getOPs().setAmendmentBlocked();
|
app_.getOPs().setAmendmentBlocked();
|
||||||
}
|
}
|
||||||
|
else if (!app_.getOPs().isAmendmentWarned() || ((l->seq() % 256) == 0))
|
||||||
|
{
|
||||||
|
// Amendments can lose majority, so re-check periodically (every
|
||||||
|
// flag ledger), and clear the flag if appropriate. If an unknown
|
||||||
|
// amendment gains majority log a warning as soon as it's
|
||||||
|
// discovered, then again every flag ledger until the operator
|
||||||
|
// upgrades, the amendment loses majority, or the amendment goes
|
||||||
|
// live and the node gets blocked. Unlike being amendment blocked,
|
||||||
|
// this message may be logged more than once per session, because
|
||||||
|
// the node will otherwise function normally, and this gives
|
||||||
|
// operators an opportunity to see and resolve the warning.
|
||||||
|
if (auto const first =
|
||||||
|
app_.getAmendmentTable().firstUnsupportedExpected())
|
||||||
|
{
|
||||||
|
JLOG(m_journal.error()) << "One or more unsupported amendments "
|
||||||
|
"reached majority. Upgrade before "
|
||||||
|
<< to_string(*first)
|
||||||
|
<< " to prevent your server from "
|
||||||
|
"becoming amendment blocked.";
|
||||||
|
app_.getOPs().setAmendmentWarned();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
app_.getOPs().clearAmendmentWarned();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ public:
|
|||||||
* @return true if an unsupported feature is enabled on the network
|
* @return true if an unsupported feature is enabled on the network
|
||||||
*/
|
*/
|
||||||
virtual bool hasUnsupportedEnabled () = 0;
|
virtual bool hasUnsupportedEnabled () = 0;
|
||||||
|
virtual boost::optional<NetClock::time_point>
|
||||||
|
firstUnsupportedExpected() = 0;
|
||||||
|
|
||||||
virtual Json::Value getJson (int) = 0;
|
virtual Json::Value getJson (int) = 0;
|
||||||
|
|
||||||
@@ -61,11 +63,15 @@ public:
|
|||||||
virtual Json::Value getJson (uint256 const& ) = 0;
|
virtual Json::Value getJson (uint256 const& ) = 0;
|
||||||
|
|
||||||
/** Called when a new fully-validated ledger is accepted. */
|
/** Called when a new fully-validated ledger is accepted. */
|
||||||
void doValidatedLedger (std::shared_ptr<ReadView const> const& lastValidatedLedger)
|
void
|
||||||
|
doValidatedLedger(
|
||||||
|
std::shared_ptr<ReadView const> const& lastValidatedLedger)
|
||||||
{
|
{
|
||||||
if (needValidatedLedger (lastValidatedLedger->seq ()))
|
if (needValidatedLedger(lastValidatedLedger->seq()))
|
||||||
doValidatedLedger (lastValidatedLedger->seq (),
|
doValidatedLedger(
|
||||||
getEnabledAmendments (*lastValidatedLedger));
|
lastValidatedLedger->seq(),
|
||||||
|
getEnabledAmendments(*lastValidatedLedger),
|
||||||
|
getMajorityAmendments(*lastValidatedLedger));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called to determine whether the amendment logic needs to process
|
/** Called to determine whether the amendment logic needs to process
|
||||||
@@ -77,7 +83,8 @@ public:
|
|||||||
virtual void
|
virtual void
|
||||||
doValidatedLedger (
|
doValidatedLedger (
|
||||||
LedgerIndex ledgerSeq,
|
LedgerIndex ledgerSeq,
|
||||||
std::set <uint256> const& enabled) = 0;
|
std::set <uint256> const& enabled,
|
||||||
|
majorityAmendments_t const& majority) = 0;
|
||||||
|
|
||||||
// Called by the consensus code when we need to
|
// Called by the consensus code when we need to
|
||||||
// inject pseudo-transactions
|
// inject pseudo-transactions
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include <ripple/app/ledger/OrderBookDB.h>
|
#include <ripple/app/ledger/OrderBookDB.h>
|
||||||
#include <ripple/app/ledger/TransactionMaster.h>
|
#include <ripple/app/ledger/TransactionMaster.h>
|
||||||
#include <ripple/app/main/LoadManager.h>
|
#include <ripple/app/main/LoadManager.h>
|
||||||
|
#include <ripple/app/misc/AmendmentTable.h>
|
||||||
#include <ripple/app/misc/HashRouter.h>
|
#include <ripple/app/misc/HashRouter.h>
|
||||||
#include <ripple/app/misc/LoadFeeTrack.h>
|
#include <ripple/app/misc/LoadFeeTrack.h>
|
||||||
#include <ripple/app/misc/Transaction.h>
|
#include <ripple/app/misc/Transaction.h>
|
||||||
@@ -389,6 +390,21 @@ public:
|
|||||||
return amendmentBlocked_;
|
return amendmentBlocked_;
|
||||||
}
|
}
|
||||||
void setAmendmentBlocked () override;
|
void setAmendmentBlocked () override;
|
||||||
|
bool
|
||||||
|
isAmendmentWarned() override
|
||||||
|
{
|
||||||
|
return !amendmentBlocked_ && amendmentWarned_;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
setAmendmentWarned() override
|
||||||
|
{
|
||||||
|
amendmentWarned_ = true;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
clearAmendmentWarned() override
|
||||||
|
{
|
||||||
|
amendmentWarned_ = false;
|
||||||
|
}
|
||||||
void consensusViewChange () override;
|
void consensusViewChange () override;
|
||||||
|
|
||||||
Json::Value getConsensusInfo () override;
|
Json::Value getConsensusInfo () override;
|
||||||
@@ -582,6 +598,7 @@ private:
|
|||||||
|
|
||||||
std::atomic <bool> needNetworkLedger_ {false};
|
std::atomic <bool> needNetworkLedger_ {false};
|
||||||
std::atomic <bool> amendmentBlocked_ {false};
|
std::atomic <bool> amendmentBlocked_ {false};
|
||||||
|
std::atomic <bool> amendmentWarned_ {false};
|
||||||
|
|
||||||
ClosureCounter<void, boost::system::error_code const&> waitHandlerCounter_;
|
ClosureCounter<void, boost::system::error_code const&> waitHandlerCounter_;
|
||||||
boost::asio::steady_timer heartbeatTimer_;
|
boost::asio::steady_timer heartbeatTimer_;
|
||||||
@@ -2258,6 +2275,38 @@ Json::Value NetworkOPsImp::getServerInfo (bool human, bool admin, bool counters)
|
|||||||
{
|
{
|
||||||
Json::Value info = Json::objectValue;
|
Json::Value info = Json::objectValue;
|
||||||
|
|
||||||
|
// System-level warnings
|
||||||
|
{
|
||||||
|
Json::Value warnings{Json::arrayValue};
|
||||||
|
if (isAmendmentBlocked())
|
||||||
|
{
|
||||||
|
Json::Value& w = warnings.append(Json::objectValue);
|
||||||
|
w[jss::id] = warnRPC_AMENDMENT_BLOCKED;
|
||||||
|
w[jss::message] =
|
||||||
|
"This server is amendment blocked, and must be updated to be "
|
||||||
|
"able to stay in sync with the network.";
|
||||||
|
}
|
||||||
|
if (admin && isAmendmentWarned())
|
||||||
|
{
|
||||||
|
Json::Value& w = warnings.append(Json::objectValue);
|
||||||
|
w[jss::id] = warnRPC_UNSUPPORTED_MAJORITY;
|
||||||
|
w[jss::message] =
|
||||||
|
"One or more unsupported amendments have reached majority. "
|
||||||
|
"Upgrade to the latest version before they are activated "
|
||||||
|
"to avoid being amendment blocked.";
|
||||||
|
if (auto const expected =
|
||||||
|
app_.getAmendmentTable().firstUnsupportedExpected())
|
||||||
|
{
|
||||||
|
auto& d = w[jss::details] = Json::objectValue;
|
||||||
|
d[jss::expected_date] = expected->time_since_epoch().count();
|
||||||
|
d[jss::expected_date_UTC] = to_string(*expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (warnings.size())
|
||||||
|
info[jss::warnings] = std::move(warnings);
|
||||||
|
}
|
||||||
|
|
||||||
// hostid: unique string describing the machine
|
// hostid: unique string describing the machine
|
||||||
if (human)
|
if (human)
|
||||||
info [jss::hostid] = getHostId (admin);
|
info [jss::hostid] = getHostId (admin);
|
||||||
|
|||||||
@@ -185,6 +185,9 @@ public:
|
|||||||
virtual void setMode(OperatingMode om) = 0;
|
virtual void setMode(OperatingMode om) = 0;
|
||||||
virtual bool isAmendmentBlocked () = 0;
|
virtual bool isAmendmentBlocked () = 0;
|
||||||
virtual void setAmendmentBlocked () = 0;
|
virtual void setAmendmentBlocked () = 0;
|
||||||
|
virtual bool isAmendmentWarned() = 0;
|
||||||
|
virtual void setAmendmentWarned() = 0;
|
||||||
|
virtual void clearAmendmentWarned() = 0;
|
||||||
virtual void consensusViewChange () = 0;
|
virtual void consensusViewChange () = 0;
|
||||||
|
|
||||||
virtual Json::Value getConsensusInfo () = 0;
|
virtual Json::Value getConsensusInfo () = 0;
|
||||||
|
|||||||
@@ -158,6 +158,10 @@ protected:
|
|||||||
|
|
||||||
// True if an unsupported amendment is enabled
|
// True if an unsupported amendment is enabled
|
||||||
bool unsupportedEnabled_;
|
bool unsupportedEnabled_;
|
||||||
|
// Unset if no unsupported amendments reach majority,
|
||||||
|
// else set to the earliest time an unsupported amendment
|
||||||
|
// will be enabled.
|
||||||
|
boost::optional<NetClock::time_point> firstUnsupportedExpected_;
|
||||||
|
|
||||||
beast::Journal const j_;
|
beast::Journal const j_;
|
||||||
|
|
||||||
@@ -190,15 +194,19 @@ public:
|
|||||||
bool isSupported (uint256 const& amendment) override;
|
bool isSupported (uint256 const& amendment) override;
|
||||||
|
|
||||||
bool hasUnsupportedEnabled () override;
|
bool hasUnsupportedEnabled () override;
|
||||||
|
boost::optional<NetClock::time_point>
|
||||||
|
firstUnsupportedExpected() override;
|
||||||
|
|
||||||
Json::Value getJson (int) override;
|
Json::Value getJson (int) override;
|
||||||
Json::Value getJson (uint256 const&) override;
|
Json::Value getJson (uint256 const&) override;
|
||||||
|
|
||||||
bool needValidatedLedger (LedgerIndex seq) override;
|
bool needValidatedLedger (LedgerIndex seq) override;
|
||||||
|
|
||||||
void doValidatedLedger (
|
void
|
||||||
|
doValidatedLedger(
|
||||||
LedgerIndex seq,
|
LedgerIndex seq,
|
||||||
std::set<uint256> const& enabled) override;
|
std::set<uint256> const& enabled,
|
||||||
|
majorityAmendments_t const& majority) override;
|
||||||
|
|
||||||
std::vector <uint256>
|
std::vector <uint256>
|
||||||
doValidation (std::set<uint256> const& enabledAmendments) override;
|
doValidation (std::set<uint256> const& enabledAmendments) override;
|
||||||
@@ -392,6 +400,13 @@ AmendmentTableImpl::hasUnsupportedEnabled ()
|
|||||||
return unsupportedEnabled_;
|
return unsupportedEnabled_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::optional<NetClock::time_point>
|
||||||
|
AmendmentTableImpl::firstUnsupportedExpected()
|
||||||
|
{
|
||||||
|
std::lock_guard sl(mutex_);
|
||||||
|
return firstUnsupportedExpected_;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector <uint256>
|
std::vector <uint256>
|
||||||
AmendmentTableImpl::doValidation (
|
AmendmentTableImpl::doValidation (
|
||||||
std::set<uint256> const& enabled)
|
std::set<uint256> const& enabled)
|
||||||
@@ -539,12 +554,36 @@ AmendmentTableImpl::needValidatedLedger (LedgerIndex ledgerSeq)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AmendmentTableImpl::doValidatedLedger (
|
AmendmentTableImpl::doValidatedLedger(
|
||||||
LedgerIndex ledgerSeq,
|
LedgerIndex ledgerSeq,
|
||||||
std::set<uint256> const& enabled)
|
std::set<uint256> const& enabled,
|
||||||
|
majorityAmendments_t const& majority)
|
||||||
{
|
{
|
||||||
for (auto& e : enabled)
|
for (auto& e : enabled)
|
||||||
enable(e);
|
enable(e);
|
||||||
|
|
||||||
|
std::lock_guard sl(mutex_);
|
||||||
|
// Since we have the whole list in `majority`, reset the time flag, even if
|
||||||
|
// it's currently set. If it's not set when the loop is done, then any
|
||||||
|
// prior unknown amendments have lost majority.
|
||||||
|
firstUnsupportedExpected_.reset();
|
||||||
|
for (auto const& [ hash, time ] : majority)
|
||||||
|
{
|
||||||
|
auto s = add(hash);
|
||||||
|
|
||||||
|
if (s->enabled)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!s->supported)
|
||||||
|
{
|
||||||
|
JLOG(j_.info()) << "Unsupported amendment " << hash
|
||||||
|
<< " reached majority at " << to_string(time);
|
||||||
|
if (!firstUnsupportedExpected_ || firstUnsupportedExpected_ > time)
|
||||||
|
firstUnsupportedExpected_ = time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (firstUnsupportedExpected_)
|
||||||
|
firstUnsupportedExpected_ = *firstUnsupportedExpected_ + majorityTime_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -138,6 +138,16 @@ enum error_code_i
|
|||||||
rpcLAST = rpcINVALID_LGR_RANGE // rpcLAST should always equal the last code.=
|
rpcLAST = rpcINVALID_LGR_RANGE // rpcLAST should always equal the last code.=
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Codes returned in the `warnings` array of certain RPC commands.
|
||||||
|
|
||||||
|
These values need to remain stable.
|
||||||
|
*/
|
||||||
|
enum warning_code_i
|
||||||
|
{
|
||||||
|
warnRPC_UNSUPPORTED_MAJORITY = 1001,
|
||||||
|
warnRPC_AMENDMENT_BLOCKED = 1002,
|
||||||
|
};
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
// VFALCO NOTE these should probably not be in the RPC namespace.
|
// VFALCO NOTE these should probably not be in the RPC namespace.
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ JSS ( destination_amount ); // in: PathRequest, RipplePathFind
|
|||||||
JSS ( destination_currencies ); // in: PathRequest, RipplePathFind
|
JSS ( destination_currencies ); // in: PathRequest, RipplePathFind
|
||||||
JSS ( destination_tag ); // in: PathRequest
|
JSS ( destination_tag ); // in: PathRequest
|
||||||
// out: AccountChannels
|
// out: AccountChannels
|
||||||
JSS ( details ); // out: Manifest
|
JSS ( details ); // out: Manifest, server_info
|
||||||
JSS ( dir_entry ); // out: DirectoryEntryIterator
|
JSS ( dir_entry ); // out: DirectoryEntryIterator
|
||||||
JSS ( dir_index ); // out: DirectoryEntryIterator
|
JSS ( dir_index ); // out: DirectoryEntryIterator
|
||||||
JSS ( dir_root ); // out: DirectoryEntryIterator
|
JSS ( dir_root ); // out: DirectoryEntryIterator
|
||||||
@@ -223,6 +223,8 @@ JSS ( error_exception ); // out: Submit
|
|||||||
JSS ( error_message ); // out: error
|
JSS ( error_message ); // out: error
|
||||||
JSS ( escrow ); // in: LedgerEntry
|
JSS ( escrow ); // in: LedgerEntry
|
||||||
JSS ( expand ); // in: handler/Ledger
|
JSS ( expand ); // in: handler/Ledger
|
||||||
|
JSS ( expected_date ); // out: any (warnings)
|
||||||
|
JSS ( expected_date_UTC ); // out: any (warnings)
|
||||||
JSS ( expected_ledger_size ); // out: TxQ
|
JSS ( expected_ledger_size ); // out: TxQ
|
||||||
JSS ( expiration ); // out: AccountOffers, AccountChannels,
|
JSS ( expiration ); // out: AccountOffers, AccountChannels,
|
||||||
// ValidatorList
|
// ValidatorList
|
||||||
@@ -573,6 +575,7 @@ JSS ( version ); // out: RPCVersion
|
|||||||
JSS ( vetoed ); // out: AmendmentTableImpl
|
JSS ( vetoed ); // out: AmendmentTableImpl
|
||||||
JSS ( vote ); // in: Feature
|
JSS ( vote ); // in: Feature
|
||||||
JSS ( warning ); // rpc:
|
JSS ( warning ); // rpc:
|
||||||
|
JSS ( warnings ); // out: server_info, server_state
|
||||||
JSS ( workers );
|
JSS ( workers );
|
||||||
JSS ( write_load ); // out: GetCounts
|
JSS ( write_load ); // out: GetCounts
|
||||||
|
|
||||||
|
|||||||
@@ -189,38 +189,6 @@ Status callMethod (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Method, class Object>
|
|
||||||
void getResult (
|
|
||||||
JsonContext& context, Method method, Object& object, std::string const& name)
|
|
||||||
{
|
|
||||||
auto&& result = Json::addObject (object, jss::result);
|
|
||||||
if (auto status = callMethod (context, method, name, result))
|
|
||||||
{
|
|
||||||
JLOG (context.j.debug()) << "rpcError: " << status.toString();
|
|
||||||
result[jss::status] = jss::error;
|
|
||||||
|
|
||||||
auto rq = context.params;
|
|
||||||
|
|
||||||
if (rq.isObject())
|
|
||||||
{
|
|
||||||
if (rq.isMember(jss::passphrase.c_str()))
|
|
||||||
rq[jss::passphrase.c_str()] = "<masked>";
|
|
||||||
if (rq.isMember(jss::secret.c_str()))
|
|
||||||
rq[jss::secret.c_str()] = "<masked>";
|
|
||||||
if (rq.isMember(jss::seed.c_str()))
|
|
||||||
rq[jss::seed.c_str()] = "<masked>";
|
|
||||||
if (rq.isMember(jss::seed_hex.c_str()))
|
|
||||||
rq[jss::seed_hex.c_str()] = "<masked>";
|
|
||||||
}
|
|
||||||
|
|
||||||
result[jss::request] = rq;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result[jss::status] = jss::success;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Status doCommand (
|
Status doCommand (
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ private:
|
|||||||
std::vector<std::string> const m_set2;
|
std::vector<std::string> const m_set2;
|
||||||
std::vector<std::string> const m_set3;
|
std::vector<std::string> const m_set3;
|
||||||
std::vector<std::string> const m_set4;
|
std::vector<std::string> const m_set4;
|
||||||
|
std::vector<std::string> const m_set5;
|
||||||
|
|
||||||
Section const emptySection;
|
Section const emptySection;
|
||||||
|
|
||||||
@@ -98,6 +99,7 @@ public:
|
|||||||
, m_set2 (createSet (2, 12))
|
, m_set2 (createSet (2, 12))
|
||||||
, m_set3 (createSet (3, 12))
|
, m_set3 (createSet (3, 12))
|
||||||
, m_set4 (createSet (4, 12))
|
, m_set4 (createSet (4, 12))
|
||||||
|
, m_set5 (createSet (5, 12))
|
||||||
, journal ("AmendmentTable_test", *this)
|
, journal ("AmendmentTable_test", *this)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -168,6 +170,8 @@ public:
|
|||||||
BEAST_EXPECT(!table->find (a));
|
BEAST_EXPECT(!table->find (a));
|
||||||
for (auto const& a : m_set4)
|
for (auto const& a : m_set4)
|
||||||
BEAST_EXPECT(!table->find (a));
|
BEAST_EXPECT(!table->find (a));
|
||||||
|
for (auto const& a : m_set5)
|
||||||
|
BEAST_EXPECT(!table->find (a));
|
||||||
}
|
}
|
||||||
|
|
||||||
void testBadConfig ()
|
void testBadConfig ()
|
||||||
@@ -283,6 +287,7 @@ public:
|
|||||||
track (m_set2);
|
track (m_set2);
|
||||||
track (m_set3);
|
track (m_set3);
|
||||||
track (m_set4);
|
track (m_set4);
|
||||||
|
track (m_set5);
|
||||||
|
|
||||||
for (auto const& a : exclude)
|
for (auto const& a : exclude)
|
||||||
state.erase(a);
|
state.erase(a);
|
||||||
@@ -304,6 +309,7 @@ public:
|
|||||||
enabled.insert (amendmentId(m_set2[0]));
|
enabled.insert (amendmentId(m_set2[0]));
|
||||||
enabled.insert (amendmentId(m_set3[0]));
|
enabled.insert (amendmentId(m_set3[0]));
|
||||||
enabled.insert (amendmentId(m_set4[0]));
|
enabled.insert (amendmentId(m_set4[0]));
|
||||||
|
enabled.insert (amendmentId(m_set5[0]));
|
||||||
|
|
||||||
// Get the state before, excluding the items we'll change:
|
// Get the state before, excluding the items we'll change:
|
||||||
auto const pre_state = getState (table.get(), enabled);
|
auto const pre_state = getState (table.get(), enabled);
|
||||||
@@ -741,14 +747,31 @@ public:
|
|||||||
{
|
{
|
||||||
testcase ("hasUnsupportedEnabled");
|
testcase ("hasUnsupportedEnabled");
|
||||||
|
|
||||||
auto table = makeTable(1);
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
int constexpr w = 1;
|
||||||
|
auto table = makeTable(w);
|
||||||
BEAST_EXPECT(! table->hasUnsupportedEnabled());
|
BEAST_EXPECT(! table->hasUnsupportedEnabled());
|
||||||
|
BEAST_EXPECT(! table->firstUnsupportedExpected());
|
||||||
|
|
||||||
std::set <uint256> enabled;
|
std::set <uint256> enabled;
|
||||||
|
majorityAmendments_t majority;
|
||||||
std::for_each(m_set4.begin(), m_set4.end(),
|
std::for_each(m_set4.begin(), m_set4.end(),
|
||||||
[&enabled](auto const &s){ enabled.insert(amendmentId(s)); });
|
[&enabled](auto const &s){ enabled.insert(amendmentId(s)); });
|
||||||
table->doValidatedLedger(1, enabled);
|
table->doValidatedLedger(1, enabled, majority);
|
||||||
BEAST_EXPECT(table->hasUnsupportedEnabled());
|
BEAST_EXPECT(table->hasUnsupportedEnabled());
|
||||||
|
BEAST_EXPECT(!table->firstUnsupportedExpected());
|
||||||
|
NetClock::duration t{1000s};
|
||||||
|
std::for_each(
|
||||||
|
m_set5.begin(), m_set5.end(), [&majority, &t](auto const& s) {
|
||||||
|
majority[amendmentId(s)] = NetClock::time_point{--t};
|
||||||
|
});
|
||||||
|
table->doValidatedLedger(1, enabled, majority);
|
||||||
|
BEAST_EXPECT(table->hasUnsupportedEnabled());
|
||||||
|
BEAST_EXPECT(
|
||||||
|
table->firstUnsupportedExpected() &&
|
||||||
|
*table->firstUnsupportedExpected() ==
|
||||||
|
NetClock::time_point{t} + weeks{w});
|
||||||
}
|
}
|
||||||
|
|
||||||
void run () override
|
void run () override
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <test/jtx.h>
|
#include <test/jtx.h>
|
||||||
#include <ripple/core/ConfigSections.h>
|
#include <ripple/core/ConfigSections.h>
|
||||||
#include <ripple/protocol/jss.h>
|
#include <ripple/protocol/jss.h>
|
||||||
|
#include <ripple/protocol/ErrorCodes.h>
|
||||||
#include <ripple/app/misc/NetworkOPs.h>
|
#include <ripple/app/misc/NetworkOPs.h>
|
||||||
#include <test/jtx/WSClient.h>
|
#include <test/jtx/WSClient.h>
|
||||||
|
|
||||||
@@ -39,7 +40,9 @@ class AmendmentBlocked_test : public beast::unit_test::suite
|
|||||||
auto const USD = gw["USD"];
|
auto const USD = gw["USD"];
|
||||||
auto const alice = Account {"alice"};
|
auto const alice = Account {"alice"};
|
||||||
auto const bob = Account {"bob"};
|
auto const bob = Account {"bob"};
|
||||||
|
Account const ali {"ali", KeyType::secp256k1};
|
||||||
env.fund (XRP(10000), alice, bob, gw);
|
env.fund (XRP(10000), alice, bob, gw);
|
||||||
|
env.memoize(ali);
|
||||||
env.trust (USD(600), alice);
|
env.trust (USD(600), alice);
|
||||||
env.trust (USD(700), bob);
|
env.trust (USD(700), bob);
|
||||||
env(pay (gw, alice, USD(70)));
|
env(pay (gw, alice, USD(70)));
|
||||||
@@ -52,14 +55,17 @@ class AmendmentBlocked_test : public beast::unit_test::suite
|
|||||||
// ledger_accept
|
// ledger_accept
|
||||||
auto jr = env.rpc ("ledger_accept") [jss::result];
|
auto jr = env.rpc ("ledger_accept") [jss::result];
|
||||||
BEAST_EXPECT (jr[jss::ledger_current_index] == current->seq ()+1);
|
BEAST_EXPECT (jr[jss::ledger_current_index] == current->seq ()+1);
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
|
|
||||||
// ledger_current
|
// ledger_current
|
||||||
jr = env.rpc ("ledger_current") [jss::result];
|
jr = env.rpc ("ledger_current") [jss::result];
|
||||||
BEAST_EXPECT (jr[jss::ledger_current_index] == current->seq ()+1);
|
BEAST_EXPECT (jr[jss::ledger_current_index] == current->seq ()+1);
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
|
|
||||||
// owner_info
|
// owner_info
|
||||||
jr = env.rpc ("owner_info", alice.human()) [jss::result];
|
jr = env.rpc ("owner_info", alice.human()) [jss::result];
|
||||||
BEAST_EXPECT (jr.isMember (jss::accepted) && jr.isMember (jss::current));
|
BEAST_EXPECT (jr.isMember (jss::accepted) && jr.isMember (jss::current));
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
|
|
||||||
// path_find
|
// path_find
|
||||||
Json::Value pf_req;
|
Json::Value pf_req;
|
||||||
@@ -72,6 +78,7 @@ class AmendmentBlocked_test : public beast::unit_test::suite
|
|||||||
BEAST_EXPECT (jr.isMember (jss::alternatives) &&
|
BEAST_EXPECT (jr.isMember (jss::alternatives) &&
|
||||||
jr[jss::alternatives].isArray() &&
|
jr[jss::alternatives].isArray() &&
|
||||||
jr[jss::alternatives].size () == 1);
|
jr[jss::alternatives].size () == 1);
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
|
|
||||||
// submit
|
// submit
|
||||||
auto jt = env.jt (noop (alice));
|
auto jt = env.jt (noop (alice));
|
||||||
@@ -80,10 +87,10 @@ class AmendmentBlocked_test : public beast::unit_test::suite
|
|||||||
jr = env.rpc ("submit", strHex (s.slice ())) [jss::result];
|
jr = env.rpc ("submit", strHex (s.slice ())) [jss::result];
|
||||||
BEAST_EXPECT (jr.isMember (jss::engine_result) &&
|
BEAST_EXPECT (jr.isMember (jss::engine_result) &&
|
||||||
jr[jss::engine_result] == "tesSUCCESS");
|
jr[jss::engine_result] == "tesSUCCESS");
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
|
|
||||||
// submit_multisigned
|
// submit_multisigned
|
||||||
env(signers(bob, 1, {{alice, 1}}), sig (bob));
|
env(signers(bob, 1, {{alice, 1}}), sig (bob));
|
||||||
Account const ali {"ali", KeyType::secp256k1};
|
|
||||||
env(regkey (alice, ali));
|
env(regkey (alice, ali));
|
||||||
env.close();
|
env.close();
|
||||||
|
|
||||||
@@ -101,6 +108,7 @@ class AmendmentBlocked_test : public beast::unit_test::suite
|
|||||||
sign_for[jss::secret] = ali.name();
|
sign_for[jss::secret] = ali.name();
|
||||||
jr = env.rpc("json", "sign_for", to_string(sign_for)) [jss::result];
|
jr = env.rpc("json", "sign_for", to_string(sign_for)) [jss::result];
|
||||||
BEAST_EXPECT(jr[jss::status] == "success");
|
BEAST_EXPECT(jr[jss::status] == "success");
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
|
|
||||||
Json::Value ms_req;
|
Json::Value ms_req;
|
||||||
ms_req[jss::tx_json] = jr[jss::tx_json];
|
ms_req[jss::tx_json] = jr[jss::tx_json];
|
||||||
@@ -108,6 +116,74 @@ class AmendmentBlocked_test : public beast::unit_test::suite
|
|||||||
[jss::result];
|
[jss::result];
|
||||||
BEAST_EXPECT (jr.isMember (jss::engine_result) &&
|
BEAST_EXPECT (jr.isMember (jss::engine_result) &&
|
||||||
jr[jss::engine_result] == "tesSUCCESS");
|
jr[jss::engine_result] == "tesSUCCESS");
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
|
|
||||||
|
// set up an amendment warning. Nothing changes
|
||||||
|
|
||||||
|
env.app ().getOPs ().setAmendmentWarned ();
|
||||||
|
|
||||||
|
current = env.current ();
|
||||||
|
// ledger_accept
|
||||||
|
jr = env.rpc ("ledger_accept") [jss::result];
|
||||||
|
BEAST_EXPECT (jr[jss::ledger_current_index] == current->seq ()+1);
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
|
|
||||||
|
// ledger_current
|
||||||
|
jr = env.rpc ("ledger_current") [jss::result];
|
||||||
|
BEAST_EXPECT (jr[jss::ledger_current_index] == current->seq ()+1);
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
|
|
||||||
|
// owner_info
|
||||||
|
jr = env.rpc ("owner_info", alice.human()) [jss::result];
|
||||||
|
BEAST_EXPECT (jr.isMember (jss::accepted) && jr.isMember (jss::current));
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
|
|
||||||
|
// path_find
|
||||||
|
pf_req[jss::subcommand] = "create";
|
||||||
|
pf_req[jss::source_account] = alice.human();
|
||||||
|
pf_req[jss::destination_account] = bob.human();
|
||||||
|
pf_req[jss::destination_amount] =
|
||||||
|
bob["USD"](20).value ().getJson (JsonOptions::none);
|
||||||
|
jr = wsc->invoke("path_find", pf_req) [jss::result];
|
||||||
|
BEAST_EXPECT (jr.isMember (jss::alternatives) &&
|
||||||
|
jr[jss::alternatives].isArray() &&
|
||||||
|
jr[jss::alternatives].size () == 1);
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
|
|
||||||
|
// submit
|
||||||
|
jt = env.jt (noop (alice));
|
||||||
|
s.erase();
|
||||||
|
jt.stx->add (s);
|
||||||
|
jr = env.rpc ("submit", strHex (s.slice ())) [jss::result];
|
||||||
|
BEAST_EXPECT (jr.isMember (jss::engine_result) &&
|
||||||
|
jr[jss::engine_result] == "tesSUCCESS");
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
|
|
||||||
|
// submit_multisigned
|
||||||
|
env(signers(bob, 1, {{alice, 1}}), sig (bob));
|
||||||
|
env(regkey (alice, ali));
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
set_tx[jss::Account] = bob.human();
|
||||||
|
set_tx[jss::TransactionType] = jss::AccountSet;
|
||||||
|
set_tx[jss::Fee] =
|
||||||
|
(8 * env.current()->fees().base).jsonClipped();
|
||||||
|
set_tx[jss::Sequence] = env.seq(bob);
|
||||||
|
set_tx[jss::SigningPubKey] = "";
|
||||||
|
|
||||||
|
sign_for[jss::tx_json] = set_tx;
|
||||||
|
sign_for[jss::account] = alice.human();
|
||||||
|
sign_for[jss::secret] = ali.name();
|
||||||
|
jr = env.rpc("json", "sign_for", to_string(sign_for)) [jss::result];
|
||||||
|
BEAST_EXPECT(jr[jss::status] == "success");
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
|
|
||||||
|
ms_req[jss::tx_json] = jr[jss::tx_json];
|
||||||
|
jr = env.rpc("json", "submit_multisigned", to_string(ms_req))
|
||||||
|
[jss::result];
|
||||||
|
BEAST_EXPECT (jr.isMember (jss::engine_result) &&
|
||||||
|
jr[jss::engine_result] == "tesSUCCESS");
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
|
|
||||||
// make the network amendment blocked...now all the same
|
// make the network amendment blocked...now all the same
|
||||||
// requests should fail
|
// requests should fail
|
||||||
@@ -120,6 +196,7 @@ class AmendmentBlocked_test : public beast::unit_test::suite
|
|||||||
jr.isMember (jss::error) &&
|
jr.isMember (jss::error) &&
|
||||||
jr[jss::error] == "amendmentBlocked");
|
jr[jss::error] == "amendmentBlocked");
|
||||||
BEAST_EXPECT(jr[jss::status] == "error");
|
BEAST_EXPECT(jr[jss::status] == "error");
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
|
|
||||||
// ledger_current
|
// ledger_current
|
||||||
jr = env.rpc ("ledger_current") [jss::result];
|
jr = env.rpc ("ledger_current") [jss::result];
|
||||||
@@ -127,6 +204,7 @@ class AmendmentBlocked_test : public beast::unit_test::suite
|
|||||||
jr.isMember (jss::error) &&
|
jr.isMember (jss::error) &&
|
||||||
jr[jss::error] == "amendmentBlocked");
|
jr[jss::error] == "amendmentBlocked");
|
||||||
BEAST_EXPECT(jr[jss::status] == "error");
|
BEAST_EXPECT(jr[jss::status] == "error");
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
|
|
||||||
// owner_info
|
// owner_info
|
||||||
jr = env.rpc ("owner_info", alice.human()) [jss::result];
|
jr = env.rpc ("owner_info", alice.human()) [jss::result];
|
||||||
@@ -134,6 +212,7 @@ class AmendmentBlocked_test : public beast::unit_test::suite
|
|||||||
jr.isMember (jss::error) &&
|
jr.isMember (jss::error) &&
|
||||||
jr[jss::error] == "amendmentBlocked");
|
jr[jss::error] == "amendmentBlocked");
|
||||||
BEAST_EXPECT(jr[jss::status] == "error");
|
BEAST_EXPECT(jr[jss::status] == "error");
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
|
|
||||||
// path_find
|
// path_find
|
||||||
jr = wsc->invoke("path_find", pf_req) [jss::result];
|
jr = wsc->invoke("path_find", pf_req) [jss::result];
|
||||||
@@ -141,6 +220,7 @@ class AmendmentBlocked_test : public beast::unit_test::suite
|
|||||||
jr.isMember (jss::error) &&
|
jr.isMember (jss::error) &&
|
||||||
jr[jss::error] == "amendmentBlocked");
|
jr[jss::error] == "amendmentBlocked");
|
||||||
BEAST_EXPECT(jr[jss::status] == "error");
|
BEAST_EXPECT(jr[jss::status] == "error");
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
|
|
||||||
// submit
|
// submit
|
||||||
jr = env.rpc("submit", strHex(s.slice())) [jss::result];
|
jr = env.rpc("submit", strHex(s.slice())) [jss::result];
|
||||||
@@ -148,6 +228,7 @@ class AmendmentBlocked_test : public beast::unit_test::suite
|
|||||||
jr.isMember (jss::error) &&
|
jr.isMember (jss::error) &&
|
||||||
jr[jss::error] == "amendmentBlocked");
|
jr[jss::error] == "amendmentBlocked");
|
||||||
BEAST_EXPECT(jr[jss::status] == "error");
|
BEAST_EXPECT(jr[jss::status] == "error");
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
|
|
||||||
// submit_multisigned
|
// submit_multisigned
|
||||||
set_tx[jss::Sequence] = env.seq(bob);
|
set_tx[jss::Sequence] = env.seq(bob);
|
||||||
@@ -160,6 +241,7 @@ class AmendmentBlocked_test : public beast::unit_test::suite
|
|||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
jr.isMember (jss::error) &&
|
jr.isMember (jss::error) &&
|
||||||
jr[jss::error] == "amendmentBlocked");
|
jr[jss::error] == "amendmentBlocked");
|
||||||
|
BEAST_EXPECT(!jr.isMember(jss::warnings));
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -167,6 +167,7 @@ class ServerStatus_test :
|
|||||||
if(ec)
|
if(ec)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
resp.body().clear();
|
||||||
if(secure)
|
if(secure)
|
||||||
{
|
{
|
||||||
ssl::context ctx{ssl::context::sslv23};
|
ssl::context ctx{ssl::context::sslv23};
|
||||||
@@ -785,6 +786,132 @@ class ServerStatus_test :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
testAmendmentWarning(boost::asio::yield_context& yield)
|
||||||
|
{
|
||||||
|
testcase("Status request over WS and RPC with/without Amendment Warning");
|
||||||
|
using namespace jtx;
|
||||||
|
using namespace boost::asio;
|
||||||
|
using namespace boost::beast::http;
|
||||||
|
Env env {*this, validator( envconfig([](std::unique_ptr<Config> cfg)
|
||||||
|
{
|
||||||
|
cfg->section("port_rpc").set("protocol", "http");
|
||||||
|
return cfg;
|
||||||
|
}), "")};
|
||||||
|
|
||||||
|
env.close();
|
||||||
|
|
||||||
|
// advance the ledger so that server status
|
||||||
|
// sees a published ledger -- without this, we get a status
|
||||||
|
// failure message about no published ledgers
|
||||||
|
env.app().getLedgerMaster().tryAdvance();
|
||||||
|
|
||||||
|
// make an RPC server info request and look for
|
||||||
|
// amendment warning status
|
||||||
|
auto si = env.rpc("server_info") [jss::result];
|
||||||
|
BEAST_EXPECT(si.isMember(jss::info));
|
||||||
|
BEAST_EXPECT(! si[jss::info].isMember(jss::amendment_blocked));
|
||||||
|
BEAST_EXPECT(
|
||||||
|
env.app().getOPs().getConsensusInfo()["validating"] == true);
|
||||||
|
BEAST_EXPECT(! si.isMember(jss::warnings));
|
||||||
|
|
||||||
|
// make an RPC server state request and look for
|
||||||
|
// amendment warning status
|
||||||
|
si = env.rpc("server_state") [jss::result];
|
||||||
|
BEAST_EXPECT(si.isMember(jss::state));
|
||||||
|
BEAST_EXPECT(! si[jss::state].isMember(jss::amendment_blocked));
|
||||||
|
BEAST_EXPECT(
|
||||||
|
env.app().getOPs().getConsensusInfo()["validating"] == true);
|
||||||
|
BEAST_EXPECT(! si[jss::state].isMember(jss::warnings));
|
||||||
|
|
||||||
|
auto const port_ws = env.app().config()["port_ws"].
|
||||||
|
get<std::uint16_t>("port");
|
||||||
|
auto const ip_ws = env.app().config()["port_ws"].
|
||||||
|
get<std::string>("ip");
|
||||||
|
|
||||||
|
boost::system::error_code ec;
|
||||||
|
response<string_body> resp;
|
||||||
|
|
||||||
|
doRequest(
|
||||||
|
yield,
|
||||||
|
makeHTTPRequest(*ip_ws, *port_ws, "", {}),
|
||||||
|
*ip_ws,
|
||||||
|
*port_ws,
|
||||||
|
false,
|
||||||
|
resp,
|
||||||
|
ec);
|
||||||
|
|
||||||
|
if(! BEAST_EXPECTS(! ec, ec.message()))
|
||||||
|
return;
|
||||||
|
BEAST_EXPECT(resp.result() == boost::beast::http::status::ok);
|
||||||
|
BEAST_EXPECT(
|
||||||
|
resp.body().find("connectivity is working.") != std::string::npos);
|
||||||
|
|
||||||
|
// mark the Network as having an Amendment Warning, but won't fail
|
||||||
|
env.app().getOPs().setAmendmentWarned ();
|
||||||
|
env.app().getOPs().beginConsensus(env.closed()->info().hash);
|
||||||
|
|
||||||
|
// consensus doesn't change
|
||||||
|
BEAST_EXPECT(
|
||||||
|
env.app().getOPs().getConsensusInfo()["validating"] == true);
|
||||||
|
|
||||||
|
// RPC request server_info again, now unsupported majority should be returned
|
||||||
|
si = env.rpc("server_info") [jss::result];
|
||||||
|
BEAST_EXPECT(si.isMember(jss::info));
|
||||||
|
BEAST_EXPECT(! si[jss::info].isMember(jss::amendment_blocked));
|
||||||
|
BEAST_EXPECT(
|
||||||
|
si[jss::info].isMember(jss::warnings) &&
|
||||||
|
si[jss::info][jss::warnings].isArray() &&
|
||||||
|
si[jss::info][jss::warnings].size() == 1 &&
|
||||||
|
si[jss::info][jss::warnings][0u][jss::id].asInt() ==
|
||||||
|
warnRPC_UNSUPPORTED_MAJORITY);
|
||||||
|
|
||||||
|
// RPC request server_state again, now unsupported majority should be returned
|
||||||
|
si = env.rpc("server_state") [jss::result];
|
||||||
|
BEAST_EXPECT(si.isMember(jss::state));
|
||||||
|
BEAST_EXPECT(! si[jss::state].isMember(jss::amendment_blocked));
|
||||||
|
BEAST_EXPECT(
|
||||||
|
si[jss::state].isMember(jss::warnings) &&
|
||||||
|
si[jss::state][jss::warnings].isArray() &&
|
||||||
|
si[jss::state][jss::warnings].size() == 1 &&
|
||||||
|
si[jss::state][jss::warnings][0u][jss::id].asInt() ==
|
||||||
|
warnRPC_UNSUPPORTED_MAJORITY);
|
||||||
|
|
||||||
|
// but status does not indicate a problem
|
||||||
|
doRequest(
|
||||||
|
yield,
|
||||||
|
makeHTTPRequest(*ip_ws, *port_ws, "", {}),
|
||||||
|
*ip_ws,
|
||||||
|
*port_ws,
|
||||||
|
false,
|
||||||
|
resp,
|
||||||
|
ec);
|
||||||
|
|
||||||
|
if(! BEAST_EXPECTS(! ec, ec.message()))
|
||||||
|
return;
|
||||||
|
BEAST_EXPECT(resp.result() == boost::beast::http::status::ok);
|
||||||
|
BEAST_EXPECT(
|
||||||
|
resp.body().find("connectivity is working.") != std::string::npos);
|
||||||
|
|
||||||
|
// with ELB_SUPPORT, status still does not indicate a problem
|
||||||
|
env.app().config().ELB_SUPPORT = true;
|
||||||
|
|
||||||
|
doRequest(
|
||||||
|
yield,
|
||||||
|
makeHTTPRequest(*ip_ws, *port_ws, "", {}),
|
||||||
|
*ip_ws,
|
||||||
|
*port_ws,
|
||||||
|
false,
|
||||||
|
resp,
|
||||||
|
ec);
|
||||||
|
|
||||||
|
if(! BEAST_EXPECTS(! ec, ec.message()))
|
||||||
|
return;
|
||||||
|
BEAST_EXPECT(resp.result() == boost::beast::http::status::ok);
|
||||||
|
BEAST_EXPECT(
|
||||||
|
resp.body().find("connectivity is working.") != std::string::npos);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
testAmendmentBlock(boost::asio::yield_context& yield)
|
testAmendmentBlock(boost::asio::yield_context& yield)
|
||||||
{
|
{
|
||||||
@@ -808,9 +935,20 @@ class ServerStatus_test :
|
|||||||
// make an RPC server info request and look for
|
// make an RPC server info request and look for
|
||||||
// amendment_blocked status
|
// amendment_blocked status
|
||||||
auto si = env.rpc("server_info") [jss::result];
|
auto si = env.rpc("server_info") [jss::result];
|
||||||
|
BEAST_EXPECT(si.isMember(jss::info));
|
||||||
BEAST_EXPECT(! si[jss::info].isMember(jss::amendment_blocked));
|
BEAST_EXPECT(! si[jss::info].isMember(jss::amendment_blocked));
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
env.app().getOPs().getConsensusInfo()["validating"] == true);
|
env.app().getOPs().getConsensusInfo()["validating"] == true);
|
||||||
|
BEAST_EXPECT(! si.isMember(jss::warnings));
|
||||||
|
|
||||||
|
// make an RPC server state request and look for
|
||||||
|
// amendment_blocked status
|
||||||
|
si = env.rpc("server_state") [jss::result];
|
||||||
|
BEAST_EXPECT(si.isMember(jss::state));
|
||||||
|
BEAST_EXPECT(! si[jss::state].isMember(jss::amendment_blocked));
|
||||||
|
BEAST_EXPECT(
|
||||||
|
env.app().getOPs().getConsensusInfo()["validating"] == true);
|
||||||
|
BEAST_EXPECT(! si[jss::state].isMember(jss::warnings));
|
||||||
|
|
||||||
auto const port_ws = env.app().config()["port_ws"].
|
auto const port_ws = env.app().config()["port_ws"].
|
||||||
get<std::uint16_t>("port");
|
get<std::uint16_t>("port");
|
||||||
@@ -847,9 +985,28 @@ class ServerStatus_test :
|
|||||||
|
|
||||||
// RPC request server_info again, now AB should be returned
|
// RPC request server_info again, now AB should be returned
|
||||||
si = env.rpc("server_info") [jss::result];
|
si = env.rpc("server_info") [jss::result];
|
||||||
|
BEAST_EXPECT(si.isMember(jss::info));
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
si[jss::info].isMember(jss::amendment_blocked) &&
|
si[jss::info].isMember(jss::amendment_blocked) &&
|
||||||
si[jss::info][jss::amendment_blocked] == true);
|
si[jss::info][jss::amendment_blocked] == true);
|
||||||
|
BEAST_EXPECT(
|
||||||
|
si[jss::info].isMember(jss::warnings) &&
|
||||||
|
si[jss::info][jss::warnings].isArray() &&
|
||||||
|
si[jss::info][jss::warnings].size() == 1 &&
|
||||||
|
si[jss::info][jss::warnings][0u][jss::id].asInt() ==
|
||||||
|
warnRPC_AMENDMENT_BLOCKED);
|
||||||
|
|
||||||
|
// RPC request server_state again, now AB should be returned
|
||||||
|
si = env.rpc("server_state") [jss::result];
|
||||||
|
BEAST_EXPECT(
|
||||||
|
si[jss::state].isMember(jss::amendment_blocked) &&
|
||||||
|
si[jss::state][jss::amendment_blocked] == true);
|
||||||
|
BEAST_EXPECT(
|
||||||
|
si[jss::state].isMember(jss::warnings) &&
|
||||||
|
si[jss::state][jss::warnings].isArray() &&
|
||||||
|
si[jss::state][jss::warnings].size() == 1 &&
|
||||||
|
si[jss::state][jss::warnings][0u][jss::id].asInt() ==
|
||||||
|
warnRPC_AMENDMENT_BLOCKED);
|
||||||
|
|
||||||
// but status does not indicate because it still relies on ELB
|
// but status does not indicate because it still relies on ELB
|
||||||
// being enabled
|
// being enabled
|
||||||
@@ -1046,6 +1203,7 @@ public:
|
|||||||
testCantConnect ("wss2", "ws2", yield);
|
testCantConnect ("wss2", "ws2", yield);
|
||||||
testCantConnect ("https", "http", yield);
|
testCantConnect ("https", "http", yield);
|
||||||
|
|
||||||
|
testAmendmentWarning(yield);
|
||||||
testAmendmentBlock(yield);
|
testAmendmentBlock(yield);
|
||||||
testAuth (false, yield);
|
testAuth (false, yield);
|
||||||
testAuth (true, yield);
|
testAuth (true, yield);
|
||||||
|
|||||||
Reference in New Issue
Block a user