Wip: remove boost from code
[novacoin.git] / src / alert.cpp
1 //
2 // Alert system
3 //
4
5 #include <map>
6
7 #include "alert.h"
8 #include "key.h"
9 #include "net.h"
10 #include "sync.h"
11 #include "interface.h"
12
13 using namespace std;
14
15 map<uint256, CAlert> mapAlerts;
16 CCriticalSection cs_mapAlerts;
17
18 static const char* pszMainKey = "043fa441fd4203d03f5df2b75ea14e36f20d39f43e7a61aa7552ab9bcd7ecb0e77a3be4585b13fcdaa22ef6e51f1ff6f2929bec2494385b086fb86610e33193195";
19
20 // TestNet alerts pubKey
21 static const char* pszTestKey = "0471dc165db490094d35cde15b1f5d755fa6ad6f2b5ed0f340e3f17f57389c3c2af113a8cbcc885bde73305a553b5640c83021128008ddf882e856336269080496";
22
23 // TestNet alerts private key
24 // "308201130201010420b665cff1884e53da26376fd1b433812c9a5a8a4d5221533b15b9629789bb7e42a081a53081a2020101302c06072a8648ce3d0101022100fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f300604010004010704410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141020101a1440342000471dc165db490094d35cde15b1f5d755fa6ad6f2b5ed0f340e3f17f57389c3c2af113a8cbcc885bde73305a553b5640c83021128008ddf882e856336269080496"
25
26 void CUnsignedAlert::SetNull()
27 {
28     nVersion = 1;
29     nRelayUntil = 0;
30     nExpiration = 0;
31     nID = 0;
32     nCancel = 0;
33     setCancel.clear();
34     nMinVer = 0;
35     nMaxVer = 0;
36     setSubVer.clear();
37     nPriority = 0;
38
39     strComment.clear();
40     strStatusBar.clear();
41     strReserved.clear();
42 }
43
44 std::string CUnsignedAlert::ToString() const
45 {
46     std::string strSetCancel;
47     for (int n : setCancel)
48         strSetCancel += strprintf("%d ", n);
49     std::string strSetSubVer;
50     for (const std::string& str : setSubVer)
51         strSetSubVer += "\"" + str + "\" ";
52     return strprintf(
53         "CAlert(\n"
54         "    nVersion     = %d\n"
55         "    nRelayUntil  = %" PRId64 "\n"
56         "    nExpiration  = %" PRId64 "\n"
57         "    nID          = %d\n"
58         "    nCancel      = %d\n"
59         "    setCancel    = %s\n"
60         "    nMinVer      = %d\n"
61         "    nMaxVer      = %d\n"
62         "    setSubVer    = %s\n"
63         "    nPriority    = %d\n"
64         "    strComment   = \"%s\"\n"
65         "    strStatusBar = \"%s\"\n"
66         ")\n",
67         nVersion,
68         nRelayUntil,
69         nExpiration,
70         nID,
71         nCancel,
72         strSetCancel.c_str(),
73         nMinVer,
74         nMaxVer,
75         strSetSubVer.c_str(),
76         nPriority,
77         strComment.c_str(),
78         strStatusBar.c_str());
79 }
80
81 void CAlert::SetNull()
82 {
83     CUnsignedAlert::SetNull();
84     vchMsg.clear();
85     vchSig.clear();
86 }
87
88 bool CAlert::IsNull() const
89 {
90     return (nExpiration == 0);
91 }
92
93 uint256 CAlert::GetHash() const
94 {
95     return Hash(this->vchMsg.begin(), this->vchMsg.end());
96 }
97
98 bool CAlert::IsInEffect() const
99 {
100     return (GetAdjustedTime() < nExpiration);
101 }
102
103 bool CAlert::Cancels(const CAlert& alert) const
104 {
105     if (!IsInEffect())
106         return false; // this was a no-op before 31403
107     return (alert.nID <= nCancel || setCancel.count(alert.nID));
108 }
109
110 bool CAlert::AppliesTo(int nVersion, const std::string& strSubVerIn) const
111 {
112     // TODO: rework for client-version-embedded-in-strSubVer ?
113     return (IsInEffect() &&
114             nMinVer <= nVersion && nVersion <= nMaxVer &&
115             (setSubVer.empty() || setSubVer.count(strSubVerIn)));
116 }
117
118 bool CAlert::AppliesToMe() const
119 {
120     return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));
121 }
122
123 bool CAlert::RelayTo(CNode* pnode) const
124 {
125     if (!IsInEffect())
126         return false;
127     // don't relay to nodes which haven't sent their version message
128     if (pnode->nVersion == 0)
129         return false;
130     // returns true if wasn't already contained in the set
131     if (pnode->setKnown.insert(GetHash()).second)
132     {
133         if (AppliesTo(pnode->nVersion, pnode->strSubVer) ||
134             AppliesToMe() ||
135             GetAdjustedTime() < nRelayUntil)
136         {
137             pnode->PushMessage("alert", *this);
138             return true;
139         }
140     }
141     return false;
142 }
143
144 bool CAlert::CheckSignature() const
145 {
146     CPubKey key;
147     key.Set(ParseHex(fTestNet ? pszTestKey : pszMainKey));
148     if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
149         return error("CAlert::CheckSignature() : verify signature failed");
150
151     // Now unserialize the data
152     CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
153     sMsg >> *(CUnsignedAlert*)this;
154     return true;
155 }
156
157 CAlert CAlert::getAlertByHash(const uint256 &hash)
158 {
159     CAlert retval;
160     {
161         LOCK(cs_mapAlerts);
162         auto mi = mapAlerts.find(hash);
163         if(mi != mapAlerts.end())
164             retval = mi->second;
165     }
166     return retval;
167 }
168
169 bool CAlert::ProcessAlert()
170 {
171     if (!CheckSignature())
172         return false;
173     if (!IsInEffect())
174         return false;
175
176     // alert.nID=max is reserved for if the alert key is
177     // compromised. It must have a pre-defined message,
178     // must never expire, must apply to all versions,
179     // and must cancel all previous
180     // alerts or it will be ignored (so an attacker can't
181     // send an "everything is OK, don't panic" version that
182     // cannot be overridden):
183     int maxInt = std::numeric_limits<int>::max();
184     if (nID == maxInt)
185     {
186         if (!(
187                 nExpiration == maxInt &&
188                 nCancel == (maxInt-1) &&
189                 nMinVer == 0 &&
190                 nMaxVer == maxInt &&
191                 setSubVer.empty() &&
192                 nPriority == maxInt &&
193                 strStatusBar == "URGENT: Alert key compromised, upgrade required"
194                 ))
195             return false;
196     }
197
198     {
199         LOCK(cs_mapAlerts);
200         // Cancel previous alerts
201         for (auto mi = mapAlerts.begin(); mi != mapAlerts.end();)
202         {
203             const CAlert& alert = (*mi).second;
204             if (Cancels(alert))
205             {
206                 printf("cancelling alert %d\n", alert.nID);
207                 uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
208                 mapAlerts.erase(mi++);
209             }
210             else if (!alert.IsInEffect())
211             {
212                 printf("expiring alert %d\n", alert.nID);
213                 uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
214                 mapAlerts.erase(mi++);
215             }
216             else
217                 mi++;
218         }
219
220         // Check if this alert has been cancelled
221         for (auto& item : mapAlerts)
222         {
223             const CAlert& alert = item.second;
224             if (alert.Cancels(*this))
225             {
226                 printf("alert already cancelled by %d\n", alert.nID);
227                 return false;
228             }
229         }
230
231         // Add to mapAlerts
232         mapAlerts.insert(make_pair(GetHash(), *this));
233         // Notify UI if it applies to me
234         if(AppliesToMe())
235             uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
236     }
237
238     printf("accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
239     return true;
240 }