![gavinandresen@gmail.com](/assets/img/avatar_default.png)
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