Open-Transactions  0.93.0-ge03d287
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
OTAccount.cpp
Go to the documentation of this file.
1 /************************************************************
2  *
3  * OTAccount.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 "OTAccount.hpp"
136 #include "util/OTDataFolder.hpp"
137 #include "util/OTFolders.hpp"
138 #include "OTLedger.hpp"
139 #include "OTLog.hpp"
140 #include "OTMessage.hpp"
141 #include "OTStorage.hpp"
142 #include "util/OTPaths.hpp"
143 #include "OTPayload.hpp"
144 #include "OTPseudonym.hpp"
145 
146 #include <irrxml/irrXML.hpp>
147 
148 #include <fstream>
149 
150 #ifndef _WIN32
151 #include <unistd.h>
152 #include <sys/time.h>
153 #endif
154 
155 using namespace irr;
156 using namespace io;
157 
158 namespace opentxs
159 {
160 
161 char const* const __TypeStrings[] = {
162  "simple", // used by users
163  "issuer", // used by issuers (these can only go negative.)
164  "basket", // issuer acct used by basket currencies (these can only go
165  // negative)
166  "basketsub", // used by the server (to store backing reserves for basket
167  // sub-accounts)
168  "mint", // used by mints (to store backing reserves for cash)
169  "voucher", // used by the server (to store backing reserves for vouchers)
170  "stash", // used by the server (to store backing reserves for stashes, for
171  // smart contracts.)
172  "err_acct"};
173 
174 // Used for generating accounts, thus no accountID needed.
175 OTAccount::OTAccount(const OTIdentifier& userId, const OTIdentifier& serverId)
177  , stashTransNum_(0)
178  , markForDeletion_(false)
179 {
180  InitAccount();
181  SetUserID(userId);
182  SetRealServerID(serverId);
183  SetPurportedServerID(serverId);
184 }
185 
188  , stashTransNum_(0)
189  , markForDeletion_(false)
190 {
191  InitAccount();
192 }
193 
194 OTAccount::OTAccount(const OTIdentifier& userId, const OTIdentifier& accountId,
195  const OTIdentifier& serverId, const OTString& name)
196  : OTTransactionType(userId, accountId, serverId)
197  , stashTransNum_(0)
198  , markForDeletion_(false)
199 {
200  InitAccount();
201  m_strName = name;
202 }
203 
204 OTAccount::OTAccount(const OTIdentifier& userId, const OTIdentifier& accountId,
205  const OTIdentifier& serverId)
206  : OTTransactionType(userId, accountId, serverId)
207  , stashTransNum_(0)
208  , markForDeletion_(false)
209 {
210  InitAccount();
211 }
212 
214 {
215  Release_Account();
216 }
217 
218 char const* OTAccount::_GetTypeString(AccountType accountType)
219 {
220  int32_t index = static_cast<int32_t>(accountType);
221  return __TypeStrings[index];
222 }
223 
224 // Caller responsible to delete.
226 {
227  auto* box =
229  OT_ASSERT(box != nullptr);
230 
231  if (box->LoadInbox() && box->VerifyAccount(nym)) {
232  return box;
233  }
234 
235  OTString strUserID(GetUserID()), strAcctID(GetRealAccountID());
236  otInfo << "Unable to load or verify inbox:\n" << strAcctID
237  << "\n For user:\n" << strUserID << "\n";
238  return nullptr;
239 }
240 
241 // Caller responsible to delete.
243 {
244  auto* box =
246  OT_ASSERT(nullptr != box);
247 
248  if (box->LoadOutbox() && box->VerifyAccount(nym)) {
249  return box;
250  }
251 
252  OTString strUserID(GetUserID()), strAcctID(GetRealAccountID());
253  otInfo << "Unable to load or verify outbox:\n" << strAcctID
254  << "\n For user:\n" << strUserID << "\n";
255  return nullptr;
256 }
257 
258 // hash is optional, the account will update its internal copy of the hash
259 // anyway.
261 {
262  if (!IsSameAccount(box)) {
263  OTString strAcctID(GetRealAccountID());
264  OTString strServerID(GetRealServerID());
265  OTString strBoxAcctID(box.GetRealAccountID());
266  OTString strBoxSvrID(box.GetRealServerID());
267  otErr << "OTAccount::SaveInbox: ERROR: The ledger passed in, isn't "
268  "even for this account!\n"
269  " Acct ID: " << strAcctID << "\n Other ID: " << strBoxAcctID
270  << "\n Server ID: " << strServerID
271  << "\n Other ID: " << strBoxSvrID << "\n";
272  return false;
273  }
274 
275  OTIdentifier theHash;
276  if (hash == nullptr) hash = &theHash;
277 
278  bool success = box.SaveInbox(hash);
279 
280  if (success) SetInboxHash(*hash);
281 
282  return success;
283 }
284 
285 // hash is optional, the account will update its internal copy of the hash
286 // anyway. If you pass the identifier in, the hash is recorded there.
288 {
289  if (!IsSameAccount(box)) {
290  OTString strAcctID(GetRealAccountID());
291  OTString strServerID(GetRealServerID());
292  OTString strBoxAcctID(box.GetRealAccountID());
293  OTString strBoxSvrID(box.GetRealServerID());
294  otErr << "OTAccount::SaveOutbox: ERROR: The ledger passed in, isn't "
295  "even for this account!\n"
296  " Acct ID: " << strAcctID << "\n Other ID: " << strBoxAcctID
297  << "\n Server ID: " << strServerID
298  << "\n Other ID: " << strBoxSvrID << "\n";
299  return false;
300  }
301 
302  OTIdentifier theHash;
303  if (hash == nullptr) hash = &theHash;
304 
305  bool success = box.SaveOutbox(hash);
306 
307  if (success) SetOutboxHash(*hash);
308 
309  return success;
310 }
311 
313 {
314  inboxHash_ = input;
315 }
316 
318 {
319  output.Release();
320 
321  if (!inboxHash_.IsEmpty()) {
322  output = inboxHash_;
323  return true;
324  }
325  else if (!GetUserID().IsEmpty() && !GetRealAccountID().IsEmpty() &&
326  !GetRealServerID().IsEmpty()) {
328 
329  if (inbox.LoadInbox() && inbox.CalculateInboxHash(output)) {
330  SetInboxHash(output);
331  return true;
332  }
333  }
334 
335  return false;
336 }
337 
339 {
340  outboxHash_ = input;
341 }
342 
344 {
345  output.Release();
346 
347  if (!outboxHash_.IsEmpty()) {
348  output = outboxHash_;
349  return true;
350  }
351  else if (!GetUserID().IsEmpty() && !GetRealAccountID().IsEmpty() &&
352  !GetRealServerID().IsEmpty()) {
354 
355  if (outbox.LoadOutbox() && outbox.CalculateOutboxHash(output)) {
356  SetOutboxHash(output);
357  return true;
358  }
359  }
360 
361  return false;
362 }
363 
364 // TODO: add an override so that OTAccount, when it loads up, it performs the
365 // check to see the ServerID, look at the Server Contract and make sure the
366 // server hashes match.
367 //
368 // TODO: override "Verify". Have some way to verify a specific Nym to a specific
369 // account.
370 //
371 // Overriding this so I can set the filename automatically inside based on ID.
373 {
374  OTString id;
375  GetIdentifier(id);
376  return OTContract::LoadContract(OTFolders::Account().Get(), id.Get());
377 }
378 
380 {
381  OTString id;
382  GetIdentifier(id);
383  return SaveContract(OTFolders::Account().Get(), id.Get());
384 }
385 
386 // Debit a certain amount from the account (presumably the same amount is being
387 // credited somewhere else)
388 bool OTAccount::Debit(const int64_t& amount)
389 {
390  int64_t oldBalance = atol(balanceAmount_.Get());
391  // The MINUS here is the big difference between Debit and Credit
392  int64_t newBalance = oldBalance - amount;
393 
394  // This is where issuer accounts get a pass. They just go negative.
395  //
396  // IF the new balance is less than zero...
397  // AND it's a normal account... (not an issuer)
398  // AND the new balance is even less than the old balance...
399  // THEN FAIL. The "new less than old" requirement is recent,
400  if (newBalance < 0 && !IsAllowedToGoNegative() && newBalance < oldBalance) {
401  return false;
402  }
403  // and it means that we now allow <0 debits on normal accounts,
404  // AS LONG AS the result is a HIGHER BALANCE :-)
405  else {
406  balanceAmount_.Format("%lld", newBalance);
407  time64_t t = OTTimeGetCurrentTime(); // Today, now.
408  balanceDate_.Format("%d", t);
409  return true;
410  }
411 }
412 
413 // Credit a certain amount to the account (presumably the same amount is being
414 // debited somewhere else)
415 bool OTAccount::Credit(const int64_t& amount)
416 {
417  int64_t oldBalance = atol(balanceAmount_.Get());
418  // The PLUS here is the big difference between Debit and Credit.
419  int64_t newBalance = oldBalance + amount;
420 
421  // If the balance gets too big, it may flip to negative due to us using
422  // int64_t int32_t.
423  // We'll maybe explicitly check that it's not negative in order to prevent
424  // that. TODO.
425  // if (newBalance > 0 || (OTAccount::simple != acctType_))
426  // {
427  // balanceAmount_.Format("%lld", newBalance);
428  // return true;
429  // }
430 
431  // This is where issuer accounts get a pass. They just go negative.
432  // IF the new balance is less than zero...
433  // AND it's a normal account... (not an issuer)
434  // AND the new balance is even less than the old balance...
435  // THEN FAIL. The "new less than old" requirement is recent,
436  if (newBalance < 0 && !IsAllowedToGoNegative() && newBalance < oldBalance) {
437  return false;
438  }
439  // and it means that we now allow <0 credits on normal accounts,
440  // AS LONG AS the result is a HIGHER BALANCE :-)
441  else {
442  balanceAmount_.Format("%lld", newBalance);
443  time64_t t = OTTimeGetCurrentTime(); // Today, now.
444  balanceDate_.Format("%d", t);
445  return true;
446  }
447 }
448 
450 {
451  return acctAssetTypeId_;
452 }
453 
455 {
456  m_strContractType = "ACCOUNT";
458 }
459 
460 // Verify Contract ID first, THEN Verify Owner.
461 // Because we use the ID in this function, so make sure that it is verified
462 // before calling this.
463 bool OTAccount::VerifyOwner(const OTPseudonym& candidate) const
464 {
465  OTIdentifier ID_CANDIDATE;
466  // ID_CANDIDATE now contains the ID of the Nym we're testing.
467  candidate.GetIdentifier(ID_CANDIDATE);
468  return m_AcctUserID == ID_CANDIDATE;
469 }
470 
471 // TODO: when entities and roles are added, probably more will go here.
472 bool OTAccount::VerifyOwnerByID(const OTIdentifier& nymId) const
473 {
474  return nymId == m_AcctUserID;
475 }
476 
477 // Let's say you don't have or know the UserID, and you just want to load the
478 // damn thing up.
479 // Then call this function. It will set userID and server ID for you.
481  const OTIdentifier& serverId)
482 {
483  bool folderAlreadyExist = false;
484  bool folderIsNew = false;
485 
486  OTString strDataFolder = "";
487  OTString strAccountPath = "";
488  if (!OTDataFolder::Get(strDataFolder)) {
489  OT_FAIL;
490  }
491  if (!OTPaths::AppendFolder(strAccountPath, strDataFolder,
492  OTFolders::Account())) {
493  OT_FAIL;
494  }
495 
496  if (!OTPaths::ConfirmCreateFolder(strAccountPath, folderAlreadyExist,
497  folderIsNew)) {
498  otErr << "Unable to find or create accounts folder: "
499  << OTFolders::Account() << "\n";
500  return nullptr;
501  }
502 
503  OTAccount* account = new OTAccount();
504  OT_ASSERT(account != nullptr);
505 
506  account->SetRealAccountID(accountId);
507  account->SetRealServerID(serverId);
508 
509  OTString strAcctID(accountId);
510 
511  account->m_strFoldername = OTFolders::Account().Get();
512  account->m_strFilename = strAcctID.Get();
513 
514  if (!OTDB::Exists(account->m_strFoldername.Get(),
515  account->m_strFilename.Get())) {
516  otInfo << "OTAccount::LoadExistingAccount: File does not exist: "
517  << account->m_strFoldername << OTLog::PathSeparator()
518  << account->m_strFilename << "\n";
519  delete account;
520  return nullptr;
521  }
522 
523  if (account->LoadContract() && account->VerifyContractID()) {
524  return account;
525  }
526 
527  delete account;
528  return nullptr;
529 }
530 
532  const OTIdentifier& serverId,
533  const OTPseudonym& serverNym,
534  const OTMessage& message,
535  OTAccount::AccountType acctType,
536  int64_t stashTransNum)
537 {
538  OTAccount* account = new OTAccount(userId, serverId);
539 
540  if (account) {
541  // This is only for stash accounts.
542  if (account->GenerateNewAccount(serverNym, message, acctType,
543  stashTransNum)) {
544  return account;
545  }
546 
547  delete account;
548  account = nullptr;
549  }
550 
551  return nullptr;
552 }
553 
554 /*
555  Just make sure message has these members populated:
556 message.m_strNymID;
557 message.m_strAssetID;
558 message.m_strServerID;
559  */
561  const OTMessage& message,
562  OTAccount::AccountType acctType,
563  int64_t stashTransNum)
564 {
565  // First we generate a secure random number into a binary object...
566  OTPayload payload;
567  // TODO: hardcoding. Plus: is 100 bytes of random a little much here?
568  if (!payload.Randomize(100)) {
569  otErr << __FUNCTION__ << ": Failed trying to acquire random numbers.\n";
570  return false;
571  }
572 
573  // Next we calculate that binary object into a message digest (an
574  // OTIdentifier).
575  OTIdentifier newID;
576  if (!newID.CalculateDigest(payload)) {
577  otErr << __FUNCTION__ << ": Error generating new account ID.\n";
578  return false;
579  }
580 
581  // Next we get that digest (which is a binary hash number)
582  // and extract a human-readable standard string format of that hash,
583  // into an OTString.
584  OTString strID(newID);
585 
586  // Set the account number based on what we just generated.
587  SetRealAccountID(newID);
588  // Might as well set them both. (Safe here to do so, for once.)
589  SetPurportedAccountID(newID);
590  // So it's not blank. The user can always change it.
591  m_strName.Set(strID);
592 
593  // Next we create the full path filename for the account using the ID.
595  m_strFilename = strID.Get();
596 
597  // Then we try to load it, in order to make sure that it doesn't already
598  // exist.
600  otErr << __FUNCTION__ << ": Account already exists: " << m_strFilename
601  << "\n";
602  return false;
603  }
604 
605  // Set up the various important starting values of the account.
606  // Account type defaults to OTAccount::simple.
607  // But there are also issuer accts.
608  acctType_ = acctType;
609 
610  // basket, basketsub, mint, voucher, and stash
611  // accounts are all "owned" by the server.
612  if (IsInternalServerAcct()) {
613  server.GetIdentifier(m_AcctUserID);
614  }
615  else {
617  }
618 
620 
621  otLog3 << __FUNCTION__ << ": Creating new account, type:\n"
622  << message.m_strAssetID << "\n";
623 
624  OTIdentifier serverId(message.m_strServerID);
625  // TODO: this assumes the serverID on the message
626  // is correct. It's vetted, but still...
627  SetRealServerID(serverId);
628  SetPurportedServerID(serverId);
629 
630  time64_t t = OTTimeGetCurrentTime(); // Today, now.
631  balanceDate_.Format("%d", t);
632 
633  balanceAmount_.Set("0");
634 
635  if (IsStashAcct()) {
636  OT_ASSERT_MSG(stashTransNum > 0, "You created a stash account, but "
637  "with a zero-or-negative transaction "
638  "number for its cron item.");
639  stashTransNum_ = stashTransNum;
640  }
641 
642  // Sign the Account (so we know that we did)... Otherwise someone could put
643  // a fake
644  // account file on the server if the code wasn't designed to verify the
645  // signature on the
646  // account.
647  SignContract(server);
648  SaveContract();
649 
650  // Save the Account to storage (based on its ID.)
651  SaveAccount();
652 
653  // Don't know why I had this here. Putting SaveAccount() instead.
654  // OTString strFilename(m_strFilename);
655  // SaveContract(strFilename.Get()); // Saves the account to a specific
656  // filename
657 
658  // No need to create the inbox and outbox ledgers...they will be created
659  // automatically if they do not exist when they are needed.
660 
661  return true;
662 }
663 
664 int64_t OTAccount::GetBalance() const
665 {
666  if (balanceAmount_.Exists()) {
667  return atol(balanceAmount_.Get());
668  }
669  return 0;
670 }
671 
673  const OTString& acctTypeString)
674 {
676 
677  if (acctTypeString.Compare("simple"))
678  acctType = OTAccount::simple;
679  else if (acctTypeString.Compare("issuer"))
680  acctType = OTAccount::issuer;
681  else if (acctTypeString.Compare("basket"))
682  acctType = OTAccount::basket;
683  else if (acctTypeString.Compare("basketsub"))
684  acctType = OTAccount::basketsub;
685  else if (acctTypeString.Compare("mint"))
686  acctType = OTAccount::mint;
687  else if (acctTypeString.Compare("voucher"))
688  acctType = OTAccount::voucher;
689  else if (acctTypeString.Compare("stash"))
690  acctType = OTAccount::stash;
691  else
692  otErr << "Error: Unknown account type: " << acctTypeString << "\n";
693 
694  return acctType;
695 }
696 
698  OTString& acctType)
699 {
700  switch (type) {
701  case OTAccount::simple:
702  acctType.Set("simple");
703  break;
704  case OTAccount::issuer:
705  acctType.Set("issuer");
706  break;
707  case OTAccount::basket:
708  acctType.Set("basket");
709  break;
711  acctType.Set("basketsub");
712  break;
713  case OTAccount::mint:
714  acctType.Set("mint");
715  break;
716  case OTAccount::voucher:
717  acctType.Set("voucher");
718  break;
719  case OTAccount::stash:
720  acctType.Set("stash");
721  break;
722  default:
723  acctType.Set("err_acct");
724  break;
725  }
726 }
727 
729 {
730  OTString strAccountID(GetPurportedAccountID());
731  OTString strServerID(GetPurportedServerID());
732  OTString strUserID(GetUserID());
733  OTString strAssetTypeID(acctAssetTypeId_);
734 
735  OTString acctType;
737 
738  contents.Concatenate(" Asset Account (%s) Name: %s\n"
739  " Last retrieved Balance: %s on date: %s\n"
740  " accountID: %s\n"
741  " userID: %s\n"
742  " serverID: %s\n"
743  " assetTypeID: %s\n"
744  "\n",
745  acctType.Get(), m_strName.Get(), balanceAmount_.Get(),
746  balanceDate_.Get(), strAccountID.Get(),
747  strUserID.Get(), strServerID.Get(),
748  strAssetTypeID.Get());
749 
750  return true;
751 }
752 
754 {
755  OTString strAccountID(GetPurportedAccountID());
756  OTString strServerID(GetPurportedServerID());
757  OTString strUserID(GetUserID());
758  OTString strAssetTypeID(acctAssetTypeId_);
759 
760  OTString acctType;
762 
763  OTASCIIArmor ascName;
764  // name is in the clear in memory, and base64 in storage.
765  if (m_strName.Exists()) {
766  ascName.SetString(m_strName, false); // linebreaks == false
767  }
768 
769  contents.Concatenate(
770  "<!-- Last retrieved balance: %s on date: %s -->\n"
771  "<!-- Account type: %s --><assetAccount name=\"%s\"\n"
772  " accountID=\"%s\"\n"
773  " userID=\"%s\"\n"
774  " serverID=\"%s\" />\n"
775  "<!-- assetTypeID: %s -->\n\n",
776  balanceAmount_.Get(), balanceDate_.Get(), acctType.Get(),
777  m_strName.Exists() ? ascName.Get() : "", strAccountID.Get(),
778  strUserID.Get(), strServerID.Get(), strAssetTypeID.Get());
779  return true;
780 }
781 
782 bool OTAccount::SaveContractWallet(std::ofstream& ofs) const
783 {
784  OTString strOutput;
785 
786  if (SaveContractWallet(strOutput)) {
787  ofs << strOutput;
788  return true;
789  }
790  return false;
791 }
792 
793 // Most contracts do not override this function...
794 // But OTAccount does, because IF THE SIGNER has chosen to SIGN the account
795 // based on the current balances, then we need to update the m_xmlUnsigned
796 // member with the current balances and other updated information before the
797 // signing occurs. (Presumably this is the whole reason why the account is
798 // being re-signed.)
799 //
800 // Normally, in other OTContract and derived classes, m_xmlUnsigned is read
801 // from the file and then kept read-only, since contracts do not normally
802 // change. But as accounts change in balance, they must be re-signed to keep the
803 // signatures valid.
805 {
806  OTString strAssetTYPEID(acctAssetTypeId_);
807 
808  OTString ACCOUNT_ID(GetPurportedAccountID());
809  OTString SERVER_ID(GetPurportedServerID());
810  OTString USER_ID(GetUserID());
811 
812  OTString acctType;
814 
815  // I release this because I'm about to repopulate it.
817 
818  m_xmlUnsigned.Concatenate("<?xml version=\"%s\"?>\n\n", "1.0");
819 
820  m_xmlUnsigned.Concatenate("<assetAccount\n version=\"%s\"\n type=\"%s\"\n "
821  "accountID=\"%s\"\n userID=\"%s\"\n"
822  " serverID=\"%s\"\n assetTypeID=\"%s\" >\n\n",
823  m_strVersion.Get(), acctType.Get(),
824  ACCOUNT_ID.Get(), USER_ID.Get(), SERVER_ID.Get(),
825  strAssetTYPEID.Get());
826  if (IsStashAcct()) {
827  m_xmlUnsigned.Concatenate("<stashinfo cronItemNum=\"%lld\"/>\n\n",
829  }
830  if (!inboxHash_.IsEmpty()) {
831  OTString strHash(inboxHash_);
832  m_xmlUnsigned.Concatenate("<inboxHash value=\"%s\"/>\n\n",
833  strHash.Get());
834  }
835  if (!outboxHash_.IsEmpty()) {
836  OTString strHash(outboxHash_);
837  m_xmlUnsigned.Concatenate("<outboxHash value=\"%s\"/>\n\n",
838  strHash.Get());
839  }
840 
841  m_xmlUnsigned.Concatenate("<balance date=\"%s\" amount=\"%s\"/>\n\n",
843 
844  if (markForDeletion_) {
846  "<MARKED_FOR_DELETION>\n"
847  "%s</MARKED_FOR_DELETION>\n\n",
848  "THIS ACCOUNT HAS BEEN MARKED FOR DELETION AT ITS OWN REQUEST");
849  }
850  m_xmlUnsigned.Concatenate("</assetAccount>\n");
851 }
852 
853 // return -1 if error, 0 if nothing, and 1 if the node was processed.
855 {
856  int32_t retval = 0;
857 
858  OTString strNodeName(xml->getNodeName());
859 
860  // Here we call the parent class first.
861  // If the node is found there, or there is some error,
862  // then we just return either way. But if it comes back
863  // as '0', then nothing happened, and we'll continue executing.
864  //
865  // -- Note you can choose not to call the parent if
866  // you don't want to use any of those xml tags.
867  // As I do below, in the case of OTAccount.
868  // if (retval = OTTransactionType::ProcessXMLNode(xml))
869  // return retval;
870 
871  if (strNodeName.Compare("assetAccount")) {
872  OTString acctType;
873 
874  m_strVersion = xml->getAttributeValue("version");
875  acctType = xml->getAttributeValue("type");
876 
877  if (!acctType.Exists()) {
878  otErr << "OTAccount::ProcessXMLNode: Failed: Empty assetAccount "
879  "'type' attribute.\n";
880  return -1;
881  }
882 
884 
886  otErr << "OTAccount::ProcessXMLNode: Failed: assetAccount 'type' "
887  "attribute contains unknown value.\n";
888  return -1;
889  }
890 
891  OTString strAcctAssetType = xml->getAttributeValue("assetTypeID");
892 
893  if (strAcctAssetType.Exists()) {
894  acctAssetTypeId_.SetString(strAcctAssetType);
895  }
896  OTString strAccountID(xml->getAttributeValue("accountID"));
897  OTString strServerID(xml->getAttributeValue("serverID"));
898  OTString strAcctUserID(xml->getAttributeValue("userID"));
899 
900  OTIdentifier ACCOUNT_ID(strAccountID);
901  OTIdentifier SERVER_ID(strServerID);
902  OTIdentifier USER_ID(strAcctUserID);
903 
904  SetPurportedAccountID(ACCOUNT_ID);
905  SetPurportedServerID(SERVER_ID);
906  SetUserID(USER_ID);
907 
908  OTString strAssetTypeID(acctAssetTypeId_);
909  otLog3 << "\n\nAccount Type: " << acctType
910  << "\nAccountID: " << strAccountID
911  << "\nUserID: " << strAcctUserID
912  << "\n"
913  "AssetTypeID: " << strAssetTypeID
914  << "\nServerID: " << strServerID << "\n";
915 
916  retval = 1;
917  }
918  else if (strNodeName.Compare("inboxHash")) {
919 
920  OTString strHash = xml->getAttributeValue("value");
921  if (strHash.Exists()) {
922  inboxHash_.SetString(strHash);
923  }
924  otLog3 << "Account inboxHash: " << strHash << "\n";
925 
926  retval = 1;
927  }
928  else if (strNodeName.Compare("outboxHash")) {
929 
930  OTString strHash = xml->getAttributeValue("value");
931  if (strHash.Exists()) {
932  outboxHash_.SetString(strHash);
933  }
934  otLog3 << "Account outboxHash: " << strHash << "\n";
935 
936  retval = 1;
937  }
938  else if (strNodeName.Compare("MARKED_FOR_DELETION")) {
939  markForDeletion_ = true;
940  otLog3 << "This asset account has been MARKED_FOR_DELETION (at some "
941  "point prior.)\n";
942 
943  retval = 1;
944  }
945  else if (strNodeName.Compare("balance")) {
946  balanceDate_ = xml->getAttributeValue("date");
947  balanceAmount_ = xml->getAttributeValue("amount");
948 
949  // I convert to integer / int64_t and back to string.
950  // (Just an easy way to keep the data clean.)
951 
952  int32_t date = atoi(balanceDate_.Get());
953  int64_t amount = atol(balanceAmount_.Get());
954 
955  balanceDate_.Format("%d", date);
956  balanceAmount_.Format("%lld", amount);
957 
958  otLog3 << "\nBALANCE -- " << balanceAmount_ << "\nDATE -- "
959  << balanceDate_ << "\n";
960 
961  retval = 1;
962  }
963  else if (strNodeName.Compare("stashinfo")) {
964  if (!IsStashAcct()) {
965  otErr << "OTAccount::ProcessXMLNode: Error: Encountered stashinfo "
966  "tag while loading NON-STASH account. \n";
967  return -1;
968  }
969 
970  int64_t lTransNum = 0;
971  OTString strStashTransNum = xml->getAttributeValue("cronItemNum");
972  if (!strStashTransNum.Exists() ||
973  ((lTransNum = atol(strStashTransNum.Get())) <= 0)) {
974  stashTransNum_ = 0;
975  otErr << "OTAccount::ProcessXMLNode: Error: Bad transaction number "
976  "for supposed corresponding cron item: " << lTransNum
977  << " \n";
978  return -1;
979  }
980  else {
981  stashTransNum_ = lTransNum;
982  }
983 
984  otLog3 << "\nSTASH INFO: CronItemNum -- " << stashTransNum_
985  << "\n";
986 
987  retval = 1;
988  }
989 
990  return retval;
991 }
992 
994 {
995  switch (acctType_) {
996  case OTAccount::simple:
997  case OTAccount::issuer:
998  return false;
999  case OTAccount::basket:
1000  case OTAccount::basketsub:
1001  case OTAccount::mint:
1002  case OTAccount::voucher:
1003  case OTAccount::stash:
1004  return true;
1005  default:
1006  otErr << "OTAccount::IsInternalServerAcct: Unknown account type.\n";
1007  return false;
1008  }
1009  return false;
1010 }
1011 
1013 {
1014  switch (acctType_) {
1015  case OTAccount::simple:
1016  case OTAccount::issuer:
1017  return true;
1018  case OTAccount::basket:
1019  case OTAccount::basketsub:
1020  case OTAccount::mint:
1021  case OTAccount::voucher:
1022  case OTAccount::stash:
1023  return false;
1024  default:
1025  otErr << "OTAccount::IsOwnedByUser: Unknown account type.\n";
1026  return false;
1027  }
1028  return false;
1029 }
1030 
1032 {
1033  return false;
1034 }
1035 
1037 {
1038  return OTAccount::issuer == acctType_;
1039 }
1040 
1042 {
1043  switch (acctType_) {
1044  // issuer acct controlled by a user
1045  case OTAccount::issuer:
1046  // basket issuer acct controlled by the server (for a basket currency)
1047  case OTAccount::basket:
1048  return true;
1049  // user asset acct
1050  case OTAccount::simple:
1051  // internal server acct for storing reserves for basket sub currencies
1052  case OTAccount::basketsub:
1053  // internal server acct for storing reserves for cash withdrawals
1054  case OTAccount::mint:
1055  // internal server acct for storing reserves for
1056  // vouchers (like cashier's cheques)
1057  case OTAccount::voucher:
1058  // internal server acct for storing reserves for
1059  // smart contract stashes. (Money stashed IN the contract.)
1060  case OTAccount::stash:
1061  return false;
1062  default:
1063  otErr << "OTAccount::IsAllowedToGoNegative: Unknown account type.\n";
1064  return false;
1065  }
1066  return false;
1067 }
1068 
1070 {
1073  inboxHash_.Release();
1074  outboxHash_.Release();
1075 }
1076 
1078 {
1079  Release_Account();
1081 }
1082 
1083 } // namespace opentxs
virtual EXPORT bool LoadContract()
Definition: OTAccount.cpp:372
virtual void UpdateContents()
Definition: OTAccount.cpp:804
EXPORT void SetInboxHash(const OTIdentifier &input)
Definition: OTAccount.cpp:312
EXPORT void Release_Account()
Definition: OTAccount.cpp:1069
virtual EXPORT void Release()
Definition: OTAccount.cpp:1077
EXPORT void InitAccount()
Definition: OTAccount.cpp:454
EXPORT bool CalculateDigest(const OTData &dataInput)
virtual EXPORT bool DisplayStatistics(OTString &contents) const
Definition: OTAccount.cpp:728
EXPORT void GetIdentifier(OTIdentifier &theIdentifier) const
EXPORT bool SaveOutbox(OTIdentifier *pOutboxHash=nullptr)
Definition: OTLedger.cpp:881
int64_t stashTransNum_
Definition: OTAccount.hpp:293
EXPORT const OTIdentifier & GetAssetTypeID() const
Definition: OTAccount.cpp:449
EXPORT bool SaveOutbox(OTLedger &box, OTIdentifier *nash=nullptr)
Definition: OTAccount.cpp:287
EXPORT int64_t GetBalance() const
Definition: OTAccount.cpp:664
EXPORT bool VerifyOwnerByID(const OTIdentifier &nymId) const
Definition: OTAccount.cpp:472
EXPORT bool SaveContract()
OTString balanceDate_
Definition: OTAccount.hpp:289
static EXPORT OTAccount * GenerateNewAccount(const OTIdentifier &userId, const OTIdentifier &serverId, const OTPseudonym &serverNym, const OTMessage &message, AccountType acctType=simple, int64_t stashTransNum=0)
Definition: OTAccount.cpp:531
static EXPORT const char * PathSeparator()
Definition: OTLog.cpp:408
EXPORT OTLedger * LoadOutbox(OTPseudonym &nym) const
Definition: OTAccount.cpp:242
EXPORT bool LoadInbox()
Definition: OTLedger.cpp:463
EXPORT void SetOutboxHash(const OTIdentifier &input)
Definition: OTAccount.cpp:338
virtual EXPORT ~OTAccount()
Definition: OTAccount.cpp:213
bool IsSameAccount(const OTTransactionType &rhs) const
void SetRealAccountID(const OTIdentifier &theID)
EXPORT bool LoadOutbox()
Definition: OTLedger.cpp:477
OTString m_strAssetID
Definition: OTMessage.hpp:203
OTLOG_IMPORT OTLogStream otLog3
EXPORT bool IsInternalServerAcct() const
Definition: OTAccount.cpp:993
EXPORT bool IsStashAcct() const
Definition: OTAccount.hpp:205
EXPORT bool GetInboxHash(OTIdentifier &output)
Definition: OTAccount.cpp:317
EXPORT void Concatenate(const char *arg,...)
Definition: OTString.cpp:1334
void TranslateAccountTypeToString(OTAccount::AccountType type, OTString &acctType)
Definition: OTAccount.cpp:697
int64_t time64_t
Definition: Common.hpp:209
EXPORT bool CalculateOutboxHash(OTIdentifier &theOutput)
Definition: OTLedger.cpp:780
void SetRealServerID(const OTIdentifier &theID)
EXPORT bool IsIssuer() const
Definition: OTAccount.cpp:1036
static EXPORT char const * _GetTypeString(AccountType accountType)
Definition: OTAccount.cpp:218
OTIdentifier inboxHash_
Definition: OTAccount.hpp:299
EXPORT bool Exists() const
Definition: OTString.cpp:1035
EXPORT bool SetString(const OTString &theData, bool bLineBreaks=true)
EXPORT void SetString(const char *szString)
EXPORT void Format(const char *fmt,...)
Definition: OTString.cpp:1319
static EXPORT bool AppendFolder(OTString &out_strPath, const OTString &strBasePath, const OTString &strFolderName)
Definition: OTPaths.cpp:1212
const OTIdentifier & GetRealAccountID() const
EXPORT bool Compare(const char *compare) const
Definition: OTString.cpp:1102
virtual EXPORT bool SaveContractWallet(std::ofstream &ofs) const
Definition: OTAccount.cpp:782
EXPORT bool VerifyOwner(const OTPseudonym &candidate) const
Definition: OTAccount.cpp:463
const OTIdentifier & GetPurportedServerID() const
EXPORT void Set(const char *data, uint32_t enforcedMaxLength=0)
Definition: OTString.cpp:1055
time64_t OTTimeGetCurrentTime()
Definition: Common.hpp:211
OTAccount::AccountType TranslateAccountTypeStringToEnum(const OTString &acctType)
Definition: OTAccount.cpp:672
virtual int32_t ProcessXMLNode(irr::io::IrrXMLReader *&xml)
Definition: OTAccount.cpp:854
char const *const __TypeStrings[]
Definition: OTAccount.cpp:161
AccountType acctType_
Definition: OTAccount.hpp:286
#define OT_ASSERT(x)
Definition: Assert.hpp:150
EXPORT OTLedger * LoadInbox(OTPseudonym &nym) const
Definition: OTAccount.cpp:225
OTString m_strContractType
Definition: OTContract.hpp:178
#define OT_ASSERT_MSG(x, s)
Definition: Assert.hpp:155
OTLOG_IMPORT OTLogStream otInfo
virtual EXPORT bool LoadContract()
virtual EXPORT void GetIdentifier(OTIdentifier &theIdentifier) const
Definition: OTContract.cpp:317
#define OT_FAIL
Definition: Assert.hpp:139
EXPORT bool IsOwnedByEntity() const
Definition: OTAccount.cpp:1031
OTString m_strServerID
Definition: OTMessage.hpp:191
OTStringXML m_xmlUnsigned
Definition: OTContract.hpp:174
static EXPORT bool ConfirmCreateFolder(const OTString &strExactPath, bool &out_Exists, bool &out_IsNew)
Definition: OTPaths.cpp:921
EXPORT bool GetOutboxHash(OTIdentifier &output)
Definition: OTAccount.cpp:343
EXPORT const char * Get() const
Definition: OTString.cpp:1045
void SetUserID(const OTIdentifier &theID)
virtual EXPORT bool SignContract(const OTPseudonym &theNym, const OTPasswordData *pPWData=nullptr)
Definition: OTContract.cpp:484
EXPORT bool IsAllowedToGoNegative() const
Definition: OTAccount.cpp:1041
EXPORT bool SaveInbox(OTLedger &box, OTIdentifier *hash=nullptr)
Definition: OTAccount.cpp:260
OTLOG_IMPORT OTLogStream otErr
const OTIdentifier & GetPurportedAccountID() const
void SetPurportedServerID(const OTIdentifier &theID)
OTString balanceAmount_
Definition: OTAccount.hpp:290
virtual EXPORT bool VerifyContractID() const
EXPORT bool Exists(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:584
EXPORT bool IsEmpty() const
Definition: OTData.cpp:291
const OTIdentifier & GetUserID() const
virtual EXPORT void Release()
Definition: OTData.cpp:257
EXPORT bool SaveAccount()
Definition: OTAccount.cpp:379
EXPORT bool Randomize(uint32_t size)
Definition: OTData.cpp:310
static EXPORT const OTString & Account()
Definition: OTFolders.cpp:295
EXPORT bool CalculateInboxHash(OTIdentifier &theOutput)
Definition: OTLedger.cpp:770
EXPORT bool Credit(const int64_t &amount)
Definition: OTAccount.cpp:415
static EXPORT OTAccount * LoadExistingAccount(const OTIdentifier &accountId, const OTIdentifier &serverId)
Definition: OTAccount.cpp:480
EXPORT bool Debit(const int64_t &amount)
Definition: OTAccount.cpp:388
void SetPurportedAccountID(const OTIdentifier &theID)
virtual EXPORT void Release()
Definition: OTString.cpp:765
static EXPORT OTString Get()
const OTIdentifier & GetRealServerID() const
OTIdentifier acctAssetTypeId_
Definition: OTAccount.hpp:288
EXPORT bool IsOwnedByUser() const
Definition: OTAccount.cpp:1012
OTString m_strFoldername
Definition: OTContract.hpp:169
EXPORT bool SaveInbox(OTIdentifier *pInboxHash=nullptr)
Definition: OTLedger.cpp:836
OTIdentifier outboxHash_
Definition: OTAccount.hpp:302