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)

manual fixes

Signed-off-by: Pasta <pasta@dashboost.org>

remove sendalert.cpp

Signed-off-by: Pasta <pasta@dashboost.org>

CAlertNotify -> AlertNotify

Signed-off-by: Pasta <pasta@dashboost.org>

remove alert.h

Signed-off-by: Pasta <pasta@dashboost.org>

remove vAlertPubKey for DevNet

Signed-off-by: Pasta <pasta@dashboost.org>

remove src/main.cpp
This commit is contained in:
Wladimir J. van der Laan 2016-03-21 12:54:28 +01:00 committed by Pasta
parent 1f6e0435b4
commit a1770b0c25
19 changed files with 88 additions and 835 deletions

View File

@ -105,7 +105,6 @@ BITCOIN_CORE_H = \
addressindex.h \
spentindex.h \
addrman.h \
alert.h \
base58.h \
batchedlogger.h \
bip39.h \
@ -262,7 +261,6 @@ libdash_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libdash_server_a_SOURCES = \
addrdb.cpp \
addrman.cpp \
alert.cpp \
batchedlogger.cpp \
bloom.cpp \
blockencodings.cpp \
@ -330,7 +328,6 @@ libdash_server_a_SOURCES = \
rpc/server.cpp \
script/sigcache.cpp \
script/ismine.cpp \
sendalert.cpp \
spork.cpp \
timedata.cpp \
torcontrol.cpp \

View File

@ -20,7 +20,7 @@ JSON_TEST_FILES = \
test/data/tx_valid.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)

View File

@ -1,286 +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 "base58.h"
#include "clientversion.h"
#include "net.h"
#include "netmessagemaker.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/thread.hpp>
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;
for (const auto& n : setCancel)
strSetCancel += strprintf("%d ", n);
std::string strSetSubVer;
for (const auto& 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, CConnman& connman) 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)
{
connman.PushMessage(pnode, CNetMsgMaker(pnode->GetSendVersion()).Make(NetMsgType::ALERT, *this));
return true;
}
}
return false;
}
bool CAlert::Sign()
{
CDataStream sMsg(SER_NETWORK, CLIENT_VERSION);
sMsg << *(CUnsignedAlert*)this;
vchMsg = std::vector<unsigned char>(sMsg.begin(), sMsg.end());
CBitcoinSecret vchSecret;
if (!vchSecret.SetString(GetArg("-alertkey", "")))
{
printf("CAlert::SignAlert() : vchSecret.SetString failed\n");
return false;
}
CKey key = vchSecret.GetKey();
if (!key.Sign(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
{
printf("CAlert::SignAlert() : key.Sign failed\n");
return false;
}
return true;
}
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);
std::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) const
{
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 (std::map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
{
const CAlert& alert = (*mi).second;
if (Cancels(alert))
{
LogPrint(BCLog::ALERT, "cancelling alert %d\n", alert.nID);
uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
mapAlerts.erase(mi++);
}
else if (!alert.IsInEffect())
{
LogPrint(BCLog::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
for (const auto& item : mapAlerts)
{
const CAlert& alert = item.second;
if (alert.Cancels(*this))
{
LogPrint(BCLog::ALERT, "alert already cancelled by %d\n", alert.nID);
return false;
}
}
// Add to mapAlerts
mapAlerts.insert(std::make_pair(GetHash(), *this));
// Notify UI and -alertnotify if it applies to me
if(AppliesToMe())
{
uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
Notify(strStatusBar, fThread);
}
}
LogPrint(BCLog::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);
}

View File

@ -1,114 +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 CConnman;
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) {
READWRITE(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) {
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, CConnman& connman) const;
bool Sign();
bool CheckSignature(const std::vector<unsigned char>& alertKey) const;
bool ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread = true) const; // fThread means run -alertnotify in a free-running thread
static void Notify(const std::string& strMessage, bool fThread = true);
/*
* 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

View File

@ -283,7 +283,6 @@ public:
pchMessageStart[1] = 0x0c;
pchMessageStart[2] = 0x6b;
pchMessageStart[3] = 0xbd;
vAlertPubKey = ParseHex("048240a8748a80a286b270ba126705ced4f2ce5a7847b3610ea3c06513150dade2a8512ed5ea86320824683fc0818f0ac019214973e677acd1244f6d0571fc5103");
nDefaultPort = 9999;
nPruneAfterHeight = 100000;
@ -461,7 +460,6 @@ public:
pchMessageStart[1] = 0xe2;
pchMessageStart[2] = 0xca;
pchMessageStart[3] = 0xff;
vAlertPubKey = ParseHex("04517d8a699cb43d3938d7b24faaff7cda448ca4ea267723ba614784de661949bf632d6304316b244646dea079735b9a6fc4af804efb4752075b9fe2245e14e412");
nDefaultPort = 19999;
nPruneAfterHeight = 1000;
@ -620,7 +618,6 @@ public:
pchMessageStart[1] = 0xca;
pchMessageStart[2] = 0xff;
pchMessageStart[3] = 0xce;
vAlertPubKey = ParseHex("04517d8a699cb43d3938d7b24faaff7cda448ca4ea267723ba614784de661949bf632d6304316b244646dea079735b9a6fc4af804efb4752075b9fe2245e14e412");
nDefaultPort = 19999;
nPruneAfterHeight = 1000;

View File

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

View File

@ -444,7 +444,6 @@ std::string HelpMessage(HelpMessageMode mode)
std::string strUsage = HelpMessageGroup(_("Options:"));
strUsage += HelpMessageOpt("-?", _("Print this help message 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("-blocknotify=<cmd>", _("Execute command when the best block changes (%s in cmd is replaced by block hash)"));
if (showDebug)
@ -1313,8 +1312,6 @@ bool AppInitParameterInteraction()
fAcceptDatacarrier = GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER);
nMaxDatacarrierBytes = GetArg("-datacarriersize", nMaxDatacarrierBytes);
fAlerts = GetBoolArg("-alerts", DEFAULT_ALERTS);
// Option to startup with mocktime set (used for regression testing):
SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op

View File

@ -5,7 +5,6 @@
#include "net_processing.h"
#include "alert.h"
#include "addrman.h"
#include "arith_uint256.h"
#include "blockencodings.h"
@ -1616,13 +1615,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
connman.MarkAddressGood(pfrom->addr);
}
// Relay alerts
{
LOCK(cs_mapAlerts);
BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
item.second.RelayTo(pfrom, connman);
}
std::string remoteAddr;
if (fLogIPs)
remoteAddr = ", peeraddr=" + pfrom->addr.ToString();
@ -2926,37 +2918,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
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);
{
connman.ForEachNode([&alert, &connman](CNode* pnode) {
alert.RelayTo(pnode, connman);
});
}
}
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)
{
CBloomFilter filter;

View File

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

View File

@ -160,13 +160,6 @@ extern const char *PING;
* @see https://bitcoin.org/en/developer-reference#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
* object the receiving node does not have available for relay.

View File

@ -10,7 +10,6 @@
#include "guiutil.h"
#include "peertablemodel.h"
#include "alert.h"
#include "chain.h"
#include "chainparams.h"
#include "checkpoints.h"
@ -202,20 +201,8 @@ void ClientModel::updateNetworkActive(bool networkActive)
Q_EMIT networkActiveChanged(networkActive);
}
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());
}
@ -323,12 +310,10 @@ static void NotifyNetworkActiveChanged(ClientModel *clientmodel, bool networkAct
Q_ARG(bool, networkActive));
}
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);
QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(hash.GetHex())),
Q_ARG(int, status));
qDebug() << "NotifyAlertChanged";
QMetaObject::invokeMethod(clientmodel, "updateAlert", Qt::QueuedConnection);
}
static void BannedListChanged(ClientModel *clientmodel)
@ -382,7 +367,7 @@ void ClientModel::subscribeToCoreSignals()
uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1));
uiInterface.NotifyNetworkActiveChanged.connect(boost::bind(NotifyNetworkActiveChanged, 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.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2, false));
uiInterface.NotifyHeaderTip.connect(boost::bind(BlockTipChanged, this, _1, _2, true));
@ -396,7 +381,7 @@ void ClientModel::unsubscribeFromCoreSignals()
uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1));
uiInterface.NotifyNetworkActiveChanged.disconnect(boost::bind(NotifyNetworkActiveChanged, 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.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2, false));
uiInterface.NotifyHeaderTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2, true));

View File

@ -69,7 +69,7 @@ public:
void setMasternodeList(const CDeterministicMNList& mnList);
CDeterministicMNList getMasternodeList() const;
void refreshMasternodeList();
quint64 getTotalBytesRecv() const;
quint64 getTotalBytesSent() const;
@ -134,7 +134,7 @@ public Q_SLOTS:
void updateTimer();
void updateNumConnections(int numConnections);
void updateNetworkActive(bool networkActive);
void updateAlert(const QString &hash, int status);
void updateAlert();
void updateBanlist();
};

View File

@ -1,112 +0,0 @@
#include "alert.h"
#include "clientversion.h"
#include "chainparams.h"
#include "init.h"
#include "net.h"
#include "utilstrencodings.h"
#include "utiltime.h"
/*
If you need to broadcast an alert, here's what to do:
1. Modify alert parameters below, see alert.* and comments in the code
for what does what.
2. run dashd with -printalert or -sendalert like this:
/path/to/dashd -printalert
One minute after starting up the alert will be broadcast. It is then
flooded through the network until the nRelayUntil time, and will be
active until nExpiration OR the alert is cancelled.
If you screw up something, send another alert with nCancel set to cancel
the bad alert.
*/
void ThreadSendAlert(CConnman& connman)
{
if (!IsArgSet("-sendalert") && !IsArgSet("-printalert"))
return;
// Wait one minute so we get well connected. If we only need to print
// but not to broadcast - do this right away.
if (IsArgSet("-sendalert"))
MilliSleep(60*1000);
//
// Alerts are relayed around the network until nRelayUntil, flood
// filling to every node.
// After the relay time is past, new nodes are told about alerts
// when they connect to peers, until either nExpiration or
// the alert is cancelled by a newer alert.
// Nodes never save alerts to disk, they are in-memory-only.
//
CAlert alert;
alert.nRelayUntil = GetAdjustedTime() + 15 * 60;
alert.nExpiration = GetAdjustedTime() + 30 * 60 * 60;
alert.nID = 1; // keep track of alert IDs somewhere
alert.nCancel = 0; // cancels previous messages up to this ID number
// These versions are protocol versions
alert.nMinVer = 70000;
alert.nMaxVer = 70103;
//
// 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
alert.nPriority = 5000;
alert.strComment = "";
alert.strStatusBar = "URGENT: Upgrade required: see https://www.dash.org";
// Set specific client version/versions here. If setSubVer is empty, no filtering on subver is done:
// alert.setSubVer.insert(std::string("/Dash Core:0.12.0.58/"));
// Sign
if(!alert.Sign())
{
LogPrintf("ThreadSendAlert() : could not sign alert\n");
return;
}
// Test
CDataStream sBuffer(SER_NETWORK, CLIENT_VERSION);
sBuffer << alert;
CAlert alert2;
sBuffer >> alert2;
if (!alert2.CheckSignature(Params().AlertKey()))
{
printf("ThreadSendAlert() : CheckSignature failed\n");
return;
}
assert(alert2.vchMsg == alert.vchMsg);
assert(alert2.vchSig == alert.vchSig);
alert.SetNull();
printf("\nThreadSendAlert:\n");
printf("hash=%s\n", alert2.GetHash().ToString().c_str());
printf("%s", alert2.ToString().c_str());
printf("vchMsg=%s\n", HexStr(alert2.vchMsg).c_str());
printf("vchSig=%s\n", HexStr(alert2.vchSig).c_str());
// Confirm
if (!IsArgSet("-sendalert"))
return;
while (connman.GetNodeCount(CConnman::CONNECTIONS_ALL) == 0 && !ShutdownRequested())
MilliSleep(500);
if (ShutdownRequested())
return;
// Send
printf("ThreadSendAlert() : Sending alert\n");
int nSent = 0;
{
connman.ForEachNode([&alert2, &connman, &nSent](CNode* pnode) {
if (alert2.RelayTo(pnode, connman))
{
printf("ThreadSendAlert() : Sent alert to %s\n", pnode->addr.ToString().c_str());
nSent++;
}
});
}
printf("ThreadSendAlert() : Alert sent to %d nodes\n", nSent);
}

View File

@ -4,232 +4,77 @@
// Unit tests for alert system
#include "alert.h"
#include "chain.h"
#include "chainparams.h"
#include "clientversion.h"
#include "data/alertTests.raw.h"
#include "fs.h"
#include "serialize.h"
#include "streams.h"
#include "utilstrencodings.h"
#include "main.h" // For PartitionCheck
#include "test/testutil.h"
#include "test/test_dash.h"
#include <fstream>
#include <boost/test/unit_test.hpp>
//
// Sign a CAlert and serialize it
//
bool SignAndSave(CAlert &alert)
BOOST_FIXTURE_TEST_SUITE(Alert_tests, TestingSetup)
static bool falseFunc() { return false; }
BOOST_AUTO_TEST_CASE(PartitionAlert)
{
// Sign
if(!alert.Sign())
// Test PartitionCheck
CCriticalSection csDummy;
CBlockIndex indexDummy[100];
CChainParams& params = Params(CBaseChainParams::MAIN);
int64_t nPowTargetSpacing = params.GetConsensus().nPowTargetSpacing;
// Generate fake blockchain timestamps relative to
// an arbitrary time:
int64_t now = 1427379054;
SetMockTime(now);
for (int i = 0; i < 100; i++)
{
printf("SignAndSave() : could not sign alert:\n%s", alert.ToString().c_str());
return false;
indexDummy[i].phashBlock = NULL;
if (i == 0) indexDummy[i].pprev = NULL;
else indexDummy[i].pprev = &indexDummy[i-1];
indexDummy[i].nHeight = i;
indexDummy[i].nTime = now - (100-i)*nPowTargetSpacing;
// Other members don't matter, the partition check code doesn't
// use them
}
std::string strFilePath = "src/test/data/alertTests.raw";
// open output file and associate it with CAutoFile
FILE *file = fopen(strFilePath.c_str(), "ab+");
CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
if (fileout.IsNull())
return error("%s: Failed to open file %s", __func__, strFilePath);
strMiscWarning = "";
try {
fileout << alert;
}
catch (std::exception &e) {
return error("%s: Serialize or I/O error - %s", __func__, e.what());
}
fileout.fclose();
return true;
}
// Test 1: chain with blocks every nPowTargetSpacing seconds,
// as normal, no worries:
PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
BOOST_CHECK_MESSAGE(strMiscWarning.empty(), strMiscWarning);
//
// alertTests contains 8 alerts, generated with this code
//
void GenerateAlertTests()
{
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";
// Test 2: go 3.5 hours without a block, expect a warning:
now += 3*60*60+30*60;
SetMockTime(now);
PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
BOOST_CHECK(!strMiscWarning.empty());
BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
strMiscWarning = "";
SignAndSave(alert);
// Test 3: test the "partition alerts only go off once per day"
// code:
now += 60*10;
SetMockTime(now);
PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
BOOST_CHECK(strMiscWarning.empty());
alert.setSubVer.insert(std::string("/Satoshi:0.1.0/"));
alert.strStatusBar = "Alert 1 for Satoshi 0.1.0";
SignAndSave(alert);
alert.setSubVer.insert(std::string("/Satoshi:0.2.0/"));
alert.strStatusBar = "Alert 1 for Satoshi 0.1.0, 0.2.0";
SignAndSave(alert);
alert.setSubVer.clear();
++alert.nID;
alert.nCancel = 1;
alert.nPriority = 100;
alert.strStatusBar = "Alert 2, cancels 1";
SignAndSave(alert);
alert.nExpiration += 60;
++alert.nID;
SignAndSave(alert);
++alert.nID;
alert.nMinVer = 11;
alert.nMaxVer = 22;
SignAndSave(alert);
++alert.nID;
alert.strStatusBar = "Alert 2 for Satoshi 0.1.0";
alert.setSubVer.insert(std::string("/Satoshi:0.1.0/"));
SignAndSave(alert);
++alert.nID;
alert.nMinVer = 0;
alert.nMaxVer = 999999;
alert.strStatusBar = "Evil Alert'; /bin/ls; echo '";
alert.setSubVer.clear();
SignAndSave(alert);
}
struct ReadAlerts : public TestingSetup
{
ReadAlerts()
{
std::vector<unsigned char> vch(raw_tests::alertTests, raw_tests::alertTests + sizeof(raw_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(fs::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)
// Steps to generate alert tests:
// - update alerts in GenerateAlertTests() (optional)
// - enable code below (#if 1)
// - replace "fffffffffffffffffffffffffffffffffffffffffffffffffff" with the actual MAINNET privkey
// - recompile and run "/path/to/test_dash -t Alert_test"
//
// NOTE: make sure to disable code and remove alert privkey when you're done!
//
#if 0
BOOST_AUTO_TEST_CASE(GenerateAlerts)
{
SoftSetArg("-alertkey", "fffffffffffffffffffffffffffffffffffffffffffffffffff");
GenerateAlertTests();
}
#endif
BOOST_AUTO_TEST_CASE(AlertApplies)
{
SetMockTime(11);
const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
for (const auto& 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/"));
// Test 4: get 2.5 times as many blocks as expected:
now += 60*60*24; // Pretend it is a day later
SetMockTime(now);
int64_t quickSpacing = nPowTargetSpacing*2/5;
for (int i = 0; i < 100; i++) // Tweak chain timestamps:
indexDummy[i].nTime = now - (100-i)*quickSpacing;
PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
BOOST_CHECK(!strMiscWarning.empty());
BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
strMiscWarning = "";
SetMockTime(0);
}
BOOST_AUTO_TEST_CASE(AlertNotify)
{
SetMockTime(11);
const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
fs::path temp = GetTempPath() /
fs::unique_path("alertnotify-%%%%.txt");
ForceSetArg("-alertnotify", std::string("echo %s >> ") + temp.string());
for (const auto& 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
fs::remove(temp);
SetMockTime(0);
}
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE_END()

Binary file not shown.

View File

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

View File

@ -6,7 +6,6 @@
#include "validation.h"
#include "alert.h"
#include "arith_uint256.h"
#include "blockencodings.h"
#include "chain.h"
@ -92,7 +91,6 @@ bool fCheckBlockIndex = false;
bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
size_t nCoinCacheUsage = 5000 * 300;
uint64_t nPruneTarget = 0;
bool fAlerts = DEFAULT_ALERTS;
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
std::atomic<bool> fDIP0001ActiveAtTip{false};
@ -1206,6 +1204,26 @@ bool IsInitialBlockDownload()
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);
}
static void CheckForkWarningConditions()
{
AssertLockHeld(cs_main);
@ -1226,7 +1244,7 @@ static void CheckForkWarningConditions()
if(pindexBestForkBase->phashBlock){
std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") +
pindexBestForkBase->phashBlock->ToString() + std::string("'");
CAlert::Notify(warning);
AlertNotify(warning);
}
}
if (pindexBestForkTip && pindexBestForkBase)
@ -2462,7 +2480,7 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
std::string strWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit);
SetMiscWarning(strWarning);
if (!fWarned) {
CAlert::Notify(strWarning);
AlertNotify(strWarning);
fWarned = true;
}
} else {
@ -2486,7 +2504,7 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
// notify GetWarnings(), called by Qt and the JSON-RPC code to warn the user:
SetMiscWarning(strWarning);
if (!fWarned) {
CAlert::Notify(strWarning);
AlertNotify(strWarning);
fWarned = true;
}
}

View File

@ -50,8 +50,6 @@ struct ChainTxData;
struct LockPoints;
/** Default for accepting alerts from the P2P network. */
static const bool DEFAULT_ALERTS = true;
/** Default for DEFAULT_WHITELISTRELAY. */
static const bool DEFAULT_WHITELISTRELAY = true;
/** Default for DEFAULT_WHITELISTFORCERELAY. */
@ -184,7 +182,6 @@ extern size_t nCoinCacheUsage;
extern CFeeRate minRelayTxFee;
/** Absolute maximum transaction fee (in duffs) used by wallet and mempool (rejects high fee in sendrawtransaction) */
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. */
extern int64_t nMaxTipAge;

View File

@ -7,7 +7,6 @@
#include "clientversion.h"
#include "util.h"
#include "warnings.h"
#include "alert.h"
#include "hash.h"
CCriticalSection cs_warnings;
@ -47,7 +46,6 @@ bool GetfLargeWorkInvalidChainFound()
std::string GetWarnings(const std::string& strFor)
{
int nPriority = 0;
std::string strStatusBar;
std::string strRPC;
std::string strGUI;
@ -66,38 +64,21 @@ std::string GetWarnings(const std::string& strFor)
// Misc warnings like out of disk space and clock is wrong
if (strMiscWarning != "")
{
nPriority = 1000;
strStatusBar = strMiscWarning;
strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + strMiscWarning;
}
if (fLargeWorkForkFound)
{
nPriority = 2000;
strStatusBar = strRPC = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.";
strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.");
}
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.";
strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + _("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);
for (const auto& item : mapAlerts)
{
const CAlert& alert = item.second;
if (alert.AppliesToMe() && alert.nPriority > nPriority)
{
nPriority = alert.nPriority;
strStatusBar = strGUI = alert.strStatusBar;
}
}
}
if (strFor == "gui")
return strGUI;
else if (strFor == "statusbar")