Line data Source code
1 : // Copyright (c) 2013 The Bitcoin Core developers
2 : // Distributed under the MIT software license, see the accompanying
3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 :
5 : // Unit tests for alert system
6 :
7 : #include "alert.h"
8 : #include "chain.h"
9 : #include "chainparams.h"
10 : #include "clientversion.h"
11 : #include "data/alertTests.raw.h"
12 : #include "main.h" // For PartitionCheck
13 : #include "serialize.h"
14 : #include "streams.h"
15 : #include "util.h"
16 : #include "utilstrencodings.h"
17 :
18 : #include "test/test_bitcoin.h"
19 :
20 : #include <fstream>
21 :
22 : #include <boost/filesystem/operations.hpp>
23 : #include <boost/foreach.hpp>
24 : #include <boost/test/unit_test.hpp>
25 :
26 : #if 0
27 : //
28 : // alertTests contains 7 alerts, generated with this code:
29 : // (SignAndSave code not shown, alert signing key is secret)
30 : //
31 : {
32 : CAlert alert;
33 : alert.nRelayUntil = 60;
34 : alert.nExpiration = 24 * 60 * 60;
35 : alert.nID = 1;
36 : alert.nCancel = 0; // cancels previous messages up to this ID number
37 : alert.nMinVer = 0; // These versions are protocol versions
38 : alert.nMaxVer = 999001;
39 : alert.nPriority = 1;
40 : alert.strComment = "Alert comment";
41 : alert.strStatusBar = "Alert 1";
42 :
43 : SignAndSave(alert, "test/alertTests");
44 :
45 : alert.setSubVer.insert(std::string("/Satoshi:0.1.0/"));
46 : alert.strStatusBar = "Alert 1 for Satoshi 0.1.0";
47 : SignAndSave(alert, "test/alertTests");
48 :
49 : alert.setSubVer.insert(std::string("/Satoshi:0.2.0/"));
50 : alert.strStatusBar = "Alert 1 for Satoshi 0.1.0, 0.2.0";
51 : SignAndSave(alert, "test/alertTests");
52 :
53 : alert.setSubVer.clear();
54 : ++alert.nID;
55 : alert.nCancel = 1;
56 : alert.nPriority = 100;
57 : alert.strStatusBar = "Alert 2, cancels 1";
58 : SignAndSave(alert, "test/alertTests");
59 :
60 : alert.nExpiration += 60;
61 : ++alert.nID;
62 : SignAndSave(alert, "test/alertTests");
63 :
64 : ++alert.nID;
65 : alert.nMinVer = 11;
66 : alert.nMaxVer = 22;
67 : SignAndSave(alert, "test/alertTests");
68 :
69 : ++alert.nID;
70 : alert.strStatusBar = "Alert 2 for Satoshi 0.1.0";
71 : alert.setSubVer.insert(std::string("/Satoshi:0.1.0/"));
72 : SignAndSave(alert, "test/alertTests");
73 :
74 : ++alert.nID;
75 : alert.nMinVer = 0;
76 : alert.nMaxVer = 999999;
77 : alert.strStatusBar = "Evil Alert'; /bin/ls; echo '";
78 : alert.setSubVer.clear();
79 : SignAndSave(alert, "test/alertTests");
80 : }
81 : #endif
82 :
83 : struct ReadAlerts : public TestingSetup
84 : {
85 3 : ReadAlerts()
86 3 : {
87 3 : std::vector<unsigned char> vch(alert_tests::alertTests, alert_tests::alertTests + sizeof(alert_tests::alertTests));
88 : CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
89 : try {
90 27 : while (!stream.eof())
91 : {
92 24 : CAlert alert;
93 : stream >> alert;
94 24 : alerts.push_back(alert);
95 24 : }
96 : }
97 0 : catch (const std::exception&) { }
98 3 : }
99 3 : ~ReadAlerts() { }
100 :
101 1 : static std::vector<std::string> read_lines(boost::filesystem::path filepath)
102 : {
103 : std::vector<std::string> result;
104 :
105 3 : std::ifstream f(filepath.string().c_str());
106 : std::string line;
107 10 : while (std::getline(f,line))
108 4 : result.push_back(line);
109 :
110 1 : return result;
111 : }
112 :
113 : std::vector<CAlert> alerts;
114 : };
115 :
116 1 : BOOST_FIXTURE_TEST_SUITE(Alert_tests, ReadAlerts)
117 :
118 :
119 7 : BOOST_AUTO_TEST_CASE(AlertApplies)
120 : {
121 1 : SetMockTime(11);
122 2 : const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
123 :
124 54 : BOOST_FOREACH(const CAlert& alert, alerts)
125 : {
126 64 : BOOST_CHECK(alert.CheckSignature(alertKey));
127 : }
128 :
129 9 : BOOST_CHECK(alerts.size() >= 3);
130 :
131 : // Matches:
132 10 : BOOST_CHECK(alerts[0].AppliesTo(1, ""));
133 10 : BOOST_CHECK(alerts[0].AppliesTo(999001, ""));
134 10 : BOOST_CHECK(alerts[0].AppliesTo(1, "/Satoshi:11.11.11/"));
135 :
136 11 : BOOST_CHECK(alerts[1].AppliesTo(1, "/Satoshi:0.1.0/"));
137 11 : BOOST_CHECK(alerts[1].AppliesTo(999001, "/Satoshi:0.1.0/"));
138 :
139 11 : BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.1.0/"));
140 11 : BOOST_CHECK(alerts[2].AppliesTo(1, "/Satoshi:0.2.0/"));
141 :
142 : // Don't match:
143 10 : BOOST_CHECK(!alerts[0].AppliesTo(-1, ""));
144 10 : BOOST_CHECK(!alerts[0].AppliesTo(999002, ""));
145 :
146 11 : BOOST_CHECK(!alerts[1].AppliesTo(1, ""));
147 11 : BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0"));
148 11 : BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.1.0"));
149 11 : BOOST_CHECK(!alerts[1].AppliesTo(1, "Satoshi:0.1.0/"));
150 11 : BOOST_CHECK(!alerts[1].AppliesTo(-1, "/Satoshi:0.1.0/"));
151 11 : BOOST_CHECK(!alerts[1].AppliesTo(999002, "/Satoshi:0.1.0/"));
152 11 : BOOST_CHECK(!alerts[1].AppliesTo(1, "/Satoshi:0.2.0/"));
153 :
154 11 : BOOST_CHECK(!alerts[2].AppliesTo(1, "/Satoshi:0.3.0/"));
155 :
156 1 : SetMockTime(0);
157 1 : }
158 :
159 :
160 7 : BOOST_AUTO_TEST_CASE(AlertNotify)
161 : {
162 1 : SetMockTime(11);
163 2 : const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
164 :
165 : boost::filesystem::path temp = GetTempPath() /
166 4 : boost::filesystem::unique_path("alertnotify-%%%%.txt");
167 :
168 6 : mapArgs["-alertnotify"] = std::string("echo %s >> ") + temp.string();
169 :
170 62 : BOOST_FOREACH(CAlert alert, alerts)
171 16 : alert.ProcessAlert(alertKey, false);
172 :
173 3 : std::vector<std::string> r = read_lines(temp);
174 6 : BOOST_CHECK_EQUAL(r.size(), 4u);
175 :
176 : // Windows built-in echo semantics are different than posixy shells. Quotes and
177 : // whitespace are printed literally.
178 :
179 : #ifndef WIN32
180 5 : BOOST_CHECK_EQUAL(r[0], "Alert 1");
181 6 : BOOST_CHECK_EQUAL(r[1], "Alert 2, cancels 1");
182 6 : BOOST_CHECK_EQUAL(r[2], "Alert 2, cancels 1");
183 6 : BOOST_CHECK_EQUAL(r[3], "Evil Alert; /bin/ls; echo "); // single-quotes should be removed
184 : #else
185 : BOOST_CHECK_EQUAL(r[0], "'Alert 1' ");
186 : BOOST_CHECK_EQUAL(r[1], "'Alert 2, cancels 1' ");
187 : BOOST_CHECK_EQUAL(r[2], "'Alert 2, cancels 1' ");
188 : BOOST_CHECK_EQUAL(r[3], "'Evil Alert; /bin/ls; echo ' ");
189 : #endif
190 : boost::filesystem::remove(temp);
191 :
192 1 : SetMockTime(0);
193 1 : }
194 :
195 4 : static bool falseFunc() { return false; }
196 :
197 7 : BOOST_AUTO_TEST_CASE(PartitionAlert)
198 : {
199 : // Test PartitionCheck
200 : CCriticalSection csDummy;
201 100 : CBlockIndex indexDummy[100];
202 1 : CChainParams& params = Params(CBaseChainParams::MAIN);
203 1 : int64_t nPowTargetSpacing = params.GetConsensus().nPowTargetSpacing;
204 :
205 : // Generate fake blockchain timestamps relative to
206 : // an arbitrary time:
207 1 : int64_t now = 1427379054;
208 1 : SetMockTime(now);
209 100 : for (int i = 0; i < 100; i++)
210 : {
211 100 : indexDummy[i].phashBlock = NULL;
212 100 : if (i == 0) indexDummy[i].pprev = NULL;
213 99 : else indexDummy[i].pprev = &indexDummy[i-1];
214 100 : indexDummy[i].nHeight = i;
215 100 : indexDummy[i].nTime = now - (100-i)*nPowTargetSpacing;
216 : // Other members don't matter, the partition check code doesn't
217 : // use them
218 : }
219 :
220 : // Test 1: chain with blocks every nPowTargetSpacing seconds,
221 : // as normal, no worries:
222 1 : PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
223 8 : BOOST_CHECK(strMiscWarning.empty());
224 :
225 : // Test 2: go 3.5 hours without a block, expect a warning:
226 1 : now += 3*60*60+30*60;
227 1 : SetMockTime(now);
228 1 : PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
229 8 : BOOST_CHECK(!strMiscWarning.empty());
230 7 : BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
231 : strMiscWarning = "";
232 :
233 : // Test 3: test the "partition alerts only go off once per day"
234 : // code:
235 1 : now += 60*10;
236 1 : SetMockTime(now);
237 1 : PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
238 8 : BOOST_CHECK(strMiscWarning.empty());
239 :
240 : // Test 4: get 2.5 times as many blocks as expected:
241 1 : now += 60*60*24; // Pretend it is a day later
242 1 : SetMockTime(now);
243 1 : int64_t quickSpacing = nPowTargetSpacing*2/5;
244 101 : for (int i = 0; i < 100; i++) // Tweak chain timestamps:
245 100 : indexDummy[i].nTime = now - (100-i)*quickSpacing;
246 1 : PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
247 8 : BOOST_CHECK(!strMiscWarning.empty());
248 7 : BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
249 : strMiscWarning = "";
250 :
251 1 : SetMockTime(0);
252 1 : }
253 :
254 3 : BOOST_AUTO_TEST_SUITE_END()
|