Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor: move alert code from main to alert.cpp/h
- Loading branch information
1 parent
06707dd
commit f35c6c4
Showing
10 changed files
with
348 additions
and
293 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
// | ||
// 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; | ||
|
||
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("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284"))) | ||
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
// Copyright (c) 2010 Satoshi Nakamoto | ||
// Copyright (c) 2009-2012 The Bitcoin developers | ||
// Distributed under the MIT/X11 software license, see the accompanying | ||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||
|
||
#ifndef _BITCOINALERT_H_ | ||
#define _BITCOINALERT_H_ 1 | ||
|
||
#include <set> | ||
#include <string> | ||
|
||
#include "uint256.h" | ||
#include "util.h" | ||
|
||
class CNode; | ||
|
||
/** 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 nRelayUntil; // when newer nodes stop relaying to newer nodes | ||
int64 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; | ||
|
||
IMPLEMENT_SERIALIZE | ||
( | ||
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(strComment); | ||
READWRITE(strStatusBar); | ||
READWRITE(strReserved); | ||
) | ||
|
||
void SetNull(); | ||
|
||
std::string ToString() const; | ||
void print() 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(); | ||
} | ||
|
||
IMPLEMENT_SERIALIZE | ||
( | ||
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, std::string strSubVerIn) const; | ||
bool AppliesToMe() const; | ||
bool RelayTo(CNode* pnode) const; | ||
bool CheckSignature() const; | ||
bool ProcessAlert(); | ||
|
||
/* | ||
* Get copy of (active) alert object by hash. Returns a null alert if it is not found. | ||
*/ | ||
static CAlert getAlertByHash(const uint256 &hash); | ||
}; | ||
|
||
#endif |
Oops, something went wrong.