Dogecoin Core  1.14.2
P2P Digital Currency
alert.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2015 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include "alert.h"
7 
8 #include "clientversion.h"
9 #include "net.h"
10 #include "netmessagemaker.h"
11 #include "pubkey.h"
12 #include "timedata.h"
13 #include "ui_interface.h"
14 #include "util.h"
15 #include "utilstrencodings.h"
16 
17 #include <stdint.h>
18 #include <algorithm>
19 #include <map>
20 
21 #include <boost/algorithm/string/classification.hpp>
22 #include <boost/algorithm/string/replace.hpp>
23 #include <boost/foreach.hpp>
24 #include <boost/thread.hpp>
25 
26 using namespace std;
27 
28 map<uint256, CAlert> mapAlerts;
30 
32 {
33  nVersion = 1;
34  nRelayUntil = 0;
35  nExpiration = 0;
36  nID = 0;
37  nCancel = 0;
38  setCancel.clear();
39  nMinVer = 0;
40  nMaxVer = 0;
41  setSubVer.clear();
42  nPriority = 0;
43 
44  strComment.clear();
45  strStatusBar.clear();
46  strReserved.clear();
47 }
48 
49 std::string CUnsignedAlert::ToString() const
50 {
51  std::string strSetCancel;
52  BOOST_FOREACH(int n, setCancel)
53  strSetCancel += strprintf("%d ", n);
54  std::string strSetSubVer;
55  BOOST_FOREACH(const std::string& str, setSubVer)
56  strSetSubVer += "\"" + str + "\" ";
57  return strprintf(
58  "CAlert(\n"
59  " nVersion = %d\n"
60  " nRelayUntil = %d\n"
61  " nExpiration = %d\n"
62  " nID = %d\n"
63  " nCancel = %d\n"
64  " setCancel = %s\n"
65  " nMinVer = %d\n"
66  " nMaxVer = %d\n"
67  " setSubVer = %s\n"
68  " nPriority = %d\n"
69  " strComment = \"%s\"\n"
70  " strStatusBar = \"%s\"\n"
71  ")\n",
72  nVersion,
73  nRelayUntil,
74  nExpiration,
75  nID,
76  nCancel,
77  strSetCancel,
78  nMinVer,
79  nMaxVer,
80  strSetSubVer,
81  nPriority,
82  strComment,
83  strStatusBar);
84 }
85 
87 {
89  vchMsg.clear();
90  vchSig.clear();
91 }
92 
93 bool CAlert::IsNull() const
94 {
95  return (nExpiration == 0);
96 }
97 
99 {
100  return Hash(this->vchMsg.begin(), this->vchMsg.end());
101 }
102 
103 bool CAlert::IsInEffect() const
104 {
105  return (GetAdjustedTime() < nExpiration);
106 }
107 
108 bool CAlert::Cancels(const CAlert& alert) const
109 {
110  if (!IsInEffect())
111  return false; // this was a no-op before 31403
112  return (alert.nID <= nCancel || setCancel.count(alert.nID));
113 }
114 
115 bool CAlert::AppliesTo(int nVersion, const std::string& strSubVerIn) const
116 {
117  // TODO: rework for client-version-embedded-in-strSubVer ?
118  return (IsInEffect() &&
119  nMinVer <= nVersion && nVersion <= nMaxVer &&
120  (setSubVer.empty() || setSubVer.count(strSubVerIn)));
121 }
122 
124 {
125  return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));
126 }
127 
128 bool CAlert::CheckSignature(const std::vector<unsigned char>& alertKey) const
129 {
130  CPubKey key(alertKey);
131  if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
132  return error("CAlert::CheckSignature(): verify signature failed");
133 
134  // Now unserialize the data
135  CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
136  sMsg >> *(CUnsignedAlert*)this;
137  return true;
138 }
139 
141 {
142  CAlert retval;
143  {
145  map<uint256, CAlert>::iterator mi = mapAlerts.find(hash);
146  if(mi != mapAlerts.end())
147  retval = mi->second;
148  }
149  return retval;
150 }
151 
152 bool CAlert::ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread)
153 {
154  if (!CheckSignature(alertKey))
155  return false;
156  if (!IsInEffect())
157  return false;
158 
159  // alert.nID=max is reserved for if the alert key is
160  // compromised. It must have a pre-defined message,
161  // must never expire, must apply to all versions,
162  // and must cancel all previous
163  // alerts or it will be ignored (so an attacker can't
164  // send an "everything is OK, don't panic" version that
165  // cannot be overridden):
166  int maxInt = std::numeric_limits<int>::max();
167  if (nID == maxInt)
168  {
169  if (!(
170  nExpiration == maxInt &&
171  nCancel == (maxInt-1) &&
172  nMinVer == 0 &&
173  nMaxVer == maxInt &&
174  setSubVer.empty() &&
175  nPriority == maxInt &&
176  strStatusBar == "URGENT: Alert key compromised, upgrade required"
177  ))
178  return false;
179  }
180 
181  {
183  // Cancel previous alerts
184  for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
185  {
186  const CAlert& alert = (*mi).second;
187  if (Cancels(alert))
188  {
189  LogPrint("alert", "cancelling alert %d\n", alert.nID);
191  mapAlerts.erase(mi++);
192  }
193  else if (!alert.IsInEffect())
194  {
195  LogPrint("alert", "expiring alert %d\n", alert.nID);
197  mapAlerts.erase(mi++);
198  }
199  else
200  mi++;
201  }
202 
203  // Check if this alert has been cancelled
204  BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
205  {
206  const CAlert& alert = item.second;
207  if (alert.Cancels(*this))
208  {
209  LogPrint("alert", "alert already cancelled by %d\n", alert.nID);
210  return false;
211  }
212  }
213 
214  // Add to mapAlerts
215  mapAlerts.insert(make_pair(GetHash(), *this));
216  // Notify UI and -alertnotify if it applies to me
217  if(AppliesToMe())
218  {
220  Notify(strStatusBar, fThread);
221  }
222  }
223 
224  LogPrint("alert", "accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
225  return true;
226 }
227 
228 void
229 CAlert::Notify(const std::string& strMessage, bool fThread)
230 {
231  std::string strCmd = GetArg("-alertnotify", "");
232  if (strCmd.empty()) return;
233 
234  // Alert text should be plain ascii coming from a trusted source, but to
235  // be safe we first strip anything not in safeChars, then add single quotes around
236  // the whole string before passing it to the shell:
237  std::string singleQuote("'");
238  std::string safeStatus = SanitizeString(strMessage);
239  safeStatus = singleQuote+safeStatus+singleQuote;
240  boost::replace_all(strCmd, "%s", safeStatus);
241 
242  if (fThread)
243  boost::thread t(runCommand, strCmd); // thread runs free
244  else
245  runCommand(strCmd);
246 }
CCriticalSection cs_mapAlerts
Definition: alert.cpp:29
map< uint256, CAlert > mapAlerts
Definition: alert.cpp:28
An alert is a combination of a serialized CUnsignedAlert and a signature.
Definition: alert.h:77
bool IsInEffect() const
Definition: alert.cpp:103
uint256 GetHash() const
Definition: alert.cpp:98
bool CheckSignature(const std::vector< unsigned char > &alertKey) const
Definition: alert.cpp:128
bool Cancels(const CAlert &alert) const
Definition: alert.cpp:108
void SetNull()
Definition: alert.cpp:86
bool IsNull() const
Definition: alert.cpp:93
bool AppliesTo(int nVersion, const std::string &strSubVerIn) const
Definition: alert.cpp:115
static CAlert getAlertByHash(const uint256 &hash)
Definition: alert.cpp:140
static void Notify(const std::string &strMessage, bool fThread=true)
Definition: alert.cpp:229
bool AppliesToMe() const
Definition: alert.cpp:123
bool ProcessAlert(const std::vector< unsigned char > &alertKey, bool fThread=true)
Definition: alert.cpp:152
boost::signals2::signal< void(const uint256 &hash, ChangeType status)> NotifyAlertChanged
New, updated or cancelled alert.
Definition: ui_interface.h:95
Wrapped boost mutex: supports recursive locking, but no waiting TODO: We should move away from using ...
Definition: sync.h:93
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:147
An encapsulated public key.
Definition: pubkey.h:40
bool Verify(const uint256 &hash, const std::vector< unsigned char > &vchSig) const
Verify a DER signature (~72 bytes).
Definition: pubkey.cpp:167
Alerts are for notifying old versions if they become too obsolete and need to upgrade.
Definition: alert.h:31
std::string ToString() const
Definition: alert.cpp:49
void SetNull()
Definition: alert.cpp:31
256-bit opaque blob.
Definition: uint256.h:123
std::string FormatSubVersion(const std::string &name, int nClientVersion, const std::vector< std::string > &comments)
Format the subversion field according to BIP 14 spec (https://github.com/bitcoin/bips/blob/master/bip...
const std::string CLIENT_NAME
uint256 Hash(const T1 pbegin, const T1 pend)
Compute the 256-bit hash of an object.
Definition: hash.h:70
@ SER_NETWORK
Definition: serialize.h:146
#define LOCK(cs)
Definition: sync.h:177
int64_t GetAdjustedTime()
Definition: timedata.cpp:36
#define strprintf
Definition: tinyformat.h:1047
CClientUIInterface uiInterface
Definition: ui_interface.cpp:8
@ CT_DELETED
Definition: ui_interface.h:25
@ CT_NEW
Definition: ui_interface.h:23
std::string GetArg(const std::string &strArg, const std::string &strDefault)
Return string argument or default value.
Definition: util.cpp:395
void runCommand(const std::string &strCommand)
Definition: util.cpp:774
#define LogPrint(category,...)
Definition: util.h:76
bool error(const char *fmt, const Args &... args)
Definition: util.h:87
string SanitizeString(const string &str, int rule)
#define PAIRTYPE(t1, t2)
This is needed because the foreach macro can't get over the comma in pair<t1, t2>