Open-Transactions  0.93.0-ge03d287
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
OTBylaw.cpp
Go to the documentation of this file.
1 /************************************************************
2  *
3  * OTBylaw.cpp
4  *
5  */
6 
7 /************************************************************
8  -----BEGIN PGP SIGNED MESSAGE-----
9  Hash: SHA1
10 
11  * OPEN TRANSACTIONS
12  *
13  * Financial Cryptography and Digital Cash
14  * Library, Protocol, API, Server, CLI, GUI
15  *
16  * -- Anonymous Numbered Accounts.
17  * -- Untraceable Digital Cash.
18  * -- Triple-Signed Receipts.
19  * -- Cheques, Vouchers, Transfers, Inboxes.
20  * -- Basket Currencies, Markets, Payment Plans.
21  * -- Signed, XML, Ricardian-style Contracts.
22  * -- Scripted smart contracts.
23  *
24  * Copyright (C) 2010-2013 by "Fellow Traveler" (A pseudonym)
25  *
26  * EMAIL:
28  *
29  * BITCOIN: 1NtTPVVjDsUfDWybS4BwvHpG2pdS9RnYyQ
30  *
31  * KEY FINGERPRINT (PGP Key in license file):
32  * 9DD5 90EB 9292 4B48 0484 7910 0308 00ED F951 BB8E
33  *
34  * OFFICIAL PROJECT WIKI(s):
35  * https://github.com/FellowTraveler/Moneychanger
36  * https://github.com/FellowTraveler/Open-Transactions/wiki
37  *
38  * WEBSITE:
39  * http://www.OpenTransactions.org/
40  *
41  * Components and licensing:
42  * -- Moneychanger..A Java client GUI.....LICENSE:.....GPLv3
43  * -- otlib.........A class library.......LICENSE:...LAGPLv3
44  * -- otapi.........A client API..........LICENSE:...LAGPLv3
45  * -- opentxs/ot....Command-line client...LICENSE:...LAGPLv3
46  * -- otserver......Server Application....LICENSE:....AGPLv3
47  * Github.com/FellowTraveler/Open-Transactions/wiki/Components
48  *
49  * All of the above OT components were designed and written by
50  * Fellow Traveler, with the exception of Moneychanger, which
51  * was contracted out to Vicky C ([email protected]).
52  * The open-source community has since actively contributed.
53  *
54  * -----------------------------------------------------
55  *
56  * LICENSE:
57  * This program is free software: you can redistribute it
58  * and/or modify it under the terms of the GNU Affero
59  * General Public License as published by the Free Software
60  * Foundation, either version 3 of the License, or (at your
61  * option) any later version.
62  *
63  * ADDITIONAL PERMISSION under the GNU Affero GPL version 3
64  * section 7: (This paragraph applies only to the LAGPLv3
65  * components listed above.) If you modify this Program, or
66  * any covered work, by linking or combining it with other
67  * code, such other code is not for that reason alone subject
68  * to any of the requirements of the GNU Affero GPL version 3.
69  * (==> This means if you are only using the OT API, then you
70  * don't have to open-source your code--only your changes to
71  * Open-Transactions itself must be open source. Similar to
72  * LGPLv3, except it applies to software-as-a-service, not
73  * just to distributing binaries.)
74  *
75  * Extra WAIVER for OpenSSL, Lucre, and all other libraries
76  * used by Open Transactions: This program is released under
77  * the AGPL with the additional exemption that compiling,
78  * linking, and/or using OpenSSL is allowed. The same is true
79  * for any other open source libraries included in this
80  * project: complete waiver from the AGPL is hereby granted to
81  * compile, link, and/or use them with Open-Transactions,
82  * according to their own terms, as long as the rest of the
83  * Open-Transactions terms remain respected, with regard to
84  * the Open-Transactions code itself.
85  *
86  * Lucre License:
87  * This code is also "dual-license", meaning that Ben Lau-
88  * rie's license must also be included and respected, since
89  * the code for Lucre is also included with Open Transactions.
90  * See Open-Transactions/src/otlib/lucre/LUCRE_LICENSE.txt
91  * The Laurie requirements are light, but if there is any
92  * problem with his license, simply remove the Lucre code.
93  * Although there are no other blind token algorithms in Open
94  * Transactions (yet. credlib is coming), the other functions
95  * will continue to operate.
96  * See Lucre on Github: https://github.com/benlaurie/lucre
97  * -----------------------------------------------------
98  * You should have received a copy of the GNU Affero General
99  * Public License along with this program. If not, see:
100  * http://www.gnu.org/licenses/
101  *
102  * If you would like to use this software outside of the free
103  * software license, please contact FellowTraveler.
104  * (Unfortunately many will run anonymously and untraceably,
105  * so who could really stop them?)
106  *
107  * DISCLAIMER:
108  * This program is distributed in the hope that it will be
109  * useful, but WITHOUT ANY WARRANTY; without even the implied
110  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
111  * PURPOSE. See the GNU Affero General Public License for
112  * more details.
113 
114  -----BEGIN PGP SIGNATURE-----
115  Version: GnuPG v1.4.9 (Darwin)
116 
117  iQIcBAEBAgAGBQJRSsfJAAoJEAMIAO35UbuOQT8P/RJbka8etf7wbxdHQNAY+2cC
118  vDf8J3X8VI+pwMqv6wgTVy17venMZJa4I4ikXD/MRyWV1XbTG0mBXk/7AZk7Rexk
119  KTvL/U1kWiez6+8XXLye+k2JNM6v7eej8xMrqEcO0ZArh/DsLoIn1y8p8qjBI7+m
120  aE7lhstDiD0z8mwRRLKFLN2IH5rAFaZZUvj5ERJaoYUKdn4c+RcQVei2YOl4T0FU
121  LWND3YLoH8naqJXkaOKEN4UfJINCwxhe5Ke9wyfLWLUO7NamRkWD2T7CJ0xocnD1
122  sjAzlVGNgaFDRflfIF4QhBx1Ddl6wwhJfw+d08bjqblSq8aXDkmFA7HeunSFKkdn
123  oIEOEgyj+veuOMRJC5pnBJ9vV+7qRdDKQWaCKotynt4sWJDGQ9kWGWm74SsNaduN
124  TPMyr9kNmGsfR69Q2Zq/FLcLX/j8ESxU+HYUB4vaARw2xEOu2xwDDv6jt0j3Vqsg
125  x7rWv4S/Eh18FDNDkVRChiNoOIilLYLL6c38uMf1pnItBuxP3uhgY6COm59kVaRh
126  nyGTYCDYD2TK+fI9o89F1297uDCwEJ62U0Q7iTDp5QuXCoxkPfv8/kX6lS6T3y9G
127  M9mqIoLbIQ1EDntFv7/t6fUTS2+46uCrdZWbQ5RjYXdrzjij02nDmJAm2BngnZvd
128  kamH0Y/n11lCvo1oQxM+
129  =uSzz
130  -----END PGP SIGNATURE-----
131  **************************************************************/
132 
133 #include "stdafx.hpp"
134 
135 #include "OTBylaw.hpp"
136 
137 #include "OTClause.hpp"
138 #include "OTLog.hpp"
139 #include "OTScriptable.hpp"
140 
141 #include <set>
142 
143 namespace opentxs
144 {
145 
146 void OTBylaw::Serialize(OTString& strAppend, bool bCalculatingID) const
147 {
148  strAppend.Concatenate("<bylaw\n name=\"%s\"\n"
149  " numVariables=\"%d\"\n"
150  " numClauses=\"%d\"\n"
151  " numHooks=\"%d\"\n"
152  " numCallbacks=\"%d\"\n"
153  " language=\"%s\" >\n\n",
154  m_strName.Get(),
155  m_mapVariables.size(), // HOW MANY VARIABLES?
156  m_mapClauses.size(), // HOW MANY CLAUSES?
157  m_mapHooks.size(), // How many HOOKS?
158  m_mapCallbacks.size(), // How many CALLBACK?
159  m_strLanguage.Get());
160 
161  for (auto& it : m_mapVariables) {
162  OTVariable* pVar = it.second;
163  OT_ASSERT(nullptr != pVar);
164 
165  pVar->Serialize(strAppend, bCalculatingID); // Variables save in a
166  // specific state during ID
167  // calculation (no matter
168  // their current actual
169  // value.)
170  }
171 
172  for (auto& it : m_mapClauses) {
173  OTClause* pClause = it.second;
174  OT_ASSERT(nullptr != pClause);
175 
176  pClause->Serialize(strAppend);
177  }
178 
179  for (auto& it : m_mapHooks) {
180  const std::string& str_hook_name = it.first;
181  const std::string& str_clause_name = it.second;
182 
183  strAppend.Concatenate("<hook\n name=\"%s\"\n"
184  " clause=\"%s\" />\n\n",
185  str_hook_name.c_str(), str_clause_name.c_str());
186  }
187 
188  for (auto& it : m_mapCallbacks) {
189  const std::string& str_callback_name = it.first;
190  const std::string& str_clause_name = it.second;
191 
192  strAppend.Concatenate("<callback\n name=\"%s\"\n"
193  " clause=\"%s\" />\n\n",
194  str_callback_name.c_str(),
195  str_clause_name.c_str());
196  }
197 
198  strAppend.Concatenate("</bylaw>\n\n");
199 }
200 
201 // So you can tell if the persistent or important variables have CHANGED since
202 // it was last set clean.
203 //
204 bool OTBylaw::IsDirty() const
205 {
206  bool bIsDirty = false;
207 
208  for (const auto& it : m_mapVariables) {
209  OTVariable* pVar = it.second;
210  OT_ASSERT(nullptr != pVar);
211 
212  // "Persistent" *AND* "Important" Variables are both considered
213  // "persistent".
214  // Important has the added distinction that notices are required when
215  // important variables change.
216  //
217  if (pVar->IsDirty()) {
218  if (pVar->IsPersistent()) {
219  bIsDirty = true;
220  break;
221  }
222  else // If it's not persistent (which also includes important) the
223  // only other option is CONSTANT. Then why is it dirty?
224  otErr << "OTBylaw::IsDirty: Error: Why is it that a variable "
225  "is CONSTANT, yet DIRTY at the same time?\n";
226  }
227  }
228 
229  return bIsDirty;
230 }
231 
232 // So you can tell if ONLY the IMPORTANT variables have changed since the last
233 // "set clean".
234 //
236 {
237  bool bIsDirty = false;
238 
239  for (const auto& it : m_mapVariables) {
240  OTVariable* pVar = it.second;
241  OT_ASSERT(nullptr != pVar);
242 
243  // "Persistent" *AND* "Important" Variables are both considered
244  // "persistent".
245  // But: Important has the added distinction that notices are required
246  // when important variables change.
247  // (So sometimes you need to know if important variables have changed,
248  // so you know whether to send a notice.)
249  //
250  if (pVar->IsDirty() && pVar->IsImportant()) {
251  bIsDirty = true;
252  break;
253  }
254  }
255 
256  return bIsDirty;
257 }
258 
259 // Sets the variables as clean, so you can check later and see if any have been
260 // changed (if it's DIRTY again.)
261 //
263 {
264  for (auto& it : m_mapVariables) {
265  OTVariable* pVar = it.second;
266  OT_ASSERT(nullptr != pVar);
267 
268  pVar->SetAsClean(); // so we can check for dirtiness later, if it's
269  // changed.
270  }
271 }
272 
273 // Register the variables of a specific Bylaw into the Script interpreter,
274 // so we can execute a script.
275 //
277 {
278  for (auto& it : m_mapVariables) {
279  const std::string str_var_name = it.first;
280  OTVariable* pVar = it.second;
281  OT_ASSERT((nullptr != pVar) && (str_var_name.size() > 0));
282 
283  pVar->RegisterForExecution(theScript);
284  }
285 }
286 
287 // Done:
289 {
290  if ((m_strName.Compare(rhs.GetName())) &&
291  (m_strLanguage.Compare(rhs.GetLanguage()))) {
292  if (GetVariableCount() != rhs.GetVariableCount()) {
293  otOut << "OTBylaw::Compare: The variable count doesn't match for "
294  "bylaw: " << m_strName << "\n";
295  return false;
296  }
297  if (GetClauseCount() != rhs.GetClauseCount()) {
298  otOut << "OTBylaw::Compare: The clause count doesn't match for "
299  "bylaw: " << m_strName << "\n";
300  return false;
301  }
302  if (GetHookCount() != rhs.GetHookCount()) {
303  otOut
304  << "OTBylaw::Compare: The hook count doesn't match for bylaw: "
305  << m_strName << "\n";
306  return false;
307  }
308  if (GetCallbackCount() != rhs.GetCallbackCount()) {
309  otOut << "OTBylaw::Compare: The callback count doesn't match for "
310  "bylaw: " << m_strName << "\n";
311  return false;
312  }
313  // THE COUNTS MATCH, Now let's look up each one by NAME and verify that
314  // they match...
315 
316  for (const auto& it : m_mapVariables) {
317  OTVariable* pVar = it.second;
318  OT_ASSERT(nullptr != pVar);
319 
320  OTVariable* pVar2 = rhs.GetVariable(pVar->GetName().Get());
321 
322  if (nullptr == pVar2) {
323  otOut << "OTBylaw::Compare: Failed: Variable not found: "
324  << pVar->GetName() << ".\n";
325  return false;
326  }
327  if (!pVar->Compare(*pVar2)) {
328  otOut << "OTBylaw::Compare: Failed comparison between 2 "
329  "variables named " << pVar->GetName() << ".\n";
330  return false;
331  }
332  }
333 
334  for (const auto& it : m_mapClauses) {
335  OTClause* pClause = it.second;
336  OT_ASSERT(nullptr != pClause);
337 
338  OTClause* pClause2 = rhs.GetClause(pClause->GetName().Get());
339 
340  if (nullptr == pClause2) {
341  otOut << "OTBylaw::Compare: Failed: Clause not found: "
342  << pClause->GetName() << ".\n";
343  return false;
344  }
345  if (!pClause->Compare(*pClause2)) {
346  otOut << "OTBylaw::Compare: Failed comparison between 2 "
347  "clauses named " << pClause->GetName() << ".\n";
348  return false;
349  }
350  }
351 
352  for (const auto& it : m_mapCallbacks) {
353  const std::string& str_callback_name = it.first;
354  const std::string& str_clause_name = it.second;
355 
356  OTClause* pCallbackClause = GetCallback(str_callback_name);
357  OTClause* pCallbackClause2 = rhs.GetCallback(str_callback_name);
358 
359  if (nullptr == pCallbackClause) {
360  otOut << "OTBylaw::Compare: Failed: Callback ("
361  << str_callback_name << ") clause (" << str_clause_name
362  << ") not found on this bylaw: " << m_strName << ".\n";
363  return false;
364  }
365  else if (nullptr == pCallbackClause2) {
366  otOut << "OTBylaw::Compare: Failed: Callback ("
367  << str_callback_name << ") clause (" << str_clause_name
368  << ") not found on rhs bylaw: " << rhs.GetName() << ".\n";
369  return false;
370  }
371  else if (!(pCallbackClause->GetName().Compare(
372  pCallbackClause2->GetName()))) {
373  otOut << "OTBylaw::Compare: Failed: Callback ("
374  << str_callback_name << ") clause (" << str_clause_name
375  << ") on rhs has a different name ("
376  << pCallbackClause2->GetName()
377  << ") than *this bylaw: " << m_strName << ".\n";
378  return false;
379  }
380 
381  // OPTIMIZE: Since ALL the clauses are already compared, one-by-one,
382  // in the above block, then we don't
383  // actually HAVE to do a compare clause here. We just need to make
384  // sure that we got them both via the same
385  // name, and that the counts are the same (as already verified
386  // above) and that should actually be good enough.
387  }
388 
389  std::set<std::string> theHookSet;
390 
391  // There might be MANY entries with the SAME HOOK NAME. So we add them
392  // all to a SET in order to get unique keys.
393  for (const auto& it : m_mapHooks) {
394  const std::string& str_hook_name = it.first;
395  theHookSet.insert(str_hook_name);
396  }
397  // Now we loop through all the unique hook names, and get
398  // the list of clauses for EACH bylaw for THAT HOOK.
399  for (const auto& it_hook : theHookSet) {
400  const std::string& str_hook_name = it_hook;
401 
402  mapOfClauses theHookClauses, theHookClauses2;
403 
404  if (!GetHooks(str_hook_name, theHookClauses) ||
405  !rhs.GetHooks(str_hook_name, theHookClauses2)) {
406  otOut << "OTBylaw::Compare: Failed finding hook ("
407  << str_hook_name
408  << ") clauses on this bylaw or rhs bylaw: " << m_strName
409  << "\n";
410  return false;
411  }
412 
413  if (theHookClauses.size() != theHookClauses2.size()) {
414  otOut << "OTBylaw::Compare: Hook (" << str_hook_name
415  << ") clauses count doesn't match between this bylaw and "
416  "the rhs bylaw named: " << m_strName << "\n";
417  return false;
418  }
419 
420  for (auto& it : theHookClauses) {
421  const std::string str_clause_name = it.first;
422  OTClause* pClause = it.second;
423  OT_ASSERT(nullptr != pClause);
424 
425  auto it_rhs = theHookClauses2.find(str_clause_name);
426 
427  if (theHookClauses2.end() == it_rhs) {
428  otOut << "OTBylaw::Compare: Unable to find hook clause ("
429  << str_clause_name
430  << ") on rhs that was definitely present on *this. "
431  "Bylaw: " << m_strName << "\n";
432  return false;
433  }
434 
435  // OPTIMIZE: Since ALL the clauses are already compared,
436  // one-by-one, in an above block, then we don't
437  // actually HAVE to do a compare clause here. We just need to
438  // make sure that we got them both via the same
439  // name, and that the counts are the same (as already verified
440  // above) and that should actually be good enough.
441  }
442  }
443 
444  return true;
445  }
446 
447  return false;
448 }
449 
450 const std::string OTBylaw::GetCallbackNameByIndex(int32_t nIndex)
451 {
452  if ((nIndex < 0) ||
453  (nIndex >= static_cast<int64_t>(m_mapCallbacks.size()))) {
454  otErr << __FUNCTION__ << ": Index out of bounds: " << nIndex << "\n";
455  }
456  else {
457  int32_t nLoopIndex = -1;
458 
459  for (auto& it : m_mapCallbacks) {
460  const std::string& str_callback_name = it.first;
461  ++nLoopIndex; // 0 on first iteration.
462  if (nLoopIndex == nIndex) return str_callback_name;
463  }
464  }
465  return "";
466 }
467 
468 OTClause* OTBylaw::GetCallback(std::string str_CallbackName)
469 {
470  if ((false ==
471  OTScriptable::ValidateName(str_CallbackName)) || // Invalid callback
472  // name was passed in.
473  (str_CallbackName.compare(0, 9, "callback_") !=
474  0)) // The first 9 characters do not match callback_
475  {
476  otErr << "OTBylaw::GetCallback: Callback name MUST begin with "
477  "callback_ but value passed in was: " << str_CallbackName
478  << "\n";
479  return nullptr;
480  }
481 
482  for (auto& it : m_mapCallbacks) {
483  const std::string& str_callback_name = it.first;
484  const std::string& str_clause_name = it.second;
485 
486  // IF this entry (of a clause registered for a specific callback)
487  // MATCHES the callback name passed in...
488  //
489  if (0 == (str_callback_name.compare(str_CallbackName))) {
490  OTClause* pClause = GetClause(str_clause_name);
491 
492  if (nullptr != pClause) // found it
493  {
494  return pClause;
495  }
496  else {
497  otOut << "OTBylaw::GetCallback: Couldn't find clause ("
498  << str_clause_name
499  << ") that was registered for callback ("
500  << str_callback_name << ")\n";
501  }
502  }
503  // else no error, since it's normal for nothing to match.
504  }
505 
506  return nullptr;
507 }
508 
509 // You are NOT allowed to add multiple callbacks for any given callback trigger.
510 // There can be only one clause that answers to any given callback.
511 //
512 bool OTBylaw::AddCallback(std::string str_CallbackName,
513  std::string str_ClauseName)
514 {
515  // Make sure it's not already there...
516  //
517  auto it = m_mapCallbacks.find(str_CallbackName);
518 
519  if (m_mapCallbacks.end() != it) // It's already there. (Can't add it twice.)
520  {
521  const std::string str_existing_clause = it->second;
522  otOut << "OTBylaw::AddCallback: Failed to add callback ("
523  << str_CallbackName << ") to bylaw " << m_strName
524  << ", already there as " << str_existing_clause << ".\n";
525  return false;
526  }
527  // Below this point, we know the callback wasn't already there.
528 
529  if (!OTScriptable::ValidateName(str_CallbackName) ||
530  !OTScriptable::ValidateName(str_ClauseName))
531  otErr << "OTBylaw::AddCallback: Error: empty name (" << str_CallbackName
532  << ") or clause (" << str_ClauseName << ").";
533  else if (str_CallbackName.compare(0, 9, "callback_") !=
534  0) // If the callback name DOESN'T begin with callback_ then it is
535  // rejected.
536  otOut << "OTBylaw::AddCallback: Callback name MUST begin with "
537  "callback_ in order to be accepted: Failure. (callback name "
538  << str_CallbackName << ") (clause name " << str_ClauseName
539  << ") \n";
540  else if (m_mapCallbacks.end() ==
541  m_mapCallbacks.insert(
542  m_mapCallbacks.begin(),
543  std::pair<std::string, std::string>(str_CallbackName.c_str(),
544  str_ClauseName.c_str())))
545  otErr << "OTBylaw::AddCallback: Failed inserting to m_mapCallbacks: "
546  << str_CallbackName << " / " << str_ClauseName << " \n";
547  else
548  return true;
549 
550  return false;
551 }
552 
553 // You ARE allowed to add multiple clauses for the same hook.
554 // They will ALL trigger on that hook.
555 //
556 bool OTBylaw::AddHook(std::string str_HookName, std::string str_ClauseName)
557 {
558  if (!OTScriptable::ValidateName(str_HookName) ||
559  !OTScriptable::ValidateName(str_ClauseName))
560  otErr << "OTBylaw::AddHook: Error: empty hook name (" << str_HookName
561  << ") or clause name (" << str_ClauseName << ").";
562  else if ((str_HookName.compare(0, 5, "cron_") != 0) &&
563  (str_HookName.compare(0, 5, "hook_") != 0))
564  otOut << "OTBylaw::AddHook: hook name MUST begin with either hook_ or "
565  "cron_ in order to be accepted: Failure."
566  " (hook name " << str_HookName << ") (clause name "
567  << str_ClauseName << ") \n";
568  else if (m_mapHooks.end() ==
569  m_mapHooks.insert(std::pair<std::string, std::string>(
570  str_HookName.c_str(), str_ClauseName.c_str())))
571  otErr << "OTBylaw::AddHook: Failed inserting to m_mapHooks: "
572  << str_HookName << " / " << str_ClauseName << " \n";
573  else
574  return true;
575 
576  return false;
577 }
578 
579 OTVariable* OTBylaw::GetVariable(std::string str_var_name) // not a
580  // reference,
581  // so you can
582  // pass in char
583 // *. Maybe that's bad? todo: research that.
584 {
585  if (!OTScriptable::ValidateName(str_var_name)) {
586  otErr << "OTBylaw::GetVariable: Error: invalid str_var_name.\n";
587  return nullptr;
588  }
589 
590  auto it = m_mapVariables.find(str_var_name);
591 
592  if (m_mapVariables.end() == it) return nullptr;
593 
594  OTVariable* pVar = it->second;
595  OT_ASSERT(nullptr != pVar);
596 
597  return pVar;
598 }
599 
603 {
604  if (!((nIndex >= 0) &&
605  (nIndex < static_cast<int64_t>(m_mapVariables.size())))) {
606  otErr << __FUNCTION__ << ": Index out of bounds: " << nIndex << "\n";
607  }
608  else {
609  int32_t nLoopIndex = -1;
610 
611  for (auto& it : m_mapVariables) {
612  OTVariable* pVar = it.second;
613  OT_ASSERT(nullptr != pVar);
614 
615  ++nLoopIndex; // 0 on first iteration.
616 
617  if (nLoopIndex == nIndex) return pVar;
618  }
619  }
620  return nullptr;
621 }
622 
623 OTClause* OTBylaw::GetClause(std::string str_clause_name) const
624 {
625  if (!OTScriptable::ValidateName(str_clause_name)) {
626  otErr << "OTBylaw::GetClause: Error: empty str_clause_name.\n";
627  return nullptr;
628  }
629 
630  auto it = m_mapClauses.find(str_clause_name);
631 
632  if (m_mapClauses.end() == it) return nullptr;
633 
634  OTClause* pClause = it->second;
635  OT_ASSERT(nullptr != pClause);
636 
637  return pClause;
638 }
639 
643 {
644  if (!((nIndex >= 0) &&
645  (nIndex < static_cast<int64_t>(m_mapClauses.size())))) {
646  otErr << __FUNCTION__ << ": Index out of bounds: " << nIndex << "\n";
647  }
648  else {
649  int32_t nLoopIndex = -1;
650 
651  for (auto& it : m_mapClauses) {
652  OTClause* pClause = it.second;
653  OT_ASSERT(nullptr != pClause);
654 
655  ++nLoopIndex; // 0 on first iteration.
656 
657  if (nLoopIndex == nIndex) return pClause;
658  }
659  }
660  return nullptr;
661 }
662 
663 const std::string OTBylaw::GetHookNameByIndex(int32_t nIndex)
664 {
665  if ((nIndex < 0) || (nIndex >= static_cast<int64_t>(m_mapHooks.size()))) {
666  otErr << __FUNCTION__ << ": Index out of bounds: " << nIndex << "\n";
667  }
668  else {
669  int32_t nLoopIndex = -1;
670 
671  for (auto& it : m_mapHooks) {
672  const std::string& str_hook_name = it.first;
673  ++nLoopIndex; // 0 on first iteration.
674 
675  if (nLoopIndex == nIndex) return str_hook_name;
676  }
677  }
678  return "";
679 }
680 
681 // Returns a map of clause pointers (or not) based on the HOOK name.
682 // ANY clauses on the list for that hook. (There could be many for each hook.)
683 // "GetHooks" could have been termed,
684 // "GetAMapOfAllClausesRegisteredForTheHookWithName(str_HookName)
685 //
686 bool OTBylaw::GetHooks(std::string str_HookName, mapOfClauses& theResults)
687 {
688  if (!OTScriptable::ValidateName(str_HookName)) {
689  otErr << __FUNCTION__ << ": Error: invalid str_HookName.\n";
690  return false;
691  }
692 
693  if ((str_HookName.compare(0, 5, "cron_") != 0) &&
694  (str_HookName.compare(0, 5, "hook_") != 0)) {
695  otOut << __FUNCTION__ << ": hook name MUST begin with either hook_ or "
696  "cron_ in order to be accepted: Failure."
697  " (hook name " << str_HookName << ")\n";
698  return false;
699  }
700 
701  bool bReturnVal = false;
702 
703  for (auto& it : m_mapHooks) {
704  const std::string& str_hook_name = it.first;
705  const std::string& str_clause_name = it.second;
706 
707  // IF this entry (of a clause registered for a specific hook) MATCHES
708  // the hook name passed in...
709  //
710  if (0 == (str_hook_name.compare(str_HookName))) {
711  OTClause* pClause = GetClause(str_clause_name);
712 
713  if (nullptr != pClause) // found it
714  {
715  // mapOfClauses is a map, meaning it will only allow one entry
716  // per unique clause name.
717  // Remember, mapOfHooks is a multimap, since there may be
718  // multiple clauses registered to
719  // the same hook. (Which is fine.) But what if someone registers
720  // the SAME clause MULTIPLE
721  // TIMES to the SAME HOOK? No need for that. So by the time the
722  // clauses are inserted into
723  // the result map, the duplicates are automatically weeded out.
724  //
725  if (theResults.end() !=
726  theResults.insert(theResults.begin(),
727  std::pair<std::string, OTClause*>(
728  str_clause_name, pClause)))
729  bReturnVal = true;
730  }
731  else {
732  otOut << __FUNCTION__ << ": Couldn't find clause ("
733  << str_clause_name << ") that was registered for hook ("
734  << str_hook_name << ")\n";
735  }
736  }
737  // else no error, since it's normal for nothing to match.
738  }
739 
740  return bReturnVal;
741 }
742 
744 {
745  const std::string str_name = theVariable.GetName().Get();
746 
747  if (!OTScriptable::ValidateName(str_name)) {
748  otErr << "OTBylaw::AddVariable: Failed due to invalid variable name. "
749  "In Bylaw: " << m_strName << "\n";
750  return false;
751  }
752 
753  // This prefix is disallowed since it's reserved for clause parameter names.
754  //
755  if (str_name.compare(0, 6, "param_") == 0) {
756  otErr << "OTBylaw::AddVariable: Failed due to invalid variable name ("
757  << str_name << "). In Bylaw: " << m_strName
758  << ". (param_ is reserved.)\n";
759  return false;
760  }
761  if (str_name.compare(0, 7, "return_") == 0) {
762  otErr << "OTBylaw::AddVariable: Failed due to invalid variable name ("
763  << str_name << "). In Bylaw: " << m_strName
764  << ". (return_ is reserved.)\n";
765  return false;
766  }
767 
768  // todo security: validate the name.
769  //
770  auto it = m_mapVariables.find(str_name);
771 
772  // Make sure it's not already there...
773  //
774  if (m_mapVariables.end() == it) // If it wasn't already there...
775  {
776 
777  // Then insert it...
778  m_mapVariables.insert(
779  std::pair<std::string, OTVariable*>(str_name, &theVariable));
780 
781  // Make sure it has a pointer back to me.
782  theVariable.SetBylaw(*this);
783 
784  return true;
785  }
786  else
787  otOut << "OTBylaw::AddVariable: Failed -- A variable was already there "
788  "named: " << str_name << "\n";
789 
790  return false;
791 }
792 
793 bool OTBylaw::AddVariable(std::string str_Name, bool bValue,
795 {
796  OTVariable* pVar = new OTVariable(str_Name, bValue, theAccess);
797  OT_ASSERT(nullptr != pVar);
798 
799  if (!AddVariable(*pVar)) {
800  delete pVar;
801  return false;
802  }
803 
804  return true;
805 }
806 
807 bool OTBylaw::AddVariable(std::string str_Name, std::string str_Value,
809 {
810  OTVariable* pVar = new OTVariable(str_Name, str_Value, theAccess);
811  OT_ASSERT(nullptr != pVar);
812 
813  if (!AddVariable(*pVar)) {
814  delete pVar;
815  return false;
816  }
817 
818  return true;
819 }
820 
821 bool OTBylaw::AddVariable(std::string str_Name, int32_t nValue,
823 {
824  OTVariable* pVar = new OTVariable(str_Name, nValue, theAccess);
825  OT_ASSERT(nullptr != pVar);
826 
827  if (!AddVariable(*pVar)) {
828  delete pVar;
829  return false;
830  }
831 
832  return true;
833 }
834 
835 bool OTBylaw::AddClause(const char* szName, const char* szCode)
836 {
837  // todo security: validate the input, especially name.
838  //
839 
840  OT_ASSERT(nullptr != szName);
841  OT_ASSERT(nullptr != szCode);
842 
843  OTClause* pClause = new OTClause(szName, szCode);
844  OT_ASSERT(nullptr != pClause);
845 
846  if (!AddClause(*pClause)) {
847  delete pClause;
848  return false;
849  }
850 
851  return true;
852 }
853 
854 bool OTBylaw::AddClause(OTClause& theClause)
855 {
856  if (!theClause.GetName().Exists()) {
857  otErr << "OTBylaw::AddClause: Failed attempt to add a clause with a "
858  "blank name.\n";
859  return false;
860  }
861 
862  // To avoid confusion, we disallow clauses beginning in cron_ or hook_ or
863  // callback_
864  //
865  const std::string str_clause_name = theClause.GetName().Get();
866 
867  if (!OTScriptable::ValidateName(str_clause_name)) {
868  otErr << "OTBylaw::AddClause: Failed due to invalid clause name. In "
869  "Bylaw: " << m_strName << "\n";
870  return false;
871  }
872 
873  if (str_clause_name.compare(0, 5, "cron_") == 0) // todo stop hardcoding
874  {
875  otOut << "OTBylaw::AddClause: Clauses may not be added with a name "
876  "beginning in cron_\n";
877  return false;
878  }
879 
880  if (str_clause_name.compare(0, 5, "hook_") == 0) // todo stop hardcoding
881  {
882  otOut << "OTBylaw::AddClause: Clauses may not be added with a name "
883  "beginning in hook_\n";
884  return false;
885  }
886 
887  if (str_clause_name.compare(0, 9, "callback_") == 0) // todo stop hardcoding
888  {
889  otOut << "OTBylaw::AddClause: Clauses may not be added with a name "
890  "beginning in callback_\n";
891  return false;
892  }
893  // Todo: any other validation on the name. security.
894 
895  auto it = m_mapClauses.find(str_clause_name);
896 
897  if (m_mapClauses.end() == it) // If it wasn't already there...
898  {
899 
900  // Then insert it...
901  m_mapClauses.insert(
902  std::pair<std::string, OTClause*>(str_clause_name, &theClause));
903 
904  // Make sure it has a pointer back to me.
905  theClause.SetBylaw(*this);
906 
907  return true;
908  }
909  else
910  otOut << "OTBylaw::AddClause: Failed -- Clause was already there named "
911  << str_clause_name << ".\n";
912 
913  return false;
914 }
915 
916 const char* OTBylaw::GetLanguage() const
917 {
918  return m_strLanguage.Exists() ? m_strLanguage.Get()
919  : "chai"; // todo add default script to config
920  // files. no hardcoding.
921 }
922 
924  : m_pOwnerAgreement(nullptr)
925 {
926 }
927 
928 OTBylaw::OTBylaw(const char* szName, const char* szLanguage)
929  : m_pOwnerAgreement(nullptr)
930 {
931  if (nullptr != szName)
932  m_strName.Set(szName);
933  else
934  otErr << "nullptr szName passed in to OTBylaw::OTBylaw \n";
935 
936  if (nullptr != szLanguage)
937  m_strLanguage = szLanguage; // "chai", "angelscript" etc.
938  else
939  otErr << "nullptr szLanguage passed in to OTBylaw::OTBylaw \n";
940 
941  const std::string str_bylaw_name = m_strName.Get();
942  const std::string str_language = m_strLanguage.Get();
943 
944  // Let the calling function validate these, if he doesn't want to risk an
945  // ASSERT...
946  //
947  if (!OTScriptable::ValidateName(str_bylaw_name) ||
948  !OTScriptable::ValidateName(str_language)) {
949  otErr << "Failed validation in to OTBylaw::OTBylaw \n";
950  }
951 }
952 
954 {
955  // A Bylaw owns its clauses and variables.
956  //
957  while (!m_mapClauses.empty()) {
958  OTClause* pClause = m_mapClauses.begin()->second;
959  OT_ASSERT(nullptr != pClause);
960 
961  m_mapClauses.erase(m_mapClauses.begin());
962 
963  delete pClause;
964  pClause = nullptr;
965  }
966 
967  while (!m_mapVariables.empty()) {
968  OTVariable* pVar = m_mapVariables.begin()->second;
969  OT_ASSERT(nullptr != pVar);
970 
971  m_mapVariables.erase(m_mapVariables.begin());
972 
973  delete pVar;
974  pVar = nullptr;
975  }
976 
977  m_pOwnerAgreement =
978  nullptr; // This Bylaw is owned by an agreement (OTScriptable-derived.)
979 
980  // Hooks and Callbacks are maps of std::string to std::string.
981  //
982  // (THEREFORE NO NEED TO CLEAN THEM UP HERE.)
983  //
984 }
985 
986 } // namespace opentxs
static bool ValidateName(std::string str_name)
EXPORT int32_t GetHookCount() const
Definition: OTBylaw.hpp:238
EXPORT bool AddClause(OTClause &theClause)
Definition: OTBylaw.cpp:854
EXPORT void RegisterForExecution(OTScript &theScript)
Definition: OTVariable.cpp:424
EXPORT OTClause * GetClauseByIndex(int32_t nIndex)
Definition: OTBylaw.cpp:642
virtual ~OTBylaw()
Definition: OTBylaw.cpp:953
bool IsDirty() const
Definition: OTVariable.cpp:353
void Serialize(OTString &strAppend) const
Definition: OTClause.cpp:184
EXPORT void RegisterVariablesForExecution(OTScript &theScript)
Definition: OTBylaw.cpp:276
bool IsImportant() const
Definition: OTVariable.hpp:208
EXPORT OTClause * GetCallback(std::string str_CallbackName)
Definition: OTBylaw.cpp:468
OTLOG_IMPORT OTLogStream otOut
void SetBylaw(OTBylaw &theBylaw)
Definition: OTVariable.hpp:212
EXPORT bool Compare(OTBylaw &rhs)
Definition: OTBylaw.cpp:288
EXPORT bool GetHooks(std::string str_HookName, mapOfClauses &theResults)
Definition: OTBylaw.cpp:686
EXPORT int32_t GetClauseCount() const
Definition: OTBylaw.hpp:230
std::map< std::string, OTClause * > mapOfClauses
Definition: OTBylaw.hpp:145
EXPORT bool IsDirty() const
Definition: OTBylaw.cpp:204
EXPORT const OTString & GetName() const
Definition: OTClause.hpp:155
EXPORT void Concatenate(const char *arg,...)
Definition: OTString.cpp:1334
EXPORT int32_t GetCallbackCount() const
Definition: OTBylaw.hpp:234
EXPORT void SetAsClean()
Definition: OTBylaw.cpp:262
EXPORT bool Exists() const
Definition: OTString.cpp:1035
EXPORT const std::string GetHookNameByIndex(int32_t nIndex)
Definition: OTBylaw.cpp:663
EXPORT OTClause * GetClause(std::string str_Name) const
Definition: OTBylaw.cpp:623
void SetBylaw(OTBylaw &theBylaw)
Definition: OTClause.hpp:150
EXPORT const std::string GetCallbackNameByIndex(int32_t nIndex)
Definition: OTBylaw.cpp:450
EXPORT const OTString & GetName() const
Definition: OTVariable.hpp:220
EXPORT bool Compare(const char *compare) const
Definition: OTString.cpp:1102
EXPORT void Set(const char *data, uint32_t enforcedMaxLength=0)
Definition: OTString.cpp:1055
void Serialize(OTString &strAppend, bool bCalculatingID=false) const
Definition: OTVariable.cpp:144
EXPORT bool AddVariable(OTVariable &theVariable)
Definition: OTBylaw.cpp:743
#define OT_ASSERT(x)
Definition: Assert.hpp:150
EXPORT bool IsDirtyImportant() const
Definition: OTBylaw.cpp:235
EXPORT void Serialize(OTString &strAppend, bool bCalculatingID=false) const
Definition: OTBylaw.cpp:146
EXPORT OTVariable * GetVariable(std::string str_Name)
Definition: OTBylaw.cpp:579
EXPORT bool AddCallback(std::string str_CallbackName, std::string str_ClauseName)
Definition: OTBylaw.cpp:512
EXPORT const char * Get() const
Definition: OTString.cpp:1045
OTLOG_IMPORT OTLogStream otErr
EXPORT const OTString & GetName() const
Definition: OTBylaw.hpp:177
EXPORT const char * GetLanguage() const
Definition: OTBylaw.cpp:916
EXPORT int32_t GetVariableCount() const
Definition: OTBylaw.hpp:226
EXPORT bool AddHook(std::string str_HookName, std::string str_ClauseName)
Definition: OTBylaw.cpp:556
bool Compare(const OTClause &rhs) const
Definition: OTClause.cpp:201
EXPORT OTVariable * GetVariableByIndex(int32_t nIndex)
Definition: OTBylaw.cpp:602
bool IsPersistent() const
Definition: OTVariable.hpp:204
bool Compare(OTVariable &rhs)
Definition: OTVariable.cpp:438
EXPORT OTBylaw()
Definition: OTBylaw.cpp:923