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