Gavin Andresen
12 years ago
10 changed files with 351 additions and 293 deletions
@ -0,0 +1,239 @@
@@ -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; |
||||
} |
@ -0,0 +1,102 @@
@@ -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