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_H = \
|
||||
addrman.h \
|
||||
alert.h \
|
||||
base58.h \
|
||||
bloom.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_SOURCES = \
|
||||
addrman.cpp \
|
||||
alert.cpp \
|
||||
bloom.cpp \
|
||||
chain.cpp \
|
||||
checkpoints.cpp \
|
||||
|
|
|
@ -29,7 +29,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)
|
||||
|
||||
|
|
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 "addrman.h"
|
||||
#include "alert.h"
|
||||
#include "arith_uint256.h"
|
||||
#include "chainparams.h"
|
||||
#include "checkpoints.h"
|
||||
|
@ -4213,14 +4212,8 @@ void static CheckBlockIndex(const Consensus::Params& consensusParams)
|
|||
assert(nNodes == forward.size());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CAlert
|
||||
//
|
||||
|
||||
std::string GetWarnings(const std::string& strFor)
|
||||
{
|
||||
int nPriority = 0;
|
||||
string strStatusBar;
|
||||
string strRPC;
|
||||
string strGUI;
|
||||
|
@ -4236,37 +4229,20 @@ std::string GetWarnings(const std::string& strFor)
|
|||
// Misc warnings like out of disk space and clock is wrong
|
||||
if (strMiscWarning != "")
|
||||
{
|
||||
nPriority = 1000;
|
||||
strStatusBar = strGUI = strMiscWarning;
|
||||
}
|
||||
|
||||
if (fLargeWorkForkFound)
|
||||
{
|
||||
nPriority = 2000;
|
||||
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.");
|
||||
}
|
||||
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 = _("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")
|
||||
return strGUI;
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
CBloomFilter filter;
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include "guiconstants.h"
|
||||
#include "peertablemodel.h"
|
||||
|
||||
#include "alert.h"
|
||||
#include "chainparams.h"
|
||||
#include "checkpoints.h"
|
||||
#include "clientversion.h"
|
||||
|
|
|
@ -4,253 +4,76 @@
|
|||
|
||||
// Unit tests for alert system
|
||||
|
||||
#include "alert.h"
|
||||
#include "chain.h"
|
||||
#include "chainparams.h"
|
||||
#include "clientversion.h"
|
||||
#include "data/alertTests.raw.h"
|
||||
#include "main.h" // For PartitionCheck
|
||||
#include "serialize.h"
|
||||
#include "streams.h"
|
||||
#include "utilstrencodings.h"
|
||||
|
||||
#include "test/testutil.h"
|
||||
#include "test/test_bitcoin.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#if 0
|
||||
//
|
||||
// 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";
|
||||
BOOST_FIXTURE_TEST_SUITE(Alert_tests, TestingSetup)
|
||||
|
||||
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; }
|
||||
|
||||
BOOST_AUTO_TEST_CASE(PartitionAlert)
|
||||
{
|
||||
// Test PartitionCheck
|
||||
CCriticalSection csDummy;
|
||||
CBlockIndex indexDummy[100];
|
||||
CChainParams& params = Params(CBaseChainParams::MAIN);
|
||||
int64_t nPowTargetSpacing = params.GetConsensus().nPowTargetSpacing;
|
||||
{
|
||||
// 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++)
|
||||
{
|
||||
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
|
||||
}
|
||||
// Generate fake blockchain timestamps relative to
|
||||
// an arbitrary time:
|
||||
int64_t now = 1427379054;
|
||||
SetMockTime(now);
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
strMiscWarning = "";
|
||||
strMiscWarning = "";
|
||||
|
||||
// Test 1: chain with blocks every nPowTargetSpacing seconds,
|
||||
// as normal, no worries:
|
||||
PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
|
||||
BOOST_CHECK_MESSAGE(strMiscWarning.empty(), strMiscWarning);
|
||||
// Test 1: chain with blocks every nPowTargetSpacing seconds,
|
||||
// as normal, no worries:
|
||||
PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
|
||||
BOOST_CHECK_MESSAGE(strMiscWarning.empty(), strMiscWarning);
|
||||
|
||||
// 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 = "";
|
||||
// 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 = "";
|
||||
|
||||
// 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());
|
||||
// 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());
|
||||
|
||||
// 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:
|
||||
// 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 = "";
|
||||
PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
|
||||
BOOST_CHECK(!strMiscWarning.empty());
|
||||
BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
|
||||
strMiscWarning = "";
|
||||
|
||||
SetMockTime(0);
|
||||
}
|
||||
SetMockTime(0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
Binary file not shown.
Loading…
Reference in a new issue