aboutsummaryrefslogtreecommitdiff
path: root/src/alert.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/alert.cpp')
-rw-r--r--src/alert.cpp239
1 files changed, 239 insertions, 0 deletions
diff --git a/src/alert.cpp b/src/alert.cpp
new file mode 100644
index 0000000000..48920629e2
--- /dev/null
+++ b/src/alert.cpp
@@ -0,0 +1,239 @@
+//
+// Alert system
+//
+
+#include <boost/foreach.hpp>
+#include <map>
+
+#include "alert.h"
+#include "key.h"
+#include "net.h"
+#include "sync.h"
+#include "ui_interface.h"
+
+using namespace std;
+
+map<uint256, CAlert> mapAlerts;
+CCriticalSection cs_mapAlerts;
+
+static const char* pszMainKey = "04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284";
+static const char* pszTestKey = "04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a";
+
+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(std::string str, setSubVer)
+ strSetSubVer += "\"" + str + "\" ";
+ return strprintf(
+ "CAlert(\n"
+ " nVersion = %d\n"
+ " nRelayUntil = %"PRI64d"\n"
+ " nExpiration = %"PRI64d"\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.c_str(),
+ nMinVer,
+ nMaxVer,
+ strSetSubVer.c_str(),
+ nPriority,
+ strComment.c_str(),
+ strStatusBar.c_str());
+}
+
+void CUnsignedAlert::print() const
+{
+ printf("%s", ToString().c_str());
+}
+
+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, 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;
+ // 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("alert", *this);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CAlert::CheckSignature() const
+{
+ CKey key;
+ if (!key.SetPubKey(ParseHex(fTestNet ? pszTestKey : pszMainKey)))
+ return error("CAlert::CheckSignature() : SetPubKey failed");
+ 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()
+{
+ if (!CheckSignature())
+ 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))
+ {
+ printf("cancelling alert %d\n", alert.nID);
+ uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
+ mapAlerts.erase(mi++);
+ }
+ else if (!alert.IsInEffect())
+ {
+ printf("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))
+ {
+ printf("alert already cancelled by %d\n", alert.nID);
+ return false;
+ }
+ }
+
+ // Add to mapAlerts
+ mapAlerts.insert(make_pair(GetHash(), *this));
+ // Notify UI if it applies to me
+ if(AppliesToMe())
+ uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
+ }
+
+ printf("accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
+ return true;
+}