diff --git a/src/alert.cpp b/src/alert.cpp index aa7ac748..6e41b11a 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -41,7 +41,7 @@ void CUnsignedAlert::SetNull() strComment.clear(); strStatusBar.clear(); - strReserved.clear(); + strRPCError.clear(); } std::string CUnsignedAlert::ToString() const @@ -66,6 +66,7 @@ std::string CUnsignedAlert::ToString() const " nPriority = %d\n" " strComment = \"%s\"\n" " strStatusBar = \"%s\"\n" + " strRPCError = \"%s\"\n" ")\n", nVersion, nRelayUntil, @@ -78,7 +79,8 @@ std::string CUnsignedAlert::ToString() const strSetSubVer, nPriority, strComment, - strStatusBar); + strStatusBar, + strRPCError); } void CAlert::SetNull() diff --git a/src/alert.h b/src/alert.h index 746967c4..b5e1cd11 100644 --- a/src/alert.h +++ b/src/alert.h @@ -44,7 +44,7 @@ public: // Actions std::string strComment; std::string strStatusBar; - std::string strReserved; + std::string strRPCError; ADD_SERIALIZE_METHODS; @@ -64,7 +64,7 @@ public: READWRITE(LIMITED_STRING(strComment, 65536)); READWRITE(LIMITED_STRING(strStatusBar, 256)); - READWRITE(LIMITED_STRING(strReserved, 256)); + READWRITE(LIMITED_STRING(strRPCError, 256)); } void SetNull(); diff --git a/src/main.cpp b/src/main.cpp index 55a4c36a..93e7e16c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4071,6 +4071,9 @@ string GetWarnings(string strFor) { nPriority = alert.nPriority; strStatusBar = alert.strStatusBar; + if (alert.nPriority >= ALERT_PRIORITY_SAFE_MODE) { + strRPC = alert.strRPCError; + } } } } diff --git a/src/main.h b/src/main.h index 0cb71407..2953162f 100644 --- a/src/main.h +++ b/src/main.h @@ -54,6 +54,8 @@ static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0; static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000; /** Default for accepting alerts from the P2P network. */ static const bool DEFAULT_ALERTS = true; +/** Minimum alert priority for enabling safe mode. */ +static const int ALERT_PRIORITY_SAFE_MODE = 4000; /** The maximum size for transactions we're willing to relay/mine */ static const unsigned int MAX_STANDARD_TX_SIZE = 100000; /** Maximum number of signature check operations in an IsStandard() P2SH script */ diff --git a/src/sendalert.cpp b/src/sendalert.cpp index d68b38f9..07607ef1 100644 --- a/src/sendalert.cpp +++ b/src/sendalert.cpp @@ -85,9 +85,11 @@ void ThreadSendAlert() // 1000 for Misc warnings like out of disk space and clock is wrong // 2000 for longer invalid proof-of-work chain // Higher numbers mean higher priority + // 4000 or higher will put the RPC into safe mode alert.nPriority = 5000; alert.strComment = ""; alert.strStatusBar = "URGENT: Upgrade required: see https://z.cash"; + alert.strRPCError = "URGENT: Upgrade required: see https://z.cash"; // Set specific client version/versions here. If setSubVer is empty, no filtering on subver is done: // alert.setSubVer.insert(std::string("/Satoshi:0.7.2/")); diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index ccfb6132..c9afafa9 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -13,6 +13,8 @@ #include "data/alertTests.raw.h" #include "main.h" +#include "rpcprotocol.h" +#include "rpcserver.h" #include "serialize.h" #include "streams.h" #include "util.h" @@ -25,6 +27,7 @@ #include #include #include +#include "json/json_spirit_reader_template.h" #include "key.h" #include "alertkeys.h" @@ -182,9 +185,22 @@ void GenerateAlertTests() ++alert.nID; SignAndSerialize(alert, sBuffer); + ++alert.nID; + alert.nPriority = 5000; + alert.strStatusBar = "Alert 3, disables RPC"; + alert.strRPCError = "RPC disabled"; + SignAndSerialize(alert, sBuffer); + + ++alert.nID; + alert.nPriority = 5000; + alert.strStatusBar = "Alert 4, re-enables RPC"; + alert.strRPCError = ""; + SignAndSerialize(alert, sBuffer); + ++alert.nID; alert.nMinVer = 11; alert.nMaxVer = 22; + alert.nPriority = 100; SignAndSerialize(alert, sBuffer); ++alert.nID; @@ -320,7 +336,7 @@ BOOST_AUTO_TEST_CASE(AlertNotify) alert.ProcessAlert(alertKey, false); std::vector r = read_lines(temp); - BOOST_CHECK_EQUAL(r.size(), 4u); + BOOST_CHECK_EQUAL(r.size(), 6u); // Windows built-in echo semantics are different than posixy shells. Quotes and // whitespace are printed literally. @@ -329,16 +345,43 @@ BOOST_AUTO_TEST_CASE(AlertNotify) BOOST_CHECK_EQUAL(r[0], "Alert 1"); BOOST_CHECK_EQUAL(r[1], "Alert 2, cancels 1"); BOOST_CHECK_EQUAL(r[2], "Alert 2, cancels 1"); - BOOST_CHECK_EQUAL(r[3], "Evil Alert; /bin/ls; echo "); // single-quotes should be removed + BOOST_CHECK_EQUAL(r[3], "Alert 3, disables RPC"); + BOOST_CHECK_EQUAL(r[4], "Alert 4, reenables RPC"); // dashes should be removed + BOOST_CHECK_EQUAL(r[5], "Evil Alert; /bin/ls; echo "); // single-quotes should be removed #else BOOST_CHECK_EQUAL(r[0], "'Alert 1' "); BOOST_CHECK_EQUAL(r[1], "'Alert 2, cancels 1' "); BOOST_CHECK_EQUAL(r[2], "'Alert 2, cancels 1' "); - BOOST_CHECK_EQUAL(r[3], "'Evil Alert; /bin/ls; echo ' "); + BOOST_CHECK_EQUAL(r[3], "'Alert 3, disables RPC' "); + BOOST_CHECK_EQUAL(r[4], "'Alert 4, reenables RPC' "); // dashes should be removed + BOOST_CHECK_EQUAL(r[5], "'Evil Alert; /bin/ls; echo ' "); #endif boost::filesystem::remove(temp); SetMockTime(0); + mapAlerts.clear(); +} + +BOOST_AUTO_TEST_CASE(AlertDisablesRPC) +{ + SetMockTime(11); + const std::vector& alertKey = Params(CBaseChainParams::MAIN).AlertKey(); + + // Command should work before alerts + BOOST_CHECK_EQUAL(GetWarnings("rpc"), ""); + + // First alert should disable RPC + alerts[5].ProcessAlert(alertKey, false); + BOOST_CHECK_EQUAL(alerts[5].strRPCError, "RPC disabled"); + BOOST_CHECK_EQUAL(GetWarnings("rpc"), "RPC disabled"); + + // Second alert should re-enable RPC + alerts[6].ProcessAlert(alertKey, false); + BOOST_CHECK_EQUAL(alerts[6].strRPCError, ""); + BOOST_CHECK_EQUAL(GetWarnings("rpc"), ""); + + SetMockTime(0); + mapAlerts.clear(); } static bool falseFunc() { return false; } diff --git a/src/test/data/alertTests.raw b/src/test/data/alertTests.raw index 019f2b0d..23fbfa98 100644 Binary files a/src/test/data/alertTests.raw and b/src/test/data/alertTests.raw differ