Gavin Andresen
12 years ago
10 changed files with 348 additions and 293 deletions
@ -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; |
||||||
|
} |
@ -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 |
Loading…
Reference in new issue