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