1 // This file is part of BOINC.
2 // http://boinc.berkeley.edu
3 // Copyright (C) 2008 University of California
5 // BOINC is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU Lesser General Public License
7 // as published by the Free Software Foundation,
8 // either version 3 of the License, or (at your option) any later version.
10 // BOINC is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 // See the GNU Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with BOINC. If not, see <http://www.gnu.org/licenses/>.
18 // Simple validator framework:
19 // Lets you create a custom validator by supplying three functions.
20 // See http://boinc.berkeley.edu/trac/wiki/ValidationSimple
29 #include "error_numbers.h"
31 #include "sched_config.h"
32 #include "sched_msgs.h"
34 #include "validator.h"
35 #include "validate_util.h"
36 #include "validate_util2.h"
37 #include "ChainWalkContext.h"
39 #include "part_validator.h"
43 // Given a set of results, check for a canonical result,
44 // i.e. a set of at least min_quorum/2+1 results for which
45 // that are equivalent according to check_pair().
48 // results.size() >= wu.min_quorum
50 // result.outcome == SUCCESS
51 // result.validate_state == INIT
54 vector<RESULT>& results, WORKUNIT& wu,
55 int& canonicalid, double& credit, bool& retry
61 int retval = frt.open("rainbowtables-distrrtgen", config.db_host, config.db_user, config.db_passwd);
63 log_messages.printf(MSG_CRITICAL, "can't open db rainbowtables-distrrtgen\n");
66 log_messages.printf(MSG_DEBUG, "Validating WU %i\n", wu.id);
69 vector<bool> had_error;
71 int min_valid = wu.min_quorum/2+1;
86 retval = init_result(results[i], data[i]);
87 if (retval == ERR_OPENDIR) {
88 log_messages.printf(MSG_CRITICAL,
89 "check_set: init_result([RESULT#%d %s]) transient failure\n",
90 results[i].id, results[i].name
94 log_messages.printf(MSG_CRITICAL,
95 "check_set: init_result([RESULT#%d %s]) failed: %d\n",
96 results[i].id, results[i].name, retval
98 results[i].outcome = RESULT_OUTCOME_VALIDATE_ERROR;
99 results[i].validate_state = VALIDATE_STATE_INVALID;
102 log_messages.printf(MSG_DEBUG, "check_set: init_result([RESULTÂ#%d %s]) fie is ok\n", results[i].id, results[i].name);
107 if (good_results < wu.min_quorum) {
108 log_messages.printf(MSG_DEBUG, "good_results < wu.min_quorum (%d < %d)", good_results, wu.min_quorum);
113 for (i=0; i<n; i++) {
114 if (had_error[i]) continue;
115 vector<bool> matches;
118 RainbowPartFile *curData = (RainbowPartFile*)data[i];
119 const char *pos = strchr(results[i].name, ' ');
120 char partnum[256] = {0};
121 strncpy(partnum, results[i].name, pos - results[i].name);
122 int partid = atoi(partnum);
123 sprintf(query, "SELECT t.PartSize, t.HashRoutine, t.Charset, t.MinLetters, t.MaxLetters, t.Index, t.ChainLength, p.ChainStart, t.Credits FROM generator_parts p INNER JOIN generator_tables t ON t.TableID = p.TableID WHERE p.PartID = %i", partid);
124 retval = frt.do_query(query);
127 log_messages.printf(MSG_CRITICAL, "Error executing query '%s'", query);
130 resp = mysql_store_result(frt.mysql);
132 log_messages.printf(MSG_CRITICAL, "Error doing mysql_store_result()");
136 row = mysql_fetch_row(resp);
138 log_messages.printf(MSG_CRITICAL, "mysql row not found for query '%s'", query);
142 int PartSize = atoi(row[0]);
143 log_messages.printf(MSG_DEBUG, "Starting verification...\n");
144 log_messages.printf(MSG_DEBUG, "Num chains: %i PartSize: %i...\n", curData->numchains, PartSize);
146 if(curData->numchains != PartSize)
148 log_messages.printf(MSG_CRITICAL,
149 "[RESULT#%d %s] File size doesn't match. Expectected %i, but got %i chains\n",
150 results[i].id, results[i].name, PartSize, curData->numchains
152 results[i].outcome = RESULT_OUTCOME_VALIDATE_ERROR;
153 results[i].validate_state = VALIDATE_STATE_INVALID;
156 log_messages.printf(MSG_DEBUG, "Converting %i %s %s %s %s %s %s %s %s...\n", partid, row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
158 string sHashRoutineName = row[1];
159 string sCharsetName = row[2];
160 int nPlainLenMin = atoi(row[3]);
161 int nPlainLenMax = atoi(row[4]);
162 int nRainbowTableIndex = atoi(row[5]);
163 int nRainbowChainLen = atoi(row[6]);
164 mysql_free_result(resp);
166 uint64 nChainStartPosition = atoll(row[7]);
167 float creditvalue = atof(row[8]);
168 log_messages.printf(MSG_DEBUG, "Setting hash routine to %s...\n", sHashRoutineName.c_str());
169 if (!CChainWalkContext::SetHashRoutine(sHashRoutineName))
171 log_messages.printf(MSG_CRITICAL,"[RESULT#%d %s]hash routine %s not supported\n", results[i].id, results[i].name, sHashRoutineName.c_str());
172 results[i].outcome = RESULT_OUTCOME_VALIDATE_ERROR;
173 results[i].validate_state = VALIDATE_STATE_INVALID;
176 log_messages.printf(MSG_DEBUG, "Setting charset to %s (%i-%i)...\n", sCharsetName.c_str(), nPlainLenMin, nPlainLenMax);
177 if (!CChainWalkContext::SetPlainCharset(sCharsetName, nPlainLenMin, nPlainLenMax))
179 log_messages.printf(MSG_CRITICAL,"[RESULT#%d %s]charset %s (%i - %i) not supported\n", results[i].id, results[i].name, sCharsetName.c_str(), nPlainLenMin, nPlainLenMax);
180 results[i].outcome = RESULT_OUTCOME_VALIDATE_ERROR;
181 results[i].validate_state = VALIDATE_STATE_INVALID;
184 log_messages.printf(MSG_DEBUG, "Setting index to %i...\n", nRainbowTableIndex);
186 if (!CChainWalkContext::SetRainbowTableIndex(nRainbowTableIndex))
188 log_messages.printf(MSG_CRITICAL,"[RESULT#%d %s]invalid rainbow table index %d\n", results[i].id, results[i].name, nRainbowTableIndex);
189 results[i].outcome = RESULT_OUTCOME_VALIDATE_ERROR;
190 results[i].validate_state = VALIDATE_STATE_INVALID;
193 RainbowChainCP *pChain = curData->pChain;
194 int nRainbowChainCountRead = curData->numchains;
196 for(j = 1; j <= 25; j++)
198 int nIndexToVerify = nRainbowChainCountRead / 25 * j - 1;
199 CChainWalkContext cwc;
200 log_messages.printf(MSG_DEBUG, "Setting seed to %lld for verification step %i...\n", pChain[nIndexToVerify].nIndexS, j);
202 cwc.SetIndex(pChain[nIndexToVerify].nIndexS);
204 for (nPos = 0; nPos < nRainbowChainLen - 1; nPos++)
208 cwc.HashToIndex(nPos);
211 if (cwc.GetIndex() != pChain[nIndexToVerify].nIndexE)
213 log_messages.printf(MSG_CRITICAL,
214 "[RESULT#%d %s] Rainbow chain length verification failed at step %i index %i (%lld != %lld)\n", results[i].id, results[i].name, j, nIndexToVerify, cwc.GetIndex(), pChain[nIndexToVerify].nIndexE);
215 results[i].outcome = RESULT_OUTCOME_VALIDATE_ERROR;
216 results[i].validate_state = VALIDATE_STATE_INVALID;
220 if(results[i].outcome == RESULT_OUTCOME_VALIDATE_ERROR && results[i].validate_state == VALIDATE_STATE_INVALID) break;
221 log_messages.printf(MSG_DEBUG, "Checking if all %i chains is within bounds...\n", PartSize);
223 for(j = 0; j < PartSize; j++)
225 if(pChain[j].nIndexS < (nChainStartPosition - 500000) || pChain[j].nIndexS > (nChainStartPosition + PartSize))
227 log_messages.printf(MSG_CRITICAL,
228 "[RESULT#%d %s] Start index verification failed at step %i with number %llu. (< %llu | > %llu)\n", results[i].id, results[i].name, j, pChain[j].nIndexS, nChainStartPosition, (nChainStartPosition + PartSize));
229 results[i].outcome = RESULT_OUTCOME_VALIDATE_ERROR;
230 results[i].validate_state = VALIDATE_STATE_INVALID;
233 if(j > 0 && pChain[j].nIndexE < pChain[j-1].nIndexE)
235 log_messages.printf(MSG_CRITICAL,
236 "[RESULT#%d %s] Chain sort test failed at step %i with number %llu < %llu\n", results[i].id, results[i].name, j, pChain[j].nIndexE, pChain[j-1].nIndexE);
237 results[i].outcome = RESULT_OUTCOME_VALIDATE_ERROR;
238 results[i].validate_state = VALIDATE_STATE_INVALID;
242 if(results[i].outcome == RESULT_OUTCOME_VALIDATE_ERROR && results[i].validate_state == VALIDATE_STATE_INVALID) break;
244 results[i].validate_state = VALIDATE_STATE_VALID;
245 canonicalid = results[i].id;
246 credit = creditvalue;
247 log_messages.printf(MSG_DEBUG, "WU %i is OK\n", wu.id);
249 for (j=0; j!=n; j++) {
250 if (had_error[j]) continue;
255 } else if (compare_results(results[i], data[i], results[j], data[j], match)) {
256 log_messages.printf(MSG_CRITICAL,
257 "generic_check_set: check_pair_with_data([RESULT#%d %s], [RESULT#%d %s]) failed\n",
258 results[i].id, results[i].name, results[j].id, results[j].name
265 if (neq >= min_valid) {
267 // set validate state for each result
269 for (j=0; j!=n; j++) {
270 if (had_error[j]) continue;
271 if (max_claimed_credit && results[j].claimed_credit > max_claimed_credit) {
272 results[j].validate_state = VALIDATE_STATE_INVALID;
274 results[j].validate_state = matches[j] ? VALIDATE_STATE_VALID : VALIDATE_STATE_INVALID;
277 canonicalid = results[i].id;
278 credit = compute_granted_credit(wu, results);
285 for (i=0; i<n; i++) {
286 cleanup_result(results[i], data[i]);
293 // r1 is the new result; r2 is canonical result
297 void check_pair(RESULT& r1, RESULT& r2, bool& retry) {
304 retval = init_result(r1, data1);
305 if (retval == ERR_OPENDIR) {
306 log_messages.printf(MSG_CRITICAL,
307 "check_pair: init_result([RESULT#%d %s]) transient failure 1\n",
313 log_messages.printf(MSG_CRITICAL,
314 "check_pair: init_result([RESULT#%d %s]) perm failure 1\n",
317 r1.outcome = RESULT_OUTCOME_VALIDATE_ERROR;
318 r1.validate_state = VALIDATE_STATE_INVALID;
322 retval = init_result(r2, data2);
323 if (retval == ERR_OPENDIR) {
324 log_messages.printf(MSG_CRITICAL,
325 "check_pair: init_result([RESULT#%d %s]) transient failure 2\n",
328 cleanup_result(r1, data1);
332 log_messages.printf(MSG_CRITICAL,
333 "check_pair: init_result([RESULT#%d %s]) perm failure2\n",
336 cleanup_result(r1, data1);
337 r1.outcome = RESULT_OUTCOME_VALIDATE_ERROR;
338 r1.validate_state = VALIDATE_STATE_INVALID;
342 retval = compare_results(r1, data1, r2, data2, match);
343 if (max_claimed_credit && r1.claimed_credit > max_claimed_credit) {
344 r1.validate_state = VALIDATE_STATE_INVALID;
346 r1.validate_state = match?VALIDATE_STATE_VALID:VALIDATE_STATE_INVALID;
348 cleanup_result(r1, data1);
349 cleanup_result(r2, data2);