Browse Source

Merge #7692: Remove p2p alert system

cfd519e Add release note documentation (BtcDrak)
6601ce5 protocol.h/cpp: Removes NetMsgType::ALERT (Thomas Kerin)
ad72104 Formatting (BtcDrak)
1b77471 Remove alert keys (BtcDrak)
01fdfef Remove `-alerts` option (BtcDrak)
9206634 Update alert notification and GUI (BtcDrak)
bbb9d1d Remove p2p alert handling (BtcDrak)
0.13
Wladimir J. van der Laan 9 years ago
parent
commit
29b2be6ad7
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
  1. 2
      doc/release-notes.md
  2. 2
      src/Makefile.am
  3. 2
      src/Makefile.test.include
  4. 266
      src/alert.cpp
  5. 113
      src/alert.h
  6. 2
      src/chainparams.cpp
  7. 3
      src/chainparams.h
  8. 3
      src/init.cpp
  9. 91
      src/main.cpp
  10. 3
      src/main.h
  11. 2
      src/protocol.cpp
  12. 7
      src/protocol.h
  13. 27
      src/qt/clientmodel.cpp
  14. 2
      src/qt/clientmodel.h
  15. 179
      src/test/alert_tests.cpp
  16. BIN
      src/test/data/alertTests.raw
  17. 5
      src/ui_interface.h

2
doc/release-notes.md

@ -51,6 +51,8 @@ The following outputs are affected by this change:
### P2P protocol and network code ### P2P protocol and network code
The p2p alert system has been removed in #7692 and the 'alert' message is no longer supported.
### Validation ### Validation
### Build system ### Build system

2
src/Makefile.am

@ -87,7 +87,6 @@ endif
# bitcoin core # # bitcoin core #
BITCOIN_CORE_H = \ BITCOIN_CORE_H = \
addrman.h \ addrman.h \
alert.h \
base58.h \ base58.h \
bloom.h \ bloom.h \
chain.h \ chain.h \
@ -176,7 +175,6 @@ libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CP
libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_server_a_SOURCES = \ libbitcoin_server_a_SOURCES = \
addrman.cpp \ addrman.cpp \
alert.cpp \
bloom.cpp \ bloom.cpp \
chain.cpp \ chain.cpp \
checkpoints.cpp \ checkpoints.cpp \

2
src/Makefile.test.include

@ -29,7 +29,7 @@ JSON_TEST_FILES = \
test/data/tx_valid.json \ test/data/tx_valid.json \
test/data/sighash.json test/data/sighash.json
RAW_TEST_FILES = test/data/alertTests.raw RAW_TEST_FILES =
GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h) GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)

266
src/alert.cpp

@ -1,266 +0,0 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "alert.h"
#include "clientversion.h"
#include "net.h"
#include "pubkey.h"
#include "timedata.h"
#include "ui_interface.h"
#include "util.h"
#include "utilstrencodings.h"
#include <stdint.h>
#include <algorithm>
#include <map>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/foreach.hpp>
#include <boost/thread.hpp>
using namespace std;
map<uint256, CAlert> mapAlerts;
CCriticalSection cs_mapAlerts;
void CUnsignedAlert::SetNull()
{
nVersion = 1;
nRelayUntil = 0;
nExpiration = 0;
nID = 0;
nCancel = 0;
setCancel.clear();
nMinVer = 0;
nMaxVer = 0;
setSubVer.clear();
nPriority = 0;
strComment.clear();
strStatusBar.clear();
strReserved.clear();
}
std::string CUnsignedAlert::ToString() const
{
std::string strSetCancel;
BOOST_FOREACH(int n, setCancel)
strSetCancel += strprintf("%d ", n);
std::string strSetSubVer;
BOOST_FOREACH(const std::string& str, setSubVer)
strSetSubVer += "\"" + str + "\" ";
return strprintf(
"CAlert(\n"
" nVersion = %d\n"
" nRelayUntil = %d\n"
" nExpiration = %d\n"
" nID = %d\n"
" nCancel = %d\n"
" setCancel = %s\n"
" nMinVer = %d\n"
" nMaxVer = %d\n"
" setSubVer = %s\n"
" nPriority = %d\n"
" strComment = \"%s\"\n"
" strStatusBar = \"%s\"\n"
")\n",
nVersion,
nRelayUntil,
nExpiration,
nID,
nCancel,
strSetCancel,
nMinVer,
nMaxVer,
strSetSubVer,
nPriority,
strComment,
strStatusBar);
}
void CAlert::SetNull()
{
CUnsignedAlert::SetNull();
vchMsg.clear();
vchSig.clear();
}
bool CAlert::IsNull() const
{
return (nExpiration == 0);
}
uint256 CAlert::GetHash() const
{
return Hash(this->vchMsg.begin(), this->vchMsg.end());
}
bool CAlert::IsInEffect() const
{
return (GetAdjustedTime() < nExpiration);
}
bool CAlert::Cancels(const CAlert& alert) const
{
if (!IsInEffect())
return false; // this was a no-op before 31403
return (alert.nID <= nCancel || setCancel.count(alert.nID));
}
bool CAlert::AppliesTo(int nVersion, const std::string& strSubVerIn) const
{
// TODO: rework for client-version-embedded-in-strSubVer ?
return (IsInEffect() &&
nMinVer <= nVersion && nVersion <= nMaxVer &&
(setSubVer.empty() || setSubVer.count(strSubVerIn)));
}
bool CAlert::AppliesToMe() const
{
return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));
}
bool CAlert::RelayTo(CNode* pnode) const
{
if (!IsInEffect())
return false;
// don't relay to nodes which haven't sent their version message
if (pnode->nVersion == 0)
return false;
// returns true if wasn't already contained in the set
if (pnode->setKnown.insert(GetHash()).second)
{
if (AppliesTo(pnode->nVersion, pnode->strSubVer) ||
AppliesToMe() ||
GetAdjustedTime() < nRelayUntil)
{
pnode->PushMessage(NetMsgType::ALERT, *this);
return true;
}
}
return false;
}
bool CAlert::CheckSignature(const std::vector<unsigned char>& alertKey) const
{
CPubKey key(alertKey);
if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
return error("CAlert::CheckSignature(): verify signature failed");
// Now unserialize the data
CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
sMsg >> *(CUnsignedAlert*)this;
return true;
}
CAlert CAlert::getAlertByHash(const uint256 &hash)
{
CAlert retval;
{
LOCK(cs_mapAlerts);
map<uint256, CAlert>::iterator mi = mapAlerts.find(hash);
if(mi != mapAlerts.end())
retval = mi->second;
}
return retval;
}
bool CAlert::ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread)
{
if (!CheckSignature(alertKey))
return false;
if (!IsInEffect())
return false;
// alert.nID=max is reserved for if the alert key is
// compromised. It must have a pre-defined message,
// must never expire, must apply to all versions,
// and must cancel all previous
// alerts or it will be ignored (so an attacker can't
// send an "everything is OK, don't panic" version that
// cannot be overridden):
int maxInt = std::numeric_limits<int>::max();
if (nID == maxInt)
{
if (!(
nExpiration == maxInt &&
nCancel == (maxInt-1) &&
nMinVer == 0 &&
nMaxVer == maxInt &&
setSubVer.empty() &&
nPriority == maxInt &&
strStatusBar == "URGENT: Alert key compromised, upgrade required"
))
return false;
}
{
LOCK(cs_mapAlerts);
// Cancel previous alerts
for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
{
const CAlert& alert = (*mi).second;
if (Cancels(alert))
{
LogPrint("alert", "cancelling alert %d\n", alert.nID);
uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
mapAlerts.erase(mi++);
}
else if (!alert.IsInEffect())
{
LogPrint("alert", "expiring alert %d\n", alert.nID);
uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
mapAlerts.erase(mi++);
}
else
mi++;
}
// Check if this alert has been cancelled
BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
{
const CAlert& alert = item.second;
if (alert.Cancels(*this))
{
LogPrint("alert", "alert already cancelled by %d\n", alert.nID);
return false;
}
}
// Add to mapAlerts
mapAlerts.insert(make_pair(GetHash(), *this));
// Notify UI and -alertnotify if it applies to me
if(AppliesToMe())
{
uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
Notify(strStatusBar, fThread);
}
}
LogPrint("alert", "accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
return true;
}
void
CAlert::Notify(const std::string& strMessage, bool fThread)
{
std::string strCmd = GetArg("-alertnotify", "");
if (strCmd.empty()) return;
// Alert text should be plain ascii coming from a trusted source, but to
// be safe we first strip anything not in safeChars, then add single quotes around
// the whole string before passing it to the shell:
std::string singleQuote("'");
std::string safeStatus = SanitizeString(strMessage);
safeStatus = singleQuote+safeStatus+singleQuote;
boost::replace_all(strCmd, "%s", safeStatus);
if (fThread)
boost::thread t(runCommand, strCmd); // thread runs free
else
runCommand(strCmd);
}

113
src/alert.h

@ -1,113 +0,0 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_ALERT_H
#define BITCOIN_ALERT_H
#include "serialize.h"
#include "sync.h"
#include <map>
#include <set>
#include <stdint.h>
#include <string>
class CAlert;
class CNode;
class uint256;
extern std::map<uint256, CAlert> mapAlerts;
extern CCriticalSection cs_mapAlerts;
/** Alerts are for notifying old versions if they become too obsolete and
* need to upgrade. The message is displayed in the status bar.
* Alert messages are broadcast as a vector of signed data. Unserializing may
* not read the entire buffer if the alert is for a newer version, but older
* versions can still relay the original data.
*/
class CUnsignedAlert
{
public:
int nVersion;
int64_t nRelayUntil; // when newer nodes stop relaying to newer nodes
int64_t nExpiration;
int nID;
int nCancel;
std::set<int> setCancel;
int nMinVer; // lowest version inclusive
int nMaxVer; // highest version inclusive
std::set<std::string> setSubVer; // empty matches all
int nPriority;
// Actions
std::string strComment;
std::string strStatusBar;
std::string strReserved;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(this->nVersion);
nVersion = this->nVersion;
READWRITE(nRelayUntil);
READWRITE(nExpiration);
READWRITE(nID);
READWRITE(nCancel);
READWRITE(setCancel);
READWRITE(nMinVer);
READWRITE(nMaxVer);
READWRITE(setSubVer);
READWRITE(nPriority);
READWRITE(LIMITED_STRING(strComment, 65536));
READWRITE(LIMITED_STRING(strStatusBar, 256));
READWRITE(LIMITED_STRING(strReserved, 256));
}
void SetNull();
std::string ToString() const;
};
/** An alert is a combination of a serialized CUnsignedAlert and a signature. */
class CAlert : public CUnsignedAlert
{
public:
std::vector<unsigned char> vchMsg;
std::vector<unsigned char> vchSig;
CAlert()
{
SetNull();
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(vchMsg);
READWRITE(vchSig);
}
void SetNull();
bool IsNull() const;
uint256 GetHash() const;
bool IsInEffect() const;
bool Cancels(const CAlert& alert) const;
bool AppliesTo(int nVersion, const std::string& strSubVerIn) const;
bool AppliesToMe() const;
bool RelayTo(CNode* pnode) const;
bool CheckSignature(const std::vector<unsigned char>& alertKey) const;
bool ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread = true); // fThread means run -alertnotify in a free-running thread
static void Notify(const std::string& strMessage, bool fThread);
/*
* Get copy of (active) alert object by hash. Returns a null alert if it is not found.
*/
static CAlert getAlertByHash(const uint256 &hash);
};
#endif // BITCOIN_ALERT_H

2
src/chainparams.cpp

@ -95,7 +95,6 @@ public:
pchMessageStart[1] = 0xbe; pchMessageStart[1] = 0xbe;
pchMessageStart[2] = 0xb4; pchMessageStart[2] = 0xb4;
pchMessageStart[3] = 0xd9; pchMessageStart[3] = 0xd9;
vAlertPubKey = ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284");
nDefaultPort = 8333; nDefaultPort = 8333;
nPruneAfterHeight = 100000; nPruneAfterHeight = 100000;
@ -176,7 +175,6 @@ public:
pchMessageStart[1] = 0x11; pchMessageStart[1] = 0x11;
pchMessageStart[2] = 0x09; pchMessageStart[2] = 0x09;
pchMessageStart[3] = 0x07; pchMessageStart[3] = 0x07;
vAlertPubKey = ParseHex("04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a");
nDefaultPort = 18333; nDefaultPort = 18333;
nPruneAfterHeight = 1000; nPruneAfterHeight = 1000;

3
src/chainparams.h

@ -54,7 +54,6 @@ public:
const Consensus::Params& GetConsensus() const { return consensus; } const Consensus::Params& GetConsensus() const { return consensus; }
const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; } const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; }
const std::vector<unsigned char>& AlertKey() const { return vAlertPubKey; }
int GetDefaultPort() const { return nDefaultPort; } int GetDefaultPort() const { return nDefaultPort; }
const CBlock& GenesisBlock() const { return genesis; } const CBlock& GenesisBlock() const { return genesis; }
@ -80,8 +79,6 @@ protected:
Consensus::Params consensus; Consensus::Params consensus;
CMessageHeader::MessageStartChars pchMessageStart; CMessageHeader::MessageStartChars pchMessageStart;
//! Raw pub key bytes for the broadcast alert signing key.
std::vector<unsigned char> vAlertPubKey;
int nDefaultPort; int nDefaultPort;
uint64_t nPruneAfterHeight; uint64_t nPruneAfterHeight;
std::vector<CDNSSeedData> vSeeds; std::vector<CDNSSeedData> vSeeds;

3
src/init.cpp

@ -315,7 +315,6 @@ std::string HelpMessage(HelpMessageMode mode)
string strUsage = HelpMessageGroup(_("Options:")); string strUsage = HelpMessageGroup(_("Options:"));
strUsage += HelpMessageOpt("-?", _("Print this help message and exit")); strUsage += HelpMessageOpt("-?", _("Print this help message and exit"));
strUsage += HelpMessageOpt("-version", _("Print version and exit")); strUsage += HelpMessageOpt("-version", _("Print version and exit"));
strUsage += HelpMessageOpt("-alerts", strprintf(_("Receive and display P2P network alerts (default: %u)"), DEFAULT_ALERTS));
strUsage += HelpMessageOpt("-alertnotify=<cmd>", _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)")); strUsage += HelpMessageOpt("-alertnotify=<cmd>", _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)"));
strUsage += HelpMessageOpt("-blocknotify=<cmd>", _("Execute command when the best block changes (%s in cmd is replaced by block hash)")); strUsage += HelpMessageOpt("-blocknotify=<cmd>", _("Execute command when the best block changes (%s in cmd is replaced by block hash)"));
if (showDebug) if (showDebug)
@ -1000,8 +999,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
fAcceptDatacarrier = GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER); fAcceptDatacarrier = GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER);
nMaxDatacarrierBytes = GetArg("-datacarriersize", nMaxDatacarrierBytes); nMaxDatacarrierBytes = GetArg("-datacarriersize", nMaxDatacarrierBytes);
fAlerts = GetBoolArg("-alerts", DEFAULT_ALERTS);
// Option to startup with mocktime set (used for regression testing): // Option to startup with mocktime set (used for regression testing):
SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op

91
src/main.cpp

@ -6,7 +6,6 @@
#include "main.h" #include "main.h"
#include "addrman.h" #include "addrman.h"
#include "alert.h"
#include "arith_uint256.h" #include "arith_uint256.h"
#include "chainparams.h" #include "chainparams.h"
#include "checkpoints.h" #include "checkpoints.h"
@ -75,7 +74,6 @@ bool fCheckBlockIndex = false;
bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED; bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
size_t nCoinCacheUsage = 5000 * 300; size_t nCoinCacheUsage = 5000 * 300;
uint64_t nPruneTarget = 0; uint64_t nPruneTarget = 0;
bool fAlerts = DEFAULT_ALERTS;
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT; bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT;
@ -1566,6 +1564,26 @@ bool fLargeWorkForkFound = false;
bool fLargeWorkInvalidChainFound = false; bool fLargeWorkInvalidChainFound = false;
CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL; CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL;
static void AlertNotify(const std::string& strMessage, bool fThread)
{
uiInterface.NotifyAlertChanged();
std::string strCmd = GetArg("-alertnotify", "");
if (strCmd.empty()) return;
// Alert text should be plain ascii coming from a trusted source, but to
// be safe we first strip anything not in safeChars, then add single quotes around
// the whole string before passing it to the shell:
std::string singleQuote("'");
std::string safeStatus = SanitizeString(strMessage);
safeStatus = singleQuote+safeStatus+singleQuote;
boost::replace_all(strCmd, "%s", safeStatus);
if (fThread)
boost::thread t(runCommand, strCmd); // thread runs free
else
runCommand(strCmd);
}
void CheckForkWarningConditions() void CheckForkWarningConditions()
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
@ -1585,7 +1603,7 @@ void CheckForkWarningConditions()
{ {
std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") + std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") +
pindexBestForkBase->phashBlock->ToString() + std::string("'"); pindexBestForkBase->phashBlock->ToString() + std::string("'");
CAlert::Notify(warning, true); AlertNotify(warning, true);
} }
if (pindexBestForkTip && pindexBestForkBase) if (pindexBestForkTip && pindexBestForkBase)
{ {
@ -2116,7 +2134,7 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const
if (!strWarning.empty()) if (!strWarning.empty())
{ {
strMiscWarning = strWarning; strMiscWarning = strWarning;
CAlert::Notify(strWarning, true); AlertNotify(strWarning, true);
lastAlertTime = now; lastAlertTime = now;
} }
} }
@ -2546,7 +2564,7 @@ void static UpdateTip(CBlockIndex *pindexNew) {
if (state == THRESHOLD_ACTIVE) { if (state == THRESHOLD_ACTIVE) {
strMiscWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit); strMiscWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit);
if (!fWarned) { if (!fWarned) {
CAlert::Notify(strMiscWarning, true); AlertNotify(strMiscWarning, true);
fWarned = true; fWarned = true;
} }
} else { } else {
@ -2568,7 +2586,7 @@ void static UpdateTip(CBlockIndex *pindexNew) {
// strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user: // strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user:
strMiscWarning = _("Warning: Unknown block versions being mined! It's possible unknown rules are in effect"); strMiscWarning = _("Warning: Unknown block versions being mined! It's possible unknown rules are in effect");
if (!fWarned) { if (!fWarned) {
CAlert::Notify(strMiscWarning, true); AlertNotify(strMiscWarning, true);
fWarned = true; fWarned = true;
} }
} }
@ -4213,14 +4231,8 @@ void static CheckBlockIndex(const Consensus::Params& consensusParams)
assert(nNodes == forward.size()); assert(nNodes == forward.size());
} }
//////////////////////////////////////////////////////////////////////////////
//
// CAlert
//
std::string GetWarnings(const std::string& strFor) std::string GetWarnings(const std::string& strFor)
{ {
int nPriority = 0;
string strStatusBar; string strStatusBar;
string strRPC; string strRPC;
string strGUI; string strGUI;
@ -4236,37 +4248,20 @@ std::string GetWarnings(const std::string& strFor)
// Misc warnings like out of disk space and clock is wrong // Misc warnings like out of disk space and clock is wrong
if (strMiscWarning != "") if (strMiscWarning != "")
{ {
nPriority = 1000;
strStatusBar = strGUI = strMiscWarning; strStatusBar = strGUI = strMiscWarning;
} }
if (fLargeWorkForkFound) if (fLargeWorkForkFound)
{ {
nPriority = 2000;
strStatusBar = strRPC = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."; strStatusBar = strRPC = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.";
strGUI = _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."); strGUI = _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.");
} }
else if (fLargeWorkInvalidChainFound) else if (fLargeWorkInvalidChainFound)
{ {
nPriority = 2000;
strStatusBar = strRPC = "Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."; strStatusBar = strRPC = "Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.";
strGUI = _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."); strGUI = _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.");
} }
// Alerts
{
LOCK(cs_mapAlerts);
BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
{
const CAlert& alert = item.second;
if (alert.AppliesToMe() && alert.nPriority > nPriority)
{
nPriority = alert.nPriority;
strStatusBar = strGUI = alert.strStatusBar;
}
}
}
if (strFor == "gui") if (strFor == "gui")
return strGUI; return strGUI;
else if (strFor == "statusbar") else if (strFor == "statusbar")
@ -4588,13 +4583,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
} }
} }
// Relay alerts
{
LOCK(cs_mapAlerts);
BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
item.second.RelayTo(pfrom);
}
pfrom->fSuccessfullyConnected = true; pfrom->fSuccessfullyConnected = true;
string remoteAddr; string remoteAddr;
@ -5302,37 +5290,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
} }
else if (fAlerts && strCommand == NetMsgType::ALERT)
{
CAlert alert;
vRecv >> alert;
uint256 alertHash = alert.GetHash();
if (pfrom->setKnown.count(alertHash) == 0)
{
if (alert.ProcessAlert(chainparams.AlertKey()))
{
// Relay
pfrom->setKnown.insert(alertHash);
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
alert.RelayTo(pnode);
}
}
else {
// Small DoS penalty so peers that send us lots of
// duplicate/expired/invalid-signature/whatever alerts
// eventually get banned.
// This isn't a Misbehaving(100) (immediate ban) because the
// peer might be an older or different implementation with
// a different signature key, etc.
Misbehaving(pfrom->GetId(), 10);
}
}
}
else if (strCommand == NetMsgType::FILTERLOAD) else if (strCommand == NetMsgType::FILTERLOAD)
{ {
CBloomFilter filter; CBloomFilter filter;

3
src/main.h

@ -42,8 +42,6 @@ class CValidationState;
struct CNodeStateStats; struct CNodeStateStats;
struct LockPoints; struct LockPoints;
/** Default for accepting alerts from the P2P network. */
static const bool DEFAULT_ALERTS = true;
/** Default for DEFAULT_WHITELISTRELAY. */ /** Default for DEFAULT_WHITELISTRELAY. */
static const bool DEFAULT_WHITELISTRELAY = true; static const bool DEFAULT_WHITELISTRELAY = true;
/** Default for DEFAULT_WHITELISTFORCERELAY. */ /** Default for DEFAULT_WHITELISTFORCERELAY. */
@ -154,7 +152,6 @@ extern size_t nCoinCacheUsage;
extern CFeeRate minRelayTxFee; extern CFeeRate minRelayTxFee;
/** Absolute maximum transaction fee (in satoshis) used by wallet and mempool (rejects high fee in sendrawtransaction) */ /** Absolute maximum transaction fee (in satoshis) used by wallet and mempool (rejects high fee in sendrawtransaction) */
extern CAmount maxTxFee; extern CAmount maxTxFee;
extern bool fAlerts;
/** If the tip is older than this (in seconds), the node is considered to be in initial block download. */ /** If the tip is older than this (in seconds), the node is considered to be in initial block download. */
extern int64_t nMaxTipAge; extern int64_t nMaxTipAge;
extern bool fEnableReplacement; extern bool fEnableReplacement;

2
src/protocol.cpp

@ -28,7 +28,6 @@ const char *GETADDR="getaddr";
const char *MEMPOOL="mempool"; const char *MEMPOOL="mempool";
const char *PING="ping"; const char *PING="ping";
const char *PONG="pong"; const char *PONG="pong";
const char *ALERT="alert";
const char *NOTFOUND="notfound"; const char *NOTFOUND="notfound";
const char *FILTERLOAD="filterload"; const char *FILTERLOAD="filterload";
const char *FILTERADD="filteradd"; const char *FILTERADD="filteradd";
@ -64,7 +63,6 @@ const static std::string allNetMessageTypes[] = {
NetMsgType::MEMPOOL, NetMsgType::MEMPOOL,
NetMsgType::PING, NetMsgType::PING,
NetMsgType::PONG, NetMsgType::PONG,
NetMsgType::ALERT,
NetMsgType::NOTFOUND, NetMsgType::NOTFOUND,
NetMsgType::FILTERLOAD, NetMsgType::FILTERLOAD,
NetMsgType::FILTERADD, NetMsgType::FILTERADD,

7
src/protocol.h

@ -163,13 +163,6 @@ extern const char *PING;
* @see https://bitcoin.org/en/developer-reference#pong * @see https://bitcoin.org/en/developer-reference#pong
*/ */
extern const char *PONG; extern const char *PONG;
/**
* The alert message warns nodes of problems that may affect them or the rest
* of the network.
* @since protocol version 311.
* @see https://bitcoin.org/en/developer-reference#alert
*/
extern const char *ALERT;
/** /**
* The notfound message is a reply to a getdata message which requested an * The notfound message is a reply to a getdata message which requested an
* object the receiving node does not have available for relay. * object the receiving node does not have available for relay.

27
src/qt/clientmodel.cpp

@ -8,7 +8,6 @@
#include "guiconstants.h" #include "guiconstants.h"
#include "peertablemodel.h" #include "peertablemodel.h"
#include "alert.h"
#include "chainparams.h" #include "chainparams.h"
#include "checkpoints.h" #include "checkpoints.h"
#include "clientversion.h" #include "clientversion.h"
@ -122,20 +121,8 @@ void ClientModel::updateNumConnections(int numConnections)
Q_EMIT numConnectionsChanged(numConnections); Q_EMIT numConnectionsChanged(numConnections);
} }
void ClientModel::updateAlert(const QString &hash, int status) void ClientModel::updateAlert()
{ {
// Show error message notification for new alert
if(status == CT_NEW)
{
uint256 hash_256;
hash_256.SetHex(hash.toStdString());
CAlert alert = CAlert::getAlertByHash(hash_256);
if(!alert.IsNull())
{
Q_EMIT message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), CClientUIInterface::ICON_ERROR);
}
}
Q_EMIT alertsChanged(getStatusBarWarnings()); Q_EMIT alertsChanged(getStatusBarWarnings());
} }
@ -227,12 +214,10 @@ static void NotifyNumConnectionsChanged(ClientModel *clientmodel, int newNumConn
Q_ARG(int, newNumConnections)); Q_ARG(int, newNumConnections));
} }
static void NotifyAlertChanged(ClientModel *clientmodel, const uint256 &hash, ChangeType status) static void NotifyAlertChanged(ClientModel *clientmodel)
{ {
qDebug() << "NotifyAlertChanged: " + QString::fromStdString(hash.GetHex()) + " status=" + QString::number(status); qDebug() << "NotifyAlertChanged";
QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection, QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection);
Q_ARG(QString, QString::fromStdString(hash.GetHex())),
Q_ARG(int, status));
} }
static void BannedListChanged(ClientModel *clientmodel) static void BannedListChanged(ClientModel *clientmodel)
@ -266,7 +251,7 @@ void ClientModel::subscribeToCoreSignals()
// Connect signals to client // Connect signals to client
uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1)); uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1));
uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2)); uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this));
uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this)); uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this));
uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2)); uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2));
} }
@ -276,7 +261,7 @@ void ClientModel::unsubscribeFromCoreSignals()
// Disconnect signals from client // Disconnect signals from client
uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1)); uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1));
uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2)); uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this));
uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this)); uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this));
uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2)); uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2));
} }

2
src/qt/clientmodel.h

@ -103,7 +103,7 @@ Q_SIGNALS:
public Q_SLOTS: public Q_SLOTS:
void updateTimer(); void updateTimer();
void updateNumConnections(int numConnections); void updateNumConnections(int numConnections);
void updateAlert(const QString &hash, int status); void updateAlert();
void updateBanlist(); void updateBanlist();
}; };

179
src/test/alert_tests.cpp

@ -4,193 +4,16 @@
// Unit tests for alert system // Unit tests for alert system
#include "alert.h"
#include "chain.h"
#include "chainparams.h" #include "chainparams.h"
#include "clientversion.h"
#include "data/alertTests.raw.h"
#include "main.h" // For PartitionCheck #include "main.h" // For PartitionCheck
#include "serialize.h"
#include "streams.h"
#include "utilstrencodings.h"
#include "test/testutil.h" #include "test/testutil.h"
#include "test/test_bitcoin.h" #include "test/test_bitcoin.h"
#include <fstream>
#include <boost/filesystem/operations.hpp>
#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#if 0 BOOST_FIXTURE_TEST_SUITE(Alert_tests, TestingSetup)
//
// alertTests contains 7 alerts, generated with this code:
// (SignAndSave code not shown, alert signing key is secret)
//
{
CAlert alert;
alert.nRelayUntil = 60;
alert.nExpiration = 24 * 60 * 60;
alert.nID = 1;
alert.nCancel = 0; // cancels previous messages up to this ID number
alert.nMinVer = 0; // These versions are protocol versions
alert.nMaxVer = 999001;
alert.nPriority = 1;
alert.strComment = "Alert comment";
alert.strStatusBar = "Alert 1";
SignAndSave(alert, "test/alertTests");
alert.setSubVer.insert(std::string("/Satoshi:0.1.0/"));
alert.strStatusBar = "Alert 1 for Satoshi 0.1.0";
SignAndSave(alert, "test/alertTests");
alert.setSubVer.insert(std::string("/Satoshi:0.2.0/"));
alert.strStatusBar = "Alert 1 for Satoshi 0.1.0, 0.2.0";
SignAndSave(alert, "test/alertTests");
alert.setSubVer.clear();
++alert.nID;
alert.nCancel = 1;
alert.nPriority = 100;
alert.strStatusBar = "Alert 2, cancels 1";
SignAndSave(alert, "test/alertTests");
alert.nExpiration += 60;
++alert.nID;
SignAndSave(alert, "test/alertTests");
++alert.nID;
alert.nMinVer = 11;
alert.nMaxVer = 22;
SignAndSave(alert, "test/alertTests");
++alert.nID;
alert.strStatusBar = "Alert 2 for Satoshi 0.1.0";
alert.setSubVer.insert(std::string("/Satoshi:0.1.0/"));
SignAndSave(alert, "test/alertTests");
++alert.nID;
alert.nMinVer = 0;
alert.nMaxVer = 999999;
alert.strStatusBar = "Evil Alert'; /bin/ls; echo '";
alert.setSubVer.clear();
SignAndSave(alert, "test/alertTests");
}
#endif
struct ReadAlerts : public TestingSetup
{
ReadAlerts()
{
std::vector<unsigned char> vch(alert_tests::alertTests, alert_tests::alertTests + sizeof(alert_tests::alertTests));
CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
try {
while (!stream.eof())
{
CAlert alert;
stream >> alert;
alerts.push_back(alert);
}
}
catch (const std::exception&) { }
}
~ReadAlerts() { }
static std::vector<std::string> read_lines(boost::filesystem::path filepath)
{
std::vector<std::string> result;
std::ifstream f(filepath.string().c_str());
std::string line;
while (std::getline(f,line))
result.push_back(line);
return result;
}
std::vector<CAlert> alerts;
};
BOOST_FIXTURE_TEST_SUITE(Alert_tests, ReadAlerts)
BOOST_AUTO_TEST_CASE(AlertApplies)
{
SetMockTime(11);
const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
BOOST_FOREACH(const CAlert& alert, alerts)
{
BOOST_CHECK(alert.CheckSignature(alertKey));
}
BOOST_CHECK(alerts.size() >= 3);
// Matches:
BOOST_CHECK(alerts[0].AppliesTo(1, ""));
BOOST_CHECK(alerts[0].AppliesTo(999001, ""));
BOOST_CHECK(alerts[0].AppliesTo(1, "/Satoshi:11.11.11/"));
BOOST_CHECK(alerts[1].AppliesTo(1, "/Satoshi:0.1.0/"));
BOOST_CHECK(alerts[1].AppliesTo(999001, "/Satoshi:0.1.0/"));
BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.1.0/"));
BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.2.0/"));
// Don't match:
BOOST_CHECK(!alerts[0].AppliesTo(-1, ""));
BOOST_CHECK(!alerts[0].AppliesTo(999002, ""));
BOOST_CHECK(!alerts[1].AppliesTo(1, ""));
BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0"));
BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.1.0"));
BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0/"));
BOOST_CHECK(!alerts[1].AppliesTo(-1, "/Satoshi:0.1.0/"));
BOOST_CHECK(!alerts[1].AppliesTo(999002, "/Satoshi:0.1.0/"));
BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.2.0/"));
BOOST_CHECK(!alerts[2].AppliesTo(1, "/Satoshi:0.3.0/"));
SetMockTime(0);
}
BOOST_AUTO_TEST_CASE(AlertNotify)
{
SetMockTime(11);
const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
boost::filesystem::path temp = GetTempPath() /
boost::filesystem::unique_path("alertnotify-%%%%.txt");
mapArgs["-alertnotify"] = std::string("echo %s >> ") + temp.string();
BOOST_FOREACH(CAlert alert, alerts)
alert.ProcessAlert(alertKey, false);
std::vector<std::string> r = read_lines(temp);
BOOST_CHECK_EQUAL(r.size(), 4u);
// Windows built-in echo semantics are different than posixy shells. Quotes and
// whitespace are printed literally.
#ifndef WIN32
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
#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 ' ");
#endif
boost::filesystem::remove(temp);
SetMockTime(0);
}
static bool falseFunc() { return false; } static bool falseFunc() { return false; }

BIN
src/test/data/alertTests.raw

Binary file not shown.

5
src/ui_interface.h

@ -83,10 +83,9 @@ public:
boost::signals2::signal<void (int newNumConnections)> NotifyNumConnectionsChanged; boost::signals2::signal<void (int newNumConnections)> NotifyNumConnectionsChanged;
/** /**
* New, updated or cancelled alert. * Status bar alerts changed.
* @note called with lock cs_mapAlerts held.
*/ */
boost::signals2::signal<void (const uint256 &hash, ChangeType status)> NotifyAlertChanged; boost::signals2::signal<void ()> NotifyAlertChanged;
/** A wallet has been loaded. */ /** A wallet has been loaded. */
boost::signals2::signal<void (CWallet* wallet)> LoadWallet; boost::signals2::signal<void (CWallet* wallet)> LoadWallet;

Loading…
Cancel
Save