Remove p2p alert handling
This commit is contained in:
parent
73b7eb501e
commit
bbb9d1d123
8 changed files with 52 additions and 673 deletions
|
@ -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 \
|
||||||
|
|
|
@ -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
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
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
|
|
62
src/main.cpp
62
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"
|
||||||
|
@ -4213,14 +4212,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 +4229,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 +4564,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 +5271,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;
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -4,253 +4,76 @@
|
||||||
|
|
||||||
// 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; }
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(PartitionAlert)
|
BOOST_AUTO_TEST_CASE(PartitionAlert)
|
||||||
{
|
{
|
||||||
// Test PartitionCheck
|
// Test PartitionCheck
|
||||||
CCriticalSection csDummy;
|
CCriticalSection csDummy;
|
||||||
CBlockIndex indexDummy[100];
|
CBlockIndex indexDummy[100];
|
||||||
CChainParams& params = Params(CBaseChainParams::MAIN);
|
CChainParams& params = Params(CBaseChainParams::MAIN);
|
||||||
int64_t nPowTargetSpacing = params.GetConsensus().nPowTargetSpacing;
|
int64_t nPowTargetSpacing = params.GetConsensus().nPowTargetSpacing;
|
||||||
|
|
||||||
// Generate fake blockchain timestamps relative to
|
// Generate fake blockchain timestamps relative to
|
||||||
// an arbitrary time:
|
// an arbitrary time:
|
||||||
int64_t now = 1427379054;
|
int64_t now = 1427379054;
|
||||||
SetMockTime(now);
|
SetMockTime(now);
|
||||||
for (int i = 0; i < 100; i++)
|
for (int i = 0; i < 100; i++)
|
||||||
{
|
{
|
||||||
indexDummy[i].phashBlock = NULL;
|
indexDummy[i].phashBlock = NULL;
|
||||||
if (i == 0) indexDummy[i].pprev = NULL;
|
if (i == 0) indexDummy[i].pprev = NULL;
|
||||||
else indexDummy[i].pprev = &indexDummy[i-1];
|
else indexDummy[i].pprev = &indexDummy[i-1];
|
||||||
indexDummy[i].nHeight = i;
|
indexDummy[i].nHeight = i;
|
||||||
indexDummy[i].nTime = now - (100-i)*nPowTargetSpacing;
|
indexDummy[i].nTime = now - (100-i)*nPowTargetSpacing;
|
||||||
// Other members don't matter, the partition check code doesn't
|
// Other members don't matter, the partition check code doesn't
|
||||||
// use them
|
// use them
|
||||||
}
|
}
|
||||||
|
|
||||||
strMiscWarning = "";
|
strMiscWarning = "";
|
||||||
|
|
||||||
// Test 1: chain with blocks every nPowTargetSpacing seconds,
|
// Test 1: chain with blocks every nPowTargetSpacing seconds,
|
||||||
// as normal, no worries:
|
// as normal, no worries:
|
||||||
PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
|
PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
|
||||||
BOOST_CHECK_MESSAGE(strMiscWarning.empty(), strMiscWarning);
|
BOOST_CHECK_MESSAGE(strMiscWarning.empty(), strMiscWarning);
|
||||||
|
|
||||||
// Test 2: go 3.5 hours without a block, expect a warning:
|
// Test 2: go 3.5 hours without a block, expect a warning:
|
||||||
now += 3*60*60+30*60;
|
now += 3*60*60+30*60;
|
||||||
SetMockTime(now);
|
SetMockTime(now);
|
||||||
PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
|
PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
|
||||||
BOOST_CHECK(!strMiscWarning.empty());
|
BOOST_CHECK(!strMiscWarning.empty());
|
||||||
BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
|
BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
|
||||||
strMiscWarning = "";
|
strMiscWarning = "";
|
||||||
|
|
||||||
// Test 3: test the "partition alerts only go off once per day"
|
// Test 3: test the "partition alerts only go off once per day"
|
||||||
// code:
|
// code:
|
||||||
now += 60*10;
|
now += 60*10;
|
||||||
SetMockTime(now);
|
SetMockTime(now);
|
||||||
PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
|
PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
|
||||||
BOOST_CHECK(strMiscWarning.empty());
|
BOOST_CHECK(strMiscWarning.empty());
|
||||||
|
|
||||||
// Test 4: get 2.5 times as many blocks as expected:
|
// Test 4: get 2.5 times as many blocks as expected:
|
||||||
now += 60*60*24; // Pretend it is a day later
|
now += 60*60*24; // Pretend it is a day later
|
||||||
SetMockTime(now);
|
SetMockTime(now);
|
||||||
int64_t quickSpacing = nPowTargetSpacing*2/5;
|
int64_t quickSpacing = nPowTargetSpacing*2/5;
|
||||||
for (int i = 0; i < 100; i++) // Tweak chain timestamps:
|
for (int i = 0; i < 100; i++) // Tweak chain timestamps:
|
||||||
indexDummy[i].nTime = now - (100-i)*quickSpacing;
|
indexDummy[i].nTime = now - (100-i)*quickSpacing;
|
||||||
PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
|
PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
|
||||||
BOOST_CHECK(!strMiscWarning.empty());
|
BOOST_CHECK(!strMiscWarning.empty());
|
||||||
BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
|
BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
|
||||||
strMiscWarning = "";
|
strMiscWarning = "";
|
||||||
|
|
||||||
SetMockTime(0);
|
SetMockTime(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
Binary file not shown.
Loading…
Reference in a new issue