Dash Core  0.12.2.1
P2P Digital Currency
governance-validators.cpp
Go to the documentation of this file.
1 // Copyright (c) 2014-2017 The Dash Core developers
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
6 
7 #include "base58.h"
8 #include "utilstrencodings.h"
9 
10 #include <algorithm>
11 
12 CProposalValidator::CProposalValidator(const std::string& strDataHexIn)
13  : strData(),
14  objJSON(UniValue::VOBJ),
15  fJSONValid(false),
16  strErrorMessages()
17 {
18  if(!strDataHexIn.empty()) {
19  SetHexData(strDataHexIn);
20  }
21 }
22 
24 {
25  strData = std::string();
27  fJSONValid = false;
28  strErrorMessages = std::string();
29 }
30 
31 void CProposalValidator::SetHexData(const std::string& strDataHexIn)
32 {
33  std::vector<unsigned char> v = ParseHex(strDataHexIn);
34  strData = std::string(v.begin(), v.end());
35  ParseJSONData();
36 }
37 
39 {
40  if(!ValidateJSON()) {
41  strErrorMessages += "JSON parsing error;";
42  return false;
43  }
44  if(!ValidateName()) {
45  strErrorMessages += "Invalid name;";
46  return false;
47  }
48  if(!ValidateStartEndEpoch()) {
49  strErrorMessages += "Invalid start:end range;";
50  return false;
51  }
52  if(!ValidatePaymentAmount()) {
53  strErrorMessages += "Invalid payment amount;";
54  return false;
55  }
56  if(!ValidatePaymentAddress()) {
57  strErrorMessages += "Invalid payment address;";
58  return false;
59  }
60  if(!ValidateURL()) {
61  strErrorMessages += "Invalid URL;";
62  return false;
63  }
64  return true;
65 }
66 
68 {
69  return fJSONValid;
70 }
71 
73 {
74  std::string strName;
75  if(!GetDataValue("name", strName)) {
76  strErrorMessages += "name field not found;";
77  return false;
78  }
79 
80  if(strName.size() > 40) {
81  strErrorMessages += "name exceeds 40 characters;";
82  return false;
83  }
84 
85  std::string strNameStripped = StripWhitespace(strName);
86 
87  if(strNameStripped.empty()) {
88  strErrorMessages += "name is empty;";
89  return false;
90  }
91 
92  static const std::string strAllowedChars = "-_abcdefghijklmnopqrstuvwxyz0123456789";
93 
94  std::transform(strName.begin(), strName.end(), strName.begin(), ::tolower);
95 
96  if(strName.find_first_not_of(strAllowedChars) != std::string::npos) {
97  strErrorMessages += "name contains invalid characters;";
98  return false;
99  }
100 
101  return true;
102 }
103 
105 {
106  int64_t nStartEpoch = 0;
107  int64_t nEndEpoch = 0;
108 
109  if(!GetDataValue("start_epoch", nStartEpoch)) {
110  strErrorMessages += "start_epoch field not found;";
111  return false;
112  }
113 
114  if(!GetDataValue("end_epoch", nEndEpoch)) {
115  strErrorMessages += "end_epoch field not found;";
116  return false;
117  }
118 
119  if(nEndEpoch <= nStartEpoch) {
120  strErrorMessages += "end_epoch <= start_epoch;";
121  return false;
122  }
123 
124  return true;
125 }
126 
128 {
129  double dValue = 0.0;
130 
131  if(!GetDataValue("payment_amount", dValue)) {
132  strErrorMessages += "payment_amount field not found;";
133  return false;
134  }
135 
136  if(dValue <= 0.0) {
137  strErrorMessages += "payment_amount is negative;";
138  return false;
139  }
140 
141  // TODO: Should check for an amount which exceeds the budget but this is
142  // currently difficult because start and end epochs are defined in terms of
143  // clock time instead of block height.
144 
145  return true;
146 }
147 
149 {
150  std::string strPaymentAddress;
151 
152  if(!GetDataValue("payment_address", strPaymentAddress)) {
153  strErrorMessages += "payment_address field not found;";
154  return false;
155  }
156 
157  static const std::string base58chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
158 
159  size_t nLength = strPaymentAddress.size();
160 
161  if((nLength < 26) || (nLength > 35)) {
162  strErrorMessages += "incorrect payment_address length;";
163  return false;
164  }
165 
166  if(strPaymentAddress.find_first_not_of(base58chars) != std::string::npos) {
167  strErrorMessages += "payment_address contains invalid characters;";
168  return false;
169  }
170 
171  CBitcoinAddress address(strPaymentAddress);
172  if(!address.IsValid()) {
173  strErrorMessages += "payment_address is invalid;";
174  return false;
175  }
176 
177  return true;
178 }
179 
181 {
182  std::string strURL;
183  if(!GetDataValue("url", strURL)) {
184  strErrorMessages += "url field not found;";
185  return false;
186  }
187 
188  std::string strURLStripped = StripWhitespace(strURL);
189 
190  if(strURLStripped.size() < 4U) {
191  strErrorMessages += "url too short;";
192  return false;
193  }
194 
195  if(!CheckURL(strURL)) {
196  strErrorMessages += "url invalid;";
197  return false;
198  }
199 
200  return true;
201 }
202 
204 {
205  fJSONValid = false;
206 
207  if(strData.empty()) {
208  return;
209  }
210 
211  try {
213  obj.read(strData);
214  std::vector<UniValue> arr1 = obj.getValues();
215  std::vector<UniValue> arr2 = arr1.at(0).getValues();
216  objJSON = arr2.at(1);
217  fJSONValid = true;
218  }
219  catch(std::exception& e) {
220  strErrorMessages += std::string(e.what()) + std::string(";");
221  }
222  catch(...) {
223  strErrorMessages += "Unknown exception;";
224  }
225 }
226 
227 bool CProposalValidator::GetDataValue(const std::string& strKey, std::string& strValue)
228 {
229  bool fOK = false;
230  try {
231  strValue = objJSON[strKey].get_str();
232  fOK = true;
233  }
234  catch(std::exception& e) {
235  strErrorMessages += std::string(e.what()) + std::string(";");
236  }
237  catch(...) {
238  strErrorMessages += "Unknown exception;";
239  }
240  return fOK;
241 }
242 
243 bool CProposalValidator::GetDataValue(const std::string& strKey, int64_t& nValue)
244 {
245  bool fOK = false;
246  try {
247  const UniValue uValue = objJSON[strKey];
248  switch(uValue.getType()) {
249  case UniValue::VNUM:
250  nValue = uValue.get_int64();
251  fOK = true;
252  break;
253  default:
254  break;
255  }
256  }
257  catch(std::exception& e) {
258  strErrorMessages += std::string(e.what()) + std::string(";");
259  }
260  catch(...) {
261  strErrorMessages += "Unknown exception;";
262  }
263  return fOK;
264 }
265 
266 bool CProposalValidator::GetDataValue(const std::string& strKey, double& dValue)
267 {
268  bool fOK = false;
269  try {
270  const UniValue uValue = objJSON[strKey];
271  switch(uValue.getType()) {
272  case UniValue::VNUM:
273  dValue = uValue.get_real();
274  fOK = true;
275  break;
276  default:
277  break;
278  }
279  }
280  catch(std::exception& e) {
281  strErrorMessages += std::string(e.what()) + std::string(";");
282  }
283  catch(...) {
284  strErrorMessages += "Unknown exception;";
285  }
286  return fOK;
287 }
288 
289 std::string CProposalValidator::StripWhitespace(const std::string& strIn)
290 {
291  static const std::string strWhitespace = " \f\n\r\t\v";
292 
293  std::string::size_type nStart = strIn.find_first_not_of(strWhitespace);
294  std::string::size_type nEnd = strIn.find_last_not_of(strWhitespace);
295 
296  if((nStart == std::string::npos) || (nEnd == std::string::npos)) {
297  return std::string();
298  }
299 
300  return strIn.substr(nStart, nEnd - nStart + 1);
301 }
302 
303 /*
304  The purpose of this function is to replicate the behavior of the
305  Python urlparse function used by sentinel (urlparse.py). This function
306  should return false whenever urlparse raises an exception and true
307  otherwise.
308  */
309 bool CProposalValidator::CheckURL(const std::string& strURLIn)
310 {
311  std::string strRest(strURLIn);
312  std::string::size_type nPos = strRest.find(':');
313 
314  if(nPos != std::string::npos) {
315  //std::string strSchema = strRest.substr(0,nPos);
316 
317  if(nPos < strRest.size()) {
318  strRest = strRest.substr(nPos + 1);
319  }
320  else {
321  strRest = "";
322  }
323  }
324 
325  // Process netloc
326  if((strRest.size() > 2) && (strRest.substr(0,2) == "//")) {
327  static const std::string strNetlocDelimiters = "/?#";
328 
329  strRest = strRest.substr(2);
330 
331  std::string::size_type nPos2 = strRest.find_first_of(strNetlocDelimiters);
332 
333  std::string strNetloc = strRest.substr(0,nPos2);
334 
335  if((strNetloc.find('[') != std::string::npos) && (strNetloc.find(']') == std::string::npos)) {
336  return false;
337  }
338 
339  if((strNetloc.find(']') != std::string::npos) && (strNetloc.find('[') == std::string::npos)) {
340  return false;
341  }
342  }
343 
344  return true;
345 }
double get_real() const
Definition: univalue.cpp:337
bool IsValid() const
Definition: base58.cpp:247
static std::string StripWhitespace(const std::string &strIn)
static bool CheckURL(const std::string &strURLIn)
int64_t get_int64() const
Definition: univalue.cpp:327
void SetHexData(const std::string &strDataHexIn)
bool GetDataValue(const std::string &strKey, std::string &strValue)
vector< unsigned char > ParseHex(const char *psz)
enum VType getType() const
Definition: univalue.h:65
bool read(const char *raw)
CProposalValidator(const std::string &strDataHexIn=std::string())
std::string get_str() const
Definition: univalue.cpp:310
std::vector< UniValue > getValues() const
Definition: univalue.cpp:296