Open-Transactions  0.93.0-ge03d287
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
OTTransaction.cpp
Go to the documentation of this file.
1 /************************************************************
2  *
3  * OTTransaction.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 
137 #include "OTTransaction.hpp"
138 #include "OTCheque.hpp"
139 #include "util/OTFolders.hpp"
140 #include "OTLedger.hpp"
141 #include "OTLog.hpp"
142 #include "OTMessage.hpp"
143 #include "OTPseudonym.hpp"
144 #include "OTStorage.hpp"
145 
146 #include <irrxml/irrXML.hpp>
147 
148 #include <memory>
149 
150 namespace opentxs
151 {
152 
153 // Used in balance agreement, part of the inbox report.
155 {
157 }
158 
159 void OTTransaction::SetClosingNum(int64_t lClosingNum)
160 {
161  m_lClosingTransactionNo = lClosingNum;
162 }
163 
164 // Make sure this contract checks out. Very high level.
165 // Verifies ID and signature.
166 // I do NOT call VerifyOwner() here, because the server may
167 // wish to verify its signature on this account, even though
168 // the server may not be the actual owner.
169 // So if you wish to VerifyOwner(), then call it.
170 //
171 // This overrides from OTTransactionType::VerifyAccount()
172 //
174 {
175  OTLedger* pParent = const_cast<OTLedger*>(m_pParent);
176 
177  // Make sure that the supposed AcctID matches the one read from the file.
178  //
179  if (!VerifyContractID()) {
180  otErr << __FUNCTION__ << ": Error verifying account ID.\n";
181  return false;
182  }
183  // todo security audit:
184  else if (IsAbbreviated() && (pParent != nullptr) &&
185  !pParent->VerifySignature(theNym)) {
186  otErr << __FUNCTION__ << ": Error verifying signature on parent ledger "
187  "for abbreviated transaction receipt.\n";
188  return false;
189  }
190  else if (!IsAbbreviated() && (false == VerifySignature(theNym))) {
191  otErr << __FUNCTION__ << ": Error verifying signature.\n";
192  return false;
193  }
194 
195  otLog4 << "\nWe now know that...\n"
196  "1) The expected Account ID matches the ID that was found on the "
197  "object.\n"
198  "2) The SIGNATURE VERIFIED on the object.\n\n";
199  return true;
200 }
201 
202 /*
203 // **** MESSAGE TRANSACTIONS ****
204 //
205 --------------------------------------------------------------------------------------
206  processNymbox, // process nymbox transaction // comes from client
207  processInbox, // process inbox transaction // comes from client
208  transfer, // or "spend". This transaction is a request to
209 transfer from one account to another
210  deposit, // this transaction is a deposit (cash or cheque)
211  withdrawal, // this transaction is a withdrawal (cash or voucher)
212  marketOffer, // this transaction is a market offer
213  paymentPlan, // this transaction is a payment plan
214  smartContract, // this transaction is a smart contract
215  cancelCronItem, // this transaction is intended to cancel a market
216 offer or payment plan.
217  exchangeBasket, // this transaction is an exchange in/out of a basket
218 currency.
219  payDividend, // this transaction is a dividend payment (to
220 shareholders.)
221 
222 
223  HarvestOpeningNumber:
224 
225 // processNymbox, // process nymbox transaction // comes from client //
226 HUH?? This message doesn't use a transaction number. That's the whole point of
227 processNymbox is that it doesn't require such a number.
228  processInbox, // process inbox transaction // comes from client
229  transfer, // or "spend". This transaction is a request to transfer
230 from one account to another
231  deposit, // this transaction is a deposit (cash or cheque)
232  withdrawal, // this transaction is a withdrawal (cash or voucher)
233  marketOffer, // this transaction is a market offer
234  paymentPlan, // this transaction is a payment plan
235  smartContract, // this transaction is a smart contract
236  cancelCronItem, // this transaction is intended to cancel a market offer or
237 payment plan.
238  exchangeBasket, // this transaction is an exchange in/out of a basket
239 currency.
240  payDividend, // this transaction is dividend payment (to shareholders.)
241 
242 
243 
244  HarvestClosingNumbers: (The X's means "not needed for closing numbers)
245 
246 // X processNymbox, // process nymbox transaction // comes from client
247 // HUH?? The whole point of processNymbox is that it uses no transaction
248 numbers.
249  X processInbox, // process inbox transaction // comes from client
250  X transfer, // or "spend". This transaction is a request to transfer
251 from one account to another
252  X deposit, // this transaction is a deposit (cash or cheque)
253  X withdrawal, // this transaction is a withdrawal (cash or voucher)
254  X cancelCronItem, // this transaction is intended to cancel a market offer
255 or payment plan.
256  X payDividend, // this transaction is a dividend payment (to
257 shareholders.)
258 
259  // ONLY THESE:
260  marketOffer, // This contains one opening number, and two closing
261 numbers.
262  paymentPlan, // This contains one primary opening number (from the payer)
263 and his closing number,
264  // as well as the opening and closing numbers for the payee. NOTE: Unless the
265 paymentPlan SUCCEEDED in
266  // activating, then the SENDER's numbers are both still good. (Normally even
267 attempting a transaction
268  // will burn the opening number, which IS the case here, for the payer. But the
269 PAYEE only burns his
270  // opening number IF SUCCESS. Thus, even if the message succeeded but the
271 transaction failed, where
272  // normally the opening number is burned, it's still good for the PAYEE (not
273 the payer.) Therefore we
274  // need to make sure, in the case of paymentPlan, that we still claw back the
275 opening number (FOR THE
276  // PAYEE) in the place where we normally would only claw back the closing
277 number.
278  smartContract, // This contains an opening number for each party, and a
279 closing number for each
280  // asset account.
281 
282 
283 
284  exchangeBasket, // this transaction is an exchange in/out of a basket
285 currency.
286 
287 
288 
289  */
290 
291 // Only do this if the message itself failed, meaning this transaction never
292 // even
293 // attempted, and thus this transaction NEVER EVEN HAD A *CHANCE* TO FAIL, and
294 // thus
295 // the opening number never got burned (Normally no point in harvesting a burned
296 // number, now is there?)
297 //
298 // Client-side.
299 //
300 // Returns true/false whether it actually harvested a number.
301 //
303  OTPseudonym& theNym,
304  bool bHarvestingForRetry, // The message was sent, failed somehow, and
305  // is now being re-tried.
306  bool bReplyWasSuccess, // false until positively asserted.
307  bool bReplyWasFailure, // false until positively asserted.
308  bool bTransactionWasSuccess, // false until positively asserted.
309  bool bTransactionWasFailure) // false until positively asserted.
310 {
311  bool bSuccess = false;
312 
313  switch (m_Type) {
314  // Note: the below remarks about "success or fail" are specific to
315  // TRANSACTION success, not message success.
316  // case OTTransaction::processNymbox: // NOTE: why was this here? You
317  // don't need trans#s to process a Nymbox--that's the whole point of a
318  // Nymbox.
319  case OTTransaction::processInbox: // Uses 1 transaction #, the opening
320  // number, and burns it whether
321  // transaction is success-or-fail.
322  case OTTransaction::withdrawal: // Uses 1 transaction #, the opening number,
323  // and burns it whether transaction is
324  // success-or-fail.
325  case OTTransaction::deposit: // Uses 1 transaction #, the opening number,
326  // and burns it whether transaction is
327  // success-or-fail.
328  case OTTransaction::cancelCronItem: // Uses 1 transaction #, the opening
329  // number, and burns it whether
330  // transaction is success-or-fail.
331  case OTTransaction::payDividend: // Uses 1 transaction #, the opening
332  // number, and burns it whether transaction
333  // is success-or-fail.
334 
335  // If the server reply message was unambiguously a FAIL, that means the
336  // opening number is STILL GOOD.
337  // (Because the transaction therefore never even had a chance to run.)
338  //
339  // Note: what if, instead, I don't know whether the transaction itself
340  // failed, because I don't have a reply message?
341  // In that case, I cannot claw back the numbers because I don't know for
342  // sure. But my future transactions WILL fail if
343  // my nymbox hash goes out of sync, so if that transaction DID process,
344  // then I'll find out right away, and I'll be forced
345  // to download the nymbox and box receipts in order to get back into
346  // sync again. And if the transaction did NOT process,
347  // then I'll know it when I don't find it among the receipts. In which
348  // case I can pull the original message from the
349  // outbuffer, using the request number from when it was sent, and then
350  // harvest it from there.
351  //
352  if (bReplyWasFailure) // NOTE: If I'm harvesting for a re-try,
353  {
354  bSuccess = theNym.ClawbackTransactionNumber(
356  GetTransactionNum()); // bSave=false, pSignerNym=nullptr
357  }
358  // Else if the server reply message was unambiguously a SUCCESS, that
359  // means the opening number is DEFINITELY BURNED.
360  // (Why? Because that means the transaction definitely ran--and the
361  // opener is burned success-or-fail, if the transaction runs.)
362  //
363  else if (bReplyWasSuccess) {
364  // The opener is DEFINITELY BAD, so therefore, we're definitely not
365  // going to claw it back!
366  //
367  // bSuccess =
368  // theNym.ClawbackTransactionNumber(GetPurportedServerID(),
369  // GetTransactionNum());
370  // //bSave=false, pSignerNym=nullptr
371  }
372  break;
373 
374  case OTTransaction::transfer: // Uses 1 transaction #, the opening number,
375  // and burns it if failure. But if success,
376  // merely marks it as "used."
377 
378  // If the server reply message was unambiguously a FAIL, that means the
379  // opening number is STILL GOOD.
380  // (Because the transaction therefore never even had a chance to run.)
381  //
382  if (bReplyWasFailure) {
383  bSuccess = theNym.ClawbackTransactionNumber(
385  GetTransactionNum()); // bSave=false, pSignerNym=nullptr
386  }
387  // Else if the server reply message was unambiguously a SUCCESS, that
388  // means the opening number is DEFINITELY NOT HARVESTABLE.
389  // Why? Because that means the transaction definitely ran--and the
390  // opener is marked as "used" on success, and "burned" on
391  // failure--either way, that's bad for harvesting (no point.)
392  //
393  else if (bReplyWasSuccess) {
394  if (bTransactionWasSuccess) {
395  // This means the "transfer" transaction# is STILL MARKED AS
396  // "USED", and will someday be marked as CLOSED.
397  // EITHER WAY, you certainly can't claw that number back now!
398  // (It is still outstanding, though. It's not gone, yet...)
399  // bSuccess =
400  // theNym.ClawbackTransactionNumber(GetPurportedServerID(),
401  // GetTransactionNum());
402  // //bSave=false, pSignerNym=nullptr
403  }
404  else if (bTransactionWasFailure) {
405  // Whereas if the transaction was a failure, that means the
406  // transaction number was DEFINITELY burned.
407  // (No point clawing it back now--it's gone already.)
408  // bSuccess =
409  // theNym.ClawbackTransactionNumber(GetPurportedServerID(),
410  // GetTransactionNum());
411  // //bSave=false, pSignerNym=nullptr
412  }
413  }
414  break;
415 
416  case OTTransaction::marketOffer: // Uses 3 transaction #s, the opening
417  // number and 2 closers. If failure, opener
418  // is burned.
419  // But if success, merely marks it as "used." Closers are also marked
420  // "used" if success,
421  // but if message succeeds while transaction fails, then closers can be
422  // harvested.
423  // If the server reply message was unambiguously a FAIL, that means the
424  // opening number is STILL GOOD.
425  // (Because the transaction therefore never even had a chance to run.)
426  //
427  if (bReplyWasFailure) {
428  bSuccess = theNym.ClawbackTransactionNumber(
430  GetTransactionNum()); // bSave=false, pSignerNym=nullptr
431  }
432  // Else if the server reply message was unambiguously a SUCCESS, that
433  // means the opening number is DEFINITELY NOT HARVESTABLE.
434  // Why? Because that means the transaction definitely ran--and the
435  // opener is marked as "used" on success, and "burned" on
436  // failure--either way, that's bad for harvesting (no point.)
437  //
438  else if (bReplyWasSuccess) {
439  if (bTransactionWasSuccess) {
440  // This means the "marketOffer" transaction# is STILL MARKED AS
441  // "USED", and will someday be marked as CLOSED.
442  // EITHER WAY, you certainly can't claw that number back now!
443  // (It is still outstanding, though. It's not gone, yet...)
444  // bSuccess =
445  // theNym.ClawbackTransactionNumber(GetPurportedServerID(),
446  // GetTransactionNum());
447  // //bSave=false, pSignerNym=nullptr
448  }
449  else if (bTransactionWasFailure) {
450  // Whereas if the transaction was a failure, that means the
451  // transaction number was DEFINITELY burned.
452  // (No point clawing it back now--it's gone already.)
453  // bSuccess =
454  // theNym.ClawbackTransactionNumber(GetPurportedServerID(),
455  // GetTransactionNum());
456  // //bSave=false, pSignerNym=nullptr
457  }
458  }
459 
460  break;
461 
462  case OTTransaction::exchangeBasket: // Uses X transaction #s: the opener,
463  // which is burned success-or-fail, and
464  // Y closers (one for
465  // each account.) Closers are marked "used" if success transaction, but
466  // if message succeeds while
467  // transaction fails, then closers can be harvested.
468  // If the server reply message was unambiguously a FAIL, that means the
469  // opening number is STILL GOOD.
470  // (Because the transaction therefore never even had a chance to run.)
471  //
472  if (bReplyWasFailure) {
473  bSuccess = theNym.ClawbackTransactionNumber(
475  GetTransactionNum()); // bSave=false, pSignerNym=nullptr
476  }
477  // Else if the server reply message was unambiguously a SUCCESS, that
478  // means the opening number is DEFINITELY BURNED.
479  // (Why? Because that means the transaction definitely ran--and the
480  // opener is burned "success-or-fail", if this transaction runs.)
481  //
482  else if (bReplyWasSuccess) {
483  // The opener is DEFINITELY BURNED, so therefore, we're definitely
484  // not going to claw it back!
485  //
486  // bSuccess =
487  // theNym.ClawbackTransactionNumber(GetPurportedServerID(),
488  // GetTransactionNum());
489  // //bSave=false, pSignerNym=nullptr
490  }
491  break;
492 
493  // These aren't AS simple.
494  case OTTransaction::paymentPlan: // Uses 4 transaction #s: the opener
495  // (sender's #), which burned on failure
496  // but kept alive on success,
497  // the sender's closer, which is only marked as "used" upon success, and
498  // the recipient's opening and
499  // closing numbers, which are both only marked as "used" upon success.
500  {
501  // The PAYER's (sender) opening number is burned just from TRYING a
502  // transaction. It's only left
503  // open if the transaction succeeds (but in that case, it's still
504  // marked as "used.") But the
505  // PAYEE's (recipient) opening number isn't marked as "used" UNLESS
506  // the transaction succeeds.
507  //
508  // Basically a failed transaction means the sender's opening number
509  // is burned and gone, but the
510  // recipient's must be clawed back!! Whereas if the message fails
511  // (before transaction even has a
512  // chance to run) then BOTH sender and recipient can claw back their
513  // numbers. The only way to tell
514  // the difference is to look at the message itself (the info isn't
515  // stored here in the transaction.)
516  //
517  // 1.
518  // Therefore we must assume that the CALLER OF THIS FUNCTION knows.
519  // If the message failed, he knows
520  // this, and he SPECIFICALLY called HarvestOpeningNumber() ANYWAY,
521  // to get the opening number back
522  // (when normally he would only recoup the closed numbers--therefore
523  // he MUST know that the message
524  // failed and that the number is thus still good!)
525  //
526  // 2.
527  // WHEREAS if the message SUCCEEDED (followed by transaction FAIL),
528  // then the payer/sender already
529  // used his opening number, whereas the recipient DID NOT! Again,
530  // the caller MUST KNOW THIS ALREADY.
531  // The caller wouldn't call "HarvestOpeningNumber" for a burned
532  // number (of the sender.) Therefore
533  // he must be calling it to recoup the (still issued) opening number
534  // of the RECIPIENT.
535  //
536  // Problems:
537  // 1. What if caller is stupid, and message hasn't actually failed?
538  // What if caller is mistakenly
539  // trying to recoup numbers that are actually burned already?
540  // Well, the opening number is already
541  // marked as "used but still issued" so when I try to claw it
542  // back, that will work (because it
543  // only adds a number BACK after it can confirm that the number
544  // WAS issued to me in the first place,
545  // and in this case, that verification will succeed.)
546  // THEREFORE: need to explicitly pass the message's
547  // success/failure status into the current
548  // function. IF the msg was a failure, the transaction never had
549  // a chance to run and thus the
550  // opening number is still good, and we can claw it back. But if
551  // the message was a SUCCESS, then
552  // the transaction definitely TRIED to run, which means the
553  // opening number is now burned. (IF
554  // the transaction itself failed, that is. Otherwise if it
555  // succeeded, then it's possible, in the
556  // cases of transfer and marketOffer, that the opening number is
557  // STILL "used but issued", until
558  // you finally close out your transferReceipt or the finalReceipt
559  // for your market offer.)
560  //
561  // 2. What if caller is stupid, and he called HarvestOpeningNumber
562  // for the sender, even though the
563  // number was already burned in the original attempt? (Which we
564  // know it was, since the message
565  // itself succeeded.) The sender, of course, has that number on
566  // his "issued" list, so his clawback
567  // will succeed, putting him out of sync.
568  //
569  // 3. What if the recipient is passed into this function? His
570  // "opening number" is not the primary
571  // one, but rather, there are three "closing numbers" on a
572  // payment plan. One for the sender, to
573  // match his normal opening number, and 2 more for the recipient
574  // (an opening and closing number).
575  // Therefore in the case of the recipient, need to grab HIS
576  // opening number, not the sender's.
577  // (Therefore need to know whether Nym is sender or recipient.)
578  // Is that actually true? Or won't
579  // the harvest process be smart enough to figure that out
580  // already? And will it know that the
581  // recipient still needs to harvest HIS opening number, even if
582  // the transaction was attempted,
583  // since the recipient's number wasn't marked as "used" unless
584  // the transaction itself succeeded.
585  // NOTE: CronItem/Agreement/PaymentPlan is definitely smart
586  // enough already to know if the Nym is
587  // the sender or recipient. It will only grab the appropriate
588  // number for the right Nym. But here
589  // in THIS function we still have to be smart enough not to call
590  // it for the SENDER if the transaction
591  // was attempted (because it must be burned already), but TO call
592  // it for the sender if the transaction
593  // was not even attempted (meaning it wasn't burned yet.)
594  // Similarly, this function has to be smart
595  // enough TO call it for the recipient if transaction was
596  // attempted but didn't succeed, since the
597  // recipient's opening number is still good in that case.
598  //
599 
600  const OTIdentifier theNymID(theNym);
601 
602  // Assumption: if theNymID matches GetUserID(), then theNym
603  // must be the SENDER / PAYER!
604  // Else, he must be RECIPIENT / PAYEE, instead!
605  // This assumption is not for proving, since the harvest functions
606  // will verify the Nym's identity
607  // anyway. Instead, this assumption is merely for deciding which
608  // logic to use about which harvest
609  // functions to call.
610  //
611  if (theNymID == GetUserID()) // theNym is SENDER / PAYER
612  {
613  // If the server reply message was unambiguously a FAIL, that
614  // means the opening number is STILL GOOD.
615  // (Because the transaction therefore never even had a chance to
616  // run.)
617  //
618  if (bReplyWasFailure && !bHarvestingForRetry) {
619  bSuccess = theNym.ClawbackTransactionNumber(
621  GetTransactionNum()); // bSave=false, pSignerNym=nullptr
622  }
623  // Else if the server reply message was unambiguously a SUCCESS,
624  // that means the opening number is DEFINITELY
625  // NOT HARVESTABLE. (For the sender, anyway.) Why not? Because
626  // that means the transaction definitely ran--and
627  // the opener is marked as "used" on success, and "burned" on
628  // failure--either way, that's bad for harvesting (no point.)
629  //
630  else if (bReplyWasSuccess) {
631  if (bTransactionWasSuccess) {
632  // This means the "paymentPlan" transaction# is MARKED
633  // AS "USED", and will someday be marked as CLOSED.
634  // EITHER WAY, you certainly can't claw that number back
635  // now! (It is still outstanding, though. It's not gone,
636  // yet...)
637  // bSuccess =
638  // theNym.ClawbackTransactionNumber(GetPurportedServerID(),
639  // GetTransactionNum());
640  // //bSave=false, pSignerNym=nullptr
641  }
642  else if (bTransactionWasFailure) {
643  // Whereas if the transaction was a failure, that means
644  // the transaction number was DEFINITELY burned.
645  // (No point clawing it back now--it's gone already.)
646  // bSuccess =
647  // theNym.ClawbackTransactionNumber(GetPurportedServerID(),
648  // GetTransactionNum());
649  // //bSave=false, pSignerNym=nullptr
650  }
651  }
652  }
653 
654  // theNym is RECIPIENT / PAYEE
655  //
656  // This case is slightly different because above, a successful
657  // message with a failed transaction will burn the
658  // opening number, whereas here, if the message is successful but
659  // the transaction is failed, the recipient's
660  // opening transaction number is STILL GOOD and can be harvested!
661  // TODO: Make sure payment plans drop a NOTICE
662  // to the recipient, so he can harvest his numbers when this happens
663  // (similar to todos I have for smart contracts.)
664  //
665  // The other big difference with the recipient is that he has a
666  // different opening and closing number than the sender
667  // does, so I need to see if I can get those from the transaction,
668  // or if I have to load up the attached cron item
669  // to get that data.
670  //
671  else // theNym is RECIPIENT / PAYEE
672  {
673  // What is this class doing here?
674  // Answer: it's the C++ equivalent of local functions.
675  //
676  class _getRecipientOpeningNum
677  {
678  public:
679  int64_t Run(OTTransaction& theTransaction)
680  {
681  OTItem* pItem =
682  theTransaction.GetItem(OTItem::paymentPlan);
683  if (nullptr != pItem) {
684  // Also load up the Payment Plan from inside the
685  // transaction item.
686  //
687  OTString strPaymentPlan;
688  OTPaymentPlan thePlan;
689  pItem->GetAttachment(strPaymentPlan);
690 
691  if (strPaymentPlan.Exists() &&
692  thePlan.LoadContractFromString(strPaymentPlan))
693  return thePlan.GetRecipientOpeningNum();
694  else
695  otErr << "OTTransaction::HarvestOpeningNumber: "
696  "Error: Unable to load "
697  "paymentPlan object from paymentPlan "
698  "transaction item.\n";
699  }
700  else
701  otErr << "OTTransaction::HarvestOpeningNumber: "
702  "Error: Unable to find "
703  "paymentPlan item in paymentPlan "
704  "transaction.\n";
705  return 0;
706  }
707  }; // class _getRecipientOpeningNum
708 
709  // If the server reply message was unambiguously a FAIL, that
710  // means the opening number is STILL GOOD.
711  // (Because the transaction therefore never even had a chance to
712  // run.)
713  //
714  if (bReplyWasFailure && !bHarvestingForRetry) {
715  _getRecipientOpeningNum getRecipientOpeningNum;
716  const int64_t lRecipientOpeningNum =
717  getRecipientOpeningNum.Run(*this);
718 
719  if (lRecipientOpeningNum > 0)
720  bSuccess = theNym.ClawbackTransactionNumber(
722  lRecipientOpeningNum); // bSave=false,
723  // pSignerNym=nullptr
724  }
725  // Else if the server reply message was unambiguously a SUCCESS,
726  // then the next question is whether the
727  // TRANSACTION INSIDE IT was also a success, or if there's a
728  // "success message / failed transaction" situation
729  // going on here. For the recipient, that's important: in the
730  // first case, his opener is definitely marked as "used
731  // but still outstanding" and CANNOT be harvested. But in the
732  // second case, unlike with the sender, his opener IS
733  // harvestable!
734  // This is because of a peculiarity with payment plans: the
735  // recipient's opening number is not marked as used until
736  // the transaction itself is a success!
737  //
738  else if (bReplyWasSuccess) {
739  if (bTransactionWasSuccess) // The opener is DEFINITELY
740  // marked as "used but still
741  // outstanding" and CANNOT be
742  // harvested.
743  {
744  // This means the "paymentPlan" transaction# is MARKED
745  // AS "USED", and will someday be marked as CLOSED.
746  // EITHER WAY, you certainly can't claw that number back
747  // now! (It is still outstanding, though. It's not gone,
748  // yet...)
749  // bSuccess =
750  // theNym.ClawbackTransactionNumber(GetPurportedServerID(),
751  // RECIPIENTS--OPENING--NUMBER--GOES--HERE);
752  // //bSave=false, pSignerNym=nullptr
753  }
754  else if (bTransactionWasFailure && !bHarvestingForRetry) {
755  // In this case, unlike with the sender, the recipient's
756  // opener IS still harvestable! This is because
757  // of a peculiarity with payment plans: the recipient's
758  // opening number is not marked as used until the
759  // transaction itself is a success! Therefore, if the
760  // transaction was a failure, that means the recipient's
761  // opening number is DEFINITELY STILL GOOD.
762  //
763  _getRecipientOpeningNum getRecipientOpeningNum;
764  const int64_t lRecipientOpeningNum =
765  getRecipientOpeningNum.Run(*this);
766 
767  if (lRecipientOpeningNum > 0)
768  bSuccess = theNym.ClawbackTransactionNumber(
770  lRecipientOpeningNum); // bSave=false,
771  // pSignerNym=nullptr
772  }
773  }
774  }
775  }
776  break;
777 
778  // TODO: Make sure that when a user receives a success notice that a smart
779  // contract has been started up,
780  // that he marks his opener as "burned" instead of as "used." It's gone!
781  // Also: if the user receives a message failure notice (not done yet) then
782  // he can mark his opening #
783  // as "new" again! But if he instead receives a "message success but
784  // transaction failure", (todo: notice)
785  // then he must burn his opening #, as that is what the server has already
786  // done.
787  //
788  // In the case where message and transaction were BOTH success, then the
789  // user's existing setup is already
790  // correct. (The openers AND closers are already marked as "used but still
791  // issued" on the client side, and
792  // the server-side sees things that way already as well.)
793  //
794 
795  case OTTransaction::smartContract: // Uses X transaction #s, with an opener
796  // for each party and a closer for each
797  // asset account.
798  // If the message is rejected by the server, then ALL openers can be
799  // harvested. But if the
800  // message was successful (REGARDLESS of whether the transaction was
801  // successful) then all of
802  // the openers for all of the parties have been burned. The closers,
803  // meanwhile, can be recovered
804  // if the message is a failure, as well as in cases where message
805  // succeeds but transaction failed.
806  // But if transaction succeeded, then the closers CANNOT be recovered.
807  // (Only removed, once you sign
808  // off on the receipt.)
809  {
810 
812 
813  if (nullptr == pItem) {
814  otErr << "OTTransaction::HarvestOpeningNumber: Error: Unable "
815  "to find "
816  "smartContract item in smartContract transaction.\n";
817  }
818  else // Load up the smart contract...
819  {
820  OTString strSmartContract;
821  OTSmartContract theSmartContract(GetPurportedServerID());
822  pItem->GetAttachment(strSmartContract);
823 
824  // If we failed to load the smart contract...
825  if (!strSmartContract.Exists() ||
826  (false ==
827  theSmartContract.LoadContractFromString(
828  strSmartContract))) {
829  otErr << "OTTransaction::HarvestOpeningNumber: Error: "
830  "Unable to load "
831  "smartContract object from smartContract "
832  "transaction item.\n";
833  }
834  else // theSmartContract is ready to go....
835  {
836 
837  // The message reply itself was a failure. This means the
838  // transaction itself never got a chance
839  // to run... which means ALL the opening numbers on that
840  // transaction are STILL GOOD.
841  //
842  if (bReplyWasFailure && !bHarvestingForRetry) {
843  // If I WAS harvesting for a re-try, I'd want to leave
844  // the opening number
845  // on this smart contract
846  theSmartContract.HarvestOpeningNumber(theNym);
847  bSuccess = true;
848  }
849  // Else if the server reply message was unambiguously a
850  // SUCCESS, that means the opening number is DEFINITELY NOT
851  // HARVESTABLE.
852  // Why? Because that means the transaction definitely
853  // ran--and the opener is marked as "used" on SUCCESS, or
854  // "burned" on
855  // FAILURE--either way, that's bad for harvesting (no
856  // point.)
857  //
858  else if (bReplyWasSuccess) {
859  if (bTransactionWasSuccess) {
860  // This means the "smartContract" opening trans# is
861  // MARKED AS "USED", and will someday be marked as
862  // CLOSED.
863  // EITHER WAY, you certainly can't claw that number
864  // back now! (It is still outstanding, though. It's
865  // not gone, yet...)
866  //
867  // theSmartContract.HarvestOpeningNumber(theNym);
868  // bSuccess = true;
869  }
870  else if (bTransactionWasFailure) {
871  // Whereas if the transaction was a failure, that
872  // means the opening trans number was DEFINITELY
873  // burned.
874  // (No point clawing it back now--it's gone
875  // already.)
876  //
877  // theSmartContract.HarvestOpeningNumber(theNym);
878  // bSuccess = true;
879  }
880  } // else if (bReplyWasSuccess)
881 
882  } // else (smart contract loaded successfully)
883  } // pItem was found.
884  }
885  break;
886 
887  default:
888  break;
889  }
890 
891  return bSuccess;
892 }
893 
894 // Normally do this if your transaction ran--and failed--so you can get most of
895 // your transaction numbers back. (The opening number is usually already gone,
896 // but any others are still salvageable.)
897 //
899  OTPseudonym& theNym,
900  bool bHarvestingForRetry, // false until positively asserted.
901  bool bReplyWasSuccess, // false until positively asserted.
902  bool bReplyWasFailure, // false until positively asserted.
903  bool bTransactionWasSuccess, // false until positively asserted.
904  bool bTransactionWasFailure) // false until positively asserted.
905 {
906  bool bSuccess = false;
907 
908  switch (m_Type) { // Note: the below remarks about "success or fail" are
909  // specific to TRANSACTION success, not message success.
910 
911  // case OTTransaction::processNymbox: // Why is this even here?
912  // processNymbox uses NO trans#s--that's the purpose of processNymbox.
913  case OTTransaction::processInbox: // Has no closing numbers.
914  case OTTransaction::deposit: // Has no closing numbers.
915  case OTTransaction::withdrawal: // Has no closing numbers.
916  case OTTransaction::cancelCronItem: // Has no closing numbers.
917  case OTTransaction::payDividend: // Has no closing numbers.
918  case OTTransaction::transfer: // Has no closing numbers.
919 
920  break;
921 
922  case OTTransaction::marketOffer: // Uses 3 transaction #s, the opening
923  // number and 2 closers.
924  // If message fails, all closing numbers are harvestable.
925  // If message succeeds but transaction fails, closers can also be
926  // harvested.
927  // If message succeeds and transaction succeeds, closers are marked as
928  // "used" (like opener.)
929  // In that last case, you can't claw them back since they are used.
930  {
932 
933  if (nullptr == pItem) {
934  otErr << "OTTransaction::HarvestClosingNumbers: Error: Unable "
935  "to find "
936  "marketOffer item in marketOffer transaction.\n";
937  }
938  else // pItem is good. Let's load up the OTCronIteam object...
939  {
940  OTCronItem theTrade;
941  OTString strTrade;
942  pItem->GetAttachment(strTrade);
943 
944  // First load the Trade up...
945  const bool bLoadContractFromString =
946  (strTrade.Exists() &&
947  theTrade.LoadContractFromString(strTrade));
948 
949  // If failed to load the trade...
950  if (!bLoadContractFromString) {
951  otErr << "OTTransaction::HarvestClosingNumbers: ERROR: "
952  "Failed loading trade from string:\n\n" << strTrade
953  << "\n\n";
954  }
955  else // theTrade is ready to go....
956  {
957 
958  // The message reply itself was a failure. This means the
959  // transaction itself never got a chance
960  // to run... which means ALL the closing numbers on that
961  // transaction are STILL GOOD.
962  //
963  if (bReplyWasFailure) // && !bHarvestingForRetry) // on
964  // re-try, we need the closing #s to
965  // stay put, so the re-try has a
966  // chance to work.
967  { // NOTE: We do NOT exclude harvesting of closing numbers,
968  // for a marketoffer, based on bHarvestingForRetry. Why
969  // not?
970  // Because with marketOffer, ALL transaction #s are
971  // re-set EACH re-try, not just the opening #. Therefore
972  // ALL must be clawed back.
973  theTrade.HarvestClosingNumbers(
974  theNym); // (Contrast this with payment plan,
975  // exchange basket, smart contract...)
976  bSuccess = true;
977 
978  // theTrade.GetAssetAcctClosingNum();
979  // // For reference.
980  // theTrade.GetCurrencyAcctClosingNum();
981  // // (The above harvest call grabs THESE numbers.)
982 
983  }
984  // Else if the server reply message was unambiguously a
985  // SUCCESS, that means the opening number is DEFINITELY NOT
986  // HARVESTABLE.
987  // Why? Because that means the transaction definitely
988  // ran--and the opener is marked as "used" on SUCCESS, or
989  // "burned" on
990  // FAILURE--either way, that's bad for harvesting (no
991  // point.)
992  //
993  // ===> But the CLOSING numbers are harvestable on
994  // transaction *failure.*
995  // (They are not harvestable on transaction *success*
996  // though.)
997  //
998  else if (bReplyWasSuccess) {
999  if (bTransactionWasSuccess) {
1000  // (They are not harvestable on transaction success
1001  // though.)
1002  // This means the "marketOffer" closing trans#s (one
1003  // for asset account, and one for currency account)
1004  // are both
1005  // MARKED AS "USED", and will someday be marked as
1006  // CLOSED.
1007  // EITHER WAY, you certainly can't claw those
1008  // numbers back now! (They are still outstanding,
1009  // though. They're not gone, yet...)
1010  //
1011  // theTrade.HarvestClosingNumbers(theNym);
1012  // bSuccess = true;
1013  }
1014  else if (bTransactionWasFailure) {
1015  // But the CLOSING numbers ARE harvestable on
1016  // transaction failure.
1017  // (Closing numbers for marketOffers are only marked
1018  // "used" if the
1019  // marketOffer transaction was a success.)
1020  //
1021  theTrade.HarvestClosingNumbers(theNym);
1022  bSuccess = true;
1023  }
1024  } // else if (bReplyWasSuccess)
1025 
1026  } // else (the trade loaded successfully)
1027  } // pItem was found.
1028  }
1029  break;
1030 
1031  // These aren't AS simple.
1032  case OTTransaction::paymentPlan: // Uses 4 transaction #s: the opener
1033  // (sender's #), which is burned on
1034  // transaction failure, but kept alive on success,
1035  // ===> the sender's closing #, which is only marked as "used" upon
1036  // success (harvestable up until that point.)
1037  // ===> and the recipient's opening/closing numbers, which are also both
1038  // only marked as "used" upon success, and are harvestable up until that
1039  // point.
1040 
1041  {
1043 
1044  if (nullptr == pItem) {
1045  otErr << "OTTransaction::HarvestClosingNumbers: Error: Unable "
1046  "to find "
1047  "paymentPlan item in paymentPlan transaction.\n";
1048  }
1049  else // pItem is good. Let's load up the OTPaymentPlan object...
1050  {
1051  OTString strPaymentPlan;
1052  OTPaymentPlan thePlan;
1053  pItem->GetAttachment(strPaymentPlan);
1054 
1055  // First load the payment plan up...
1056  const bool bLoadContractFromString =
1057  (strPaymentPlan.Exists() &&
1058  thePlan.LoadContractFromString(strPaymentPlan));
1059 
1060  // If failed to load the payment plan from string...
1061  if (!bLoadContractFromString) {
1062  otErr << "OTTransaction::HarvestClosingNumbers: ERROR: "
1063  "Failed loading payment plan from string:\n\n"
1064  << strPaymentPlan << "\n\n";
1065  }
1066  else // thePlan is ready to go....
1067  {
1068  // If the server reply message was unambiguously a FAIL,
1069  // that means the closing numbers are STILL GOOD.
1070  // (Because the transaction therefore never even had a
1071  // chance to run.)
1072  //
1073  if (bReplyWasFailure &&
1074  !bHarvestingForRetry) // on re-try, we need the closing
1075  // #s to stay put, so the re-try
1076  // has a chance to work.
1077  {
1078  thePlan.HarvestClosingNumbers(theNym);
1079  bSuccess = true;
1080  }
1081  // Else if the server reply message was unambiguously a
1082  // SUCCESS, that means the opening number is DEFINITELY
1083  // NOT HARVESTABLE. (For the sender, anyway.) Why not?
1084  // Because that means the transaction definitely ran--and
1085  // the opener is marked as "used" on success, and "burned"
1086  // on failure--either way, that's bad for harvesting (no
1087  // point.)
1088  // The recipient, by contrast, actually retains
1089  // harvestability on his opening number up until the very
1090  // point of
1091  // transaction success.
1092  //
1093  // ====> I know you are wondering:
1094  // ====> HOW ABOUT THE CLOSING NUMBERS? (When message is
1095  // success)
1096  // 1. Transaction success: Sender and Recipient CANNOT
1097  // harvest closing numbers, which are now marked as "used."
1098  // 2. Transaction failed: Sender and Recipient **CAN**
1099  // both harvest their closing numbers.
1100  //
1101  else if (bReplyWasSuccess) {
1102  if (bTransactionWasSuccess) {
1103  // This means the "paymentPlan" closing trans#s are
1104  // MARKED AS "USED", and will someday be marked as
1105  // CLOSED.
1106  // EITHER WAY, you certainly can't claw that number
1107  // back now! (It is still outstanding, though. It's
1108  // not gone, yet...)
1109  // thePlan.HarvestClosingNumbers(theNym);
1110  // bSuccess = true;
1111  }
1112  else if (bTransactionWasFailure &&
1113  !bHarvestingForRetry) // on re-try, we need
1114  // the closing #s to
1115  // stay put, so the
1116  // re-try has a chance
1117  // to work.
1118  {
1119  // Whereas if the payment plan was a failure, that
1120  // means the closing numbers are harvestable!
1121  thePlan.HarvestClosingNumbers(theNym);
1122  bSuccess = true;
1123  }
1124  }
1125 
1126  } // else (the payment plan loaded successfully)
1127  } // pItem was found.
1128  }
1129  break;
1130 
1131  case OTTransaction::smartContract: // Uses X transaction #s, with an opener
1132  // for each party and a closer for each
1133  // asset account.
1134  // If the message is rejected by the server, then ALL openers can be
1135  // harvested. But if the
1136  // message was successful (REGARDLESS of whether the transaction was
1137  // successful) then all of
1138  // the openers for all of the parties have been burned. The closers,
1139  // meanwhile, can be recovered
1140  // if the message is a failure, as well as in cases where message
1141  // succeeds but transaction failed.
1142  // But if transaction succeeded, then the closers CANNOT be recovered.
1143  // (Only removed, once you sign
1144  // off on the receipt.)
1145  {
1146 
1148 
1149  if (nullptr == pItem) {
1150  otErr << "OTTransaction::HarvestClosingNumbers: Error: Unable "
1151  "to find "
1152  "smartContract item in smartContract transaction.\n";
1153  }
1154  else // Load up the smart contract...
1155  {
1156  OTString strSmartContract;
1157  OTSmartContract theSmartContract(GetPurportedServerID());
1158  pItem->GetAttachment(strSmartContract);
1159 
1160  // If we failed to load the smart contract...
1161  if (!strSmartContract.Exists() ||
1162  (false ==
1163  theSmartContract.LoadContractFromString(
1164  strSmartContract))) {
1165  otErr << "OTTransaction::HarvestClosingNumbers: Error: "
1166  "Unable to load "
1167  "smartContract object from smartContract "
1168  "transaction item.\n";
1169  }
1170  else // theSmartContract is ready to go....
1171  {
1172 
1173  // The message reply itself was a failure. This means the
1174  // transaction itself never got a chance
1175  // to run... which means ALL the closing numbers on that
1176  // transaction are STILL GOOD.
1177  //
1178  if (bReplyWasFailure &&
1179  !bHarvestingForRetry) // on re-try, we need the closing
1180  // #s to stay put, so the re-try
1181  // has a chance to work.
1182  {
1183  theSmartContract.HarvestClosingNumbers(theNym);
1184  bSuccess = true;
1185  }
1186  // Else if the server reply message was unambiguously a
1187  // SUCCESS, that means the opening number is DEFINITELY NOT
1188  // HARVESTABLE.
1189  // Why? Because that means the transaction definitely
1190  // ran--and the opener is marked as "used" on SUCCESS, or
1191  // "burned" on
1192  // FAILURE--either way, that's bad for harvesting (no
1193  // point.)
1194  //
1195  // ===> HOW ABOUT THE CLOSING NUMBERS?
1196  // In cases where the message succeeds but the transaction
1197  // failed, the closing numbers are recoverable. (TODO send
1198  // notice to the parties when this happens...)
1199  // But if transaction succeeded, then the closers CANNOT be
1200  // recovered. They are now "used" on the server, so you
1201  // might as well keep them in that format on the client
1202  // side, since that's how the client has them already.
1203  else if (bReplyWasSuccess) {
1204  if (bTransactionWasSuccess) {
1205  // This means the "smartContract" opening trans# is
1206  // MARKED AS "USED", and will someday be marked as
1207  // CLOSED.
1208  // EITHER WAY, you certainly can't claw that number
1209  // back now! (It is still outstanding, though. It's
1210  // not gone, yet...)
1211  //
1212  // theSmartContract.HarvestClosingNumbers(theNym);
1213  // bSuccess = true;
1214  }
1215  else if (bTransactionWasFailure &&
1216  !bHarvestingForRetry) // on re-try, we need
1217  // the closing #s to
1218  // stay put, so the
1219  // re-try has a chance
1220  // to work.
1221  {
1222  // If the transaction was a failure, the opening
1223  // trans number was burned,
1224  // but the CLOSING numbers are still harvestable...
1225  //
1226  theSmartContract.HarvestClosingNumbers(theNym);
1227  bSuccess = true;
1228  }
1229  } // else if (bReplyWasSuccess)
1230 
1231  } // else (smart contract loaded successfully)
1232  } // pItem was found.
1233  }
1234  break;
1235 
1236  default:
1237  break;
1238  }
1239 
1240  return bSuccess;
1241 }
1242 
1243 // Client-side
1244 //
1245 // This transaction actually was saved as a balance receipt (filename:
1246 // accountID.success)
1247 // and now, for whatever reason, I want to verify the receipt against the local
1248 // data (the Nym,
1249 // the inbox, the outbox, and the account balance).
1250 //
1251 // Let's say the Nym has the numbers 9 and 10. He signs a receipt to that
1252 // effect. Until a new
1253 // receipt is signed, they should STILL be 9 and 10! Therefore I should be able
1254 // to load up
1255 // the last receipt, pass it the Nym, and verify this.
1256 //
1257 // But what if the last receipt is a transaction receipt, instead of a balance
1258 // receipt? Let's
1259 // say I grab the Nym and he has 9, 10, and 15! And though this balance receipt
1260 // shows 9 and 10,
1261 // there is a newer one that shows 9, 10, and 15? That means even when verifying
1262 // a balance
1263 // receipt, I need to also load the last transaction receipt and for transaction
1264 // numbers, use
1265 // whichever one is newer.
1266 //
1267 // When downloading the inbox, the outbox, the account, or the nym, if there is
1268 // a receipt, I
1269 // should compare what I've downloaded with the last receipt. Because if there's
1270 // a discrepancy,
1271 // then I don't want to USE that inbox/outbox/account/nym to sign a NEW receipt,
1272 // causing me
1273 // to sign agreement to invalid data! Instead, I want a red flag to go up, and
1274 // the receipt
1275 // automatically saved to a disputes folder, etc.
1276 //
1278  OTPseudonym& SERVER_NYM, // For verifying a signature.
1279  OTPseudonym& THE_NYM) // transaction numbers issued according to nym must
1280  // match this.
1281 // OTLedger& THE_INBOX, // All inbox items on *this must also be found in
1282 // THE_INBOX. All new items (on THE_INBOX only) must be accounted for in the
1283 // balance.
1284 // OTLedger& THE_OUTBOX, // All inbox items that changed balance (cheque,
1285 // market, payment) must be found on the list of issued numbers.
1286 // const OTAccount& THE_ACCOUNT) // All outbox items must match, and the
1287 // account balance must be accounted for as described.
1288 { // These are now loaded within this function, so no need to pass them in.
1289  // Load the other receipt (see above) if necessary.
1290 
1291  // Compare the inbox I just downloaded with what my last signed receipt SAYS
1292  // it should say.
1293  // Let's say the inbox has transaction 9 in it -- well, my last signed
1294  // receipt better show
1295  // that 9 was in my inbox then, too. But what if 9 was on a cheque, and it
1296  // only recently hit?
1297  // Well it won't be in my old inbox, but it WILL still be signed for as an
1298  // open transaction.
1299 
1300  // Since this involves verifying the outbox, inbox, AND account, this
1301  // function should only
1302  // be called after all three have been downloaded, not after each one.
1303  // Basically the outbox should RARELY change, the inbox is EXPECTED to
1304  // change, and the account
1305  // is EXPECTED to change, BUT ONLY in cases where the inbox justifies it!
1306  //
1307  // -- Verify the transaction numbers on the nym match those exactly on the
1308  // newest transaction or balance receipt. (this)
1309  // -- Make sure outbox is the same.
1310  // -- Loop through all items in the inbox, AND in the inbox according to the
1311  // receipt, and total the
1312  // values of both. I might have 9 and 10 issued in the last receipt, with
1313  // #9 in the inbox,
1314  // showing 50 clams and a balance of 93. But now I downloaded an inbox
1315  // showing #9 AND #10,
1316  // with values of 50 and 4, and a balance of 89.
1317  // The new inbox is still valid, and the new account balance is still
1318  // valid, because the
1319  // new number that appeared was issued to me and signed out, and because
1320  // the last receipt's
1321  // balance of 93 with 50 clams worth of receipts, matches up to the new
1322  // account/inbox
1323  // balance of 89 with 54 clams worth of receipts.
1324  // The two totals still match! That's what we're checking for.
1325  //
1326  // Not JUST that actually, but that, if #10 is NOT found in the old one,
1327  // THEN the amount (4)
1328  // must be the DIFFERENCE between the balances (counting all new
1329  // transactions like #10.)
1330  // Meaning, the difference between the two balances MUST be made up EXACTLY
1331  // by the transactions
1332  // that are found now, that were not previously found, minus the total of
1333  // the transactions
1334  // from before that are no longer there, but are also no longer on my issued
1335  // list and thus don't matter.
1336  //
1337  // Wow ! OTItem::VerifyBalanceStatement will have useful code but it doesn't
1338  // encapsulate all this
1339  // new functionality, since this version must assume differences are there,
1340  // and STILL verify things
1341  // by comparing details about those differences, whereas that version only
1342  // serves to make sure
1343  // everything still matches.
1344 
1345  // -- Verify nym transactions match. (issued.)
1346  // -- Verify outbox matches.
1347  // -- Loop through all items on receipt. If outbox item, should match
1348  // exactly.
1349  // -- But for inbox items, total up: the amount of the total of the items
1350  // from the receipt,
1351  // for all those that would actually change the balance (chequeReceipt,
1352  // marketReceipt, paymentReceipt, basketReceipt.)
1353  // These should ALL be found in the current version of the inbox. (They
1354  // can only be removed by balance agreement,
1355  // which would update THIS RECEIPT to remove them...)
1356  // -- That was the receipt. Now loop through the above inbox items and do
1357  // the reverse: for each item in the NEW inbox,
1358  // add up the total of those that would change the balance, for receipts
1359  // found on the new but not the old, and account for that exactly as a
1360  // difference in balance.
1361  /*
1362 
1363  Example.
1364 
1365  -- Oldest signed receipt shows a balance of 115 clams.
1366  But then, cheque #78 hits my inbox and though I haven't yet accepted the
1367  receipt, I still need to do a transaction, like a 5 clam withdrawal, or
1368  whatever,
1369  and somehow I end up doing a balance agreement. That results in the
1370  below signed receipt:
1371 
1372  --- Old receipt shows inbox/account/nym as:
1373  Currently signed out: 8, 9, 10, and 15
1374  Balance of 100 clams (Last signed balance before this was for 115 clams
1375  above)
1376  Inbox items:
1377  #78 cheque receipt (#8) for 15 clams. (The missing money is already
1378  reflected in the above balance. BUT!! #8 must still be signed out for this
1379  to verify. Here I must sign to acknowledge the receipt is in my inbox, but
1380  I still have option to accept or dispute the receipt. Until then, server
1381  keeps it around since it has my signature on it and proves the current
1382  balance.)
1383  #82 incoming transfer for 50 clams (A new balance agreement occurs during
1384  acceptance of this. And the number doesn't belong to me. So, irrelevant
1385  here.)
1386  #10 transfer receipt for some old transfer (does NOT change balance, which
1387  already happened in the past, BUT!! #10 must still be signed out for this
1388  to verify.)
1389 
1390  My nym ISSUED list should not change unless I have a new transaction
1391  agreement, therefore I expect the list to match every time.
1392  My outbox should also match. Thus, only my account balance and inbox might
1393  change. (On the server side, which I'll see when I dl
1394  new versions of them and compare against my last receipt i.e. this
1395  function.)
1396  How? NOT via transfer receipt, since I would sign a new balance agreement
1397  whenever that would actually impact my balance.
1398  But it could happen with a *** chequeReceipt, a paymentReceipt,
1399  marketReceipt, or basketReceipt. ***
1400  Those mean, my balance has changed.
1401  In those cases, my account balance WOULD be different, but there had better
1402  be matching receipts in the inbox!
1403 
1404  --- New inbox/account/nym shows:
1405  Currently signed out: 8, 9, 10, and 15
1406  Balance of 89 clams
1407  Inbox items:
1408  #78 cheque receipt (#8) for 15 clams.
1409  #82 incoming transfer for 50 clams (A new balance agreement occurs during
1410  acceptance. So this type has no affect on balance here.)
1411  #10 transfer receipt for some old transfer (does NOT change balance, which
1412  already happened in the past)
1413  #96 cheque receipt for 7 clams (cheque #9)
1414  #97 marketReceipt for 4 clams (marketOffer #15)
1415  #99 incoming transfer for 2000 clams (Accepting it will require a new
1416  balance agreement.)
1417 
1418  ---------------------------------
1419 
1420  How do I interpret all this data?
1421  -- Transaction numbers signed out had better match. (If #s issued had
1422  changed, I would have signed for it already.)
1423 
1424  Next loop through the inbox from the old receipt:
1425  -- #78, cheque receipt, had better be there in the new inbox, since
1426  removing it requires a balance agreement, meaning it would already be off
1427  the receipt that I'm verifying... Since it's here in inbox, should
1428  therefore also be in the last receipt.
1429  -- #82, incoming transfer from old receipt, had better be also on the new
1430  inbox, since I could only accept or reject it with a balance agreement,
1431  which I'm comparing the inbox to now.
1432  -- #10 had also better be there in the new inbox for the same reason: if I
1433  had accepted this transfer receipt, then my last balance receipt would
1434  reflect that.
1435  -- THEREFORE: ALL items from old receipt must be found inside new inbox!
1436 
1437  Next, loop through the new version of the inbox:
1438  -- #78, though found in the new inbox, wouldn't necessarily be expected to
1439  be found in the last receipt, since someone may have cashed my cheque since
1440  the receipt was made.
1441  -- #82, though found in the new inbox, wouldn't necessarily be expected to
1442  be found in the last receipt, since someone may have sent me the transfer
1443  since receipt was made.
1444  -- #10 in new inbox, same thing: Someone may have recently accepted my
1445  transfer, and thus #10 only would have popped in since the last agreement.
1446  (It was there before, but I couldn't EXPECT that in every case.)
1447  -- #96 and #97 represent balance CHANGES totalling -11 clams. They must
1448  correspond to a change in balance.
1449  -- #96 is a cheque receipt.. it has changed the balance and I must account
1450  for that. But #78 is ALSO a cheque receipt, so why am I not accounting for
1451  ITs total (instead just assuming it's accounted for already in the prior
1452  balance, like 78?) Because it's NEW and wasn't on the old receipt like 78
1453  is!
1454  -- Due to the reasoning explained on the above line, ANY chequeReceipt,
1455  paymentReceipt, marketReceipt, or basketReceipt
1456  found on the new version of the inbox but NOT on the old one from the
1457  receipt, must be accounted for against the balance.
1458  -- #99 is an incoming transfer, but it will not change the balance until
1459  that transfer is accepted with a new balance agreement sometime in the
1460  future.
1461  */
1462 
1463  if (IsAbbreviated()) {
1464  otErr << "OTTransaction::VerifyBalanceReceipt: Error: This is an "
1465  "abbreviated receipt. (Load the box receipt first.)\n";
1466  return false;
1467  }
1468 
1469  OTIdentifier USER_ID(THE_NYM), SERVER_USER_ID(SERVER_NYM);
1470 
1471  const OTString strServerID(GetRealServerID()), strReceiptID(USER_ID);
1472 
1473  // if (USER_ID != GetUserID())
1474  // {
1475  // otErr << "*** OTIdentifier USER_ID(OTPseudonym THE_NYM) doesn't
1476  // match OTTransactionType::GetUserID() in
1477  // OTTransaction::VerifyBalanceReceipt\n";
1478  // return false;
1479  // }
1480 
1481  // Load the last TRANSACTION STATEMENT as well...
1482 
1483  OTString strFilename;
1484  strFilename.Format("%s.success", strReceiptID.Get());
1485 
1486  const char* szFolder1name = OTFolders::Receipt().Get(); // receipts
1487  const char* szFolder2name = strServerID.Get(); // receipts/SERVER_ID
1488  const char* szFilename =
1489  strFilename.Get(); // receipts/SERVER_ID/USER_ID.success
1490 
1491  if (!OTDB::Exists(szFolder1name, szFolder2name, szFilename)) {
1492  otWarn << "Receipt file doesn't exist in "
1493  "OTTransaction::VerifyBalanceReceipt:\n " << szFilename
1494  << "\n";
1495  return false;
1496  }
1497 
1498  std::string strFileContents(
1499  OTDB::QueryPlainString(szFolder1name, szFolder2name,
1500  szFilename)); // <=== LOADING FROM DATA STORE.
1501 
1502  if (strFileContents.length() < 2) {
1503  otErr << "OTTransaction::VerifyBalanceReceipt: Error reading "
1504  "transaction statement:\n " << szFolder1name
1505  << OTLog::PathSeparator() << szFolder2name
1506  << OTLog::PathSeparator() << szFilename << "\n";
1507  return false;
1508  }
1509 
1510  OTString strTransaction(strFileContents.c_str());
1511 
1512  // OTTransaction tranOut(SERVER_USER_ID, USER_ID, GetRealServerID());
1513  std::unique_ptr<OTTransactionType> pContents(
1514  OTTransactionType::TransactionFactory(strTransaction));
1515 
1516  if (nullptr == pContents) {
1517  otErr << "OTTransaction::VerifyBalanceReceipt: Unable to load "
1518  "transaction statement:\n " << szFolder1name
1519  << OTLog::PathSeparator() << szFolder2name
1520  << OTLog::PathSeparator() << szFilename << "\n";
1521  return false;
1522  }
1523  else if (!pContents->VerifySignature(SERVER_NYM)) {
1524  otErr << "OTTransaction::VerifyBalanceReceipt: Unable to verify "
1525  "signature on transaction statement:\n " << szFolder1name
1526  << OTLog::PathSeparator() << szFolder2name
1527  << OTLog::PathSeparator() << szFilename << "\n";
1528  return false;
1529  }
1530 
1531  // At this point, pContents is successfully loaded and verified, containing
1532  // the last transaction receipt.
1533  OTTransaction* pTrans = dynamic_cast<OTTransaction*>(pContents.get());
1534 
1535  if (nullptr == pTrans) {
1536  otErr << "OTTransaction::VerifyBalanceReceipt: Was expecting an "
1537  "OTTransaction to be stored in the transaction statement "
1538  "at:\n " << szFolder1name << OTLog::PathSeparator()
1539  << szFolder2name << OTLog::PathSeparator() << szFilename << "\n";
1540  return false;
1541  }
1542 
1543  OTTransaction& tranOut = *pTrans;
1544 
1545  // I ONLY need this transaction statement if it's newer than the balance
1546  // statement.
1547  // Otherwise, I don't use it at all. But if it's newer, then I use it
1548  // instead of the current
1549  // balance statement (only for verifying the list of issued numbers, not for
1550  // anything else.)
1551 
1552  // And in the case where that happens, I ONLY expect to see new numbers
1553  // added, NOT removed.
1554  // But again, ONLY if the transaction statement is MORE RECENT. Otherwise it
1555  // may have extra
1556  // numbers alright: ones that were already removed and I don't want to
1557  // re-sign responsibility for!
1558 
1559  // CHECK IF IT'S NEWER AND SET A POINTER BASED ON THIS.
1560 
1561  OTItem* pItemWithIssuedList =
1562  nullptr; // the item from that transaction that
1563  // actually has the issued list we'll be
1564  // using.
1565 
1566  OTItem* pTransactionItem = nullptr;
1567 
1568  if (tranOut.GetDateSigned() > GetDateSigned()) // it's newer.
1569  {
1570  // GET THE "AT TRANSACTION STATEMENT" ITEM
1571  //
1572  // only if it's new than balance receipt does this get set, to:
1573  // tranOut.GetItem(OTItem::atTransactionStatement);
1574  OTItem* pResponseTransactionItem =
1576 
1577  if (nullptr == pResponseTransactionItem) {
1578  // error, return.
1579  otOut << "No atTransactionStatement item found on receipt "
1580  "(strange.)\n";
1581  return false;
1582  }
1583  else if (OTItem::acknowledgement !=
1584  pResponseTransactionItem->GetStatus()) {
1585  // error, return.
1586  otOut << "Error: atTransactionStatement found on receipt, but not "
1587  "a successful one.\n";
1588  return false;
1589  }
1590  else if (!pResponseTransactionItem->VerifySignature(SERVER_NYM)) {
1591  otOut << "Unable to verify signature on atTransactionStatement "
1592  "item in OTTransaction::VerifyBalanceReceipt.\n";
1593  return false;
1594  }
1595 
1596  // LOAD "TRANSACTION STATEMENT" (ITEM) from within the above item we
1597  // got.
1598 
1599  OTString strBalanceItem;
1600  pResponseTransactionItem->GetReferenceString(strBalanceItem);
1601 
1602  if (!strBalanceItem.Exists()) {
1603  // error, return.
1604  otOut << "No transactionStatement item found as 'in ref to' string "
1605  "on a receipt containing atTransactionStatement item.\n";
1606  return false;
1607  }
1608 
1609  pTransactionItem = OTItem::CreateItemFromString(
1610  strBalanceItem, GetRealServerID(),
1611  pResponseTransactionItem->GetReferenceToNum());
1612 
1613  if (nullptr == pTransactionItem) {
1614  otOut << "Unable to load transactionStatement item from string "
1615  "(from a receipt containing an atTransactionStatement "
1616  "item.)\n";
1617  return false;
1618  }
1619  else if (pTransactionItem->GetType() !=
1621  otOut << "Wrong type on pTransactionItem (expected "
1622  "OTItem::transactionStatement)\n";
1623  return false;
1624  }
1625  else if (!pTransactionItem->VerifySignature(THE_NYM)) {
1626  otOut << "Unable to verify signature on transactionStatement item "
1627  "in OTTransaction::VerifyBalanceReceipt.\n";
1628  return false;
1629  }
1630 
1631  pItemWithIssuedList = pTransactionItem;
1632  }
1633 
1634  // LOAD THE ACCOUNT
1635 
1636  OTAccount THE_ACCOUNT(USER_ID, GetRealAccountID(), GetRealServerID());
1637 
1638  if (!THE_ACCOUNT.LoadContract() || !THE_ACCOUNT.VerifyAccount(THE_NYM)) {
1639  // error, return.
1640  otOut << "Failed loading or verifying account for THE_NYM in "
1641  "OTTransaction::VerifyBalanceReceipt.\n";
1642  return false;
1643  }
1644  else if (THE_ACCOUNT.GetPurportedServerID() !=
1645  GetPurportedServerID()) // the account, inbox, and outbox all
1646  // have the same Server ID. But does it
1647  // match *this receipt?
1648  {
1649  // error, return.
1650  otOut << "Account, inbox or outbox server ID fails to match receipt "
1651  "server ID.\n";
1652  return false;
1653  }
1654  else if (THE_ACCOUNT.GetPurportedAccountID() !=
1655  GetPurportedAccountID()) // Same as above except for account ID
1656  // instead of server ID.
1657  {
1658  // error, return.
1659  otOut << "Account ID fails to match receipt account ID.\n";
1660  return false;
1661  }
1662 
1663  // LOAD INBOX AND OUTBOX
1664 
1665  std::unique_ptr<OTLedger> pInbox(THE_ACCOUNT.LoadInbox(
1666  THE_NYM)); // OTAccount::Load also calls VerifyAccount() already
1667  std::unique_ptr<OTLedger> pOutbox(THE_ACCOUNT.LoadOutbox(
1668  THE_NYM)); // OTAccount::Load also calls VerifyAccount() already
1669 
1670  if ((nullptr == pInbox) || (nullptr == pOutbox)) {
1671  // error, return.
1672  otOut << "Inbox or outbox was nullptr after THE_ACCOUNT.Load in "
1673  "OTTransaction::VerifyBalanceReceipt.\n";
1674  return false;
1675  }
1676 
1677  // LOAD "AT BALANCE STATEMENT" (ITEM)
1678 
1679  OTItem* pResponseBalanceItem = GetItem(OTItem::atBalanceStatement);
1680 
1681  if (nullptr == pResponseBalanceItem) {
1682  // error, return.
1683  otOut << "No atBalanceStatement item found on receipt (strange.)\n";
1684  return false;
1685  }
1686  else if (OTItem::acknowledgement != pResponseBalanceItem->GetStatus()) {
1687  // error, return.
1688  otOut << "Error: atBalanceStatement found on receipt, but not a "
1689  "successful one.\n";
1690  return false;
1691  }
1692  else if (!pResponseBalanceItem->VerifySignature(SERVER_NYM)) {
1693  otOut << "Unable to verify signature on atBalanceStatement item in "
1694  "OTTransaction::VerifyBalanceReceipt.\n";
1695  return false;
1696  }
1697 
1698  // LOAD "BALANCE STATEMENT" (ITEM)
1699 
1700  OTItem* pBalanceItem = nullptr;
1701 
1702  OTString strBalanceItem;
1703  pResponseBalanceItem->GetReferenceString(strBalanceItem);
1704 
1705  if (!strBalanceItem.Exists()) {
1706  // error, return.
1707  otOut << "No balanceStatement item found as 'in ref to' string on a "
1708  "receipt containing atBalanceStatement item.\n";
1709  return false;
1710  }
1711 
1712  pBalanceItem =
1714  pResponseBalanceItem->GetReferenceToNum());
1715 
1716  if (nullptr == pBalanceItem) {
1717  otOut << "Unable to load balanceStatement item from string (from a "
1718  "receipt containing an atBalanceStatement item.)\n";
1719  return false;
1720  }
1721  else if (pBalanceItem->GetType() != OTItem::balanceStatement) {
1722  otOut << "Wrong type on pBalanceItem (expected "
1723  "OTItem::balanceStatement)\n";
1724  return false;
1725  }
1726  else if (!pBalanceItem->VerifySignature(THE_NYM)) {
1727  otOut << "Unable to verify signature on balanceStatement item in "
1728  "OTTransaction::VerifyBalanceReceipt.\n";
1729  return false;
1730  }
1731 
1732  // LOAD MESSAGE NYM (THE LIST OF ISSUED NUMBERS ACCORDING TO THE RECEIPT.)
1733 
1734  OTPseudonym theMessageNym;
1735  OTString strMessageNym; // Okay now we have the transaction numbers in this
1736  // MessageNym string.
1737 
1738  //
1739  if ((nullptr != pTransactionItem) &&
1740  (tranOut.GetDateSigned() > GetDateSigned())) // transaction
1741  // statement is newer
1742  // than (this)
1743  // balance statement.
1744  pItemWithIssuedList =
1745  pTransactionItem; // already set above, but I'm re-stating here for
1746  // clarity, since the else is now possible...
1747  else
1748  pItemWithIssuedList =
1749  pBalanceItem; // Hereafter we can use pItemWithIssuedList to verify
1750  // issued transaction numbers (and NOTHING ELSE.)
1751 
1752  pItemWithIssuedList->GetAttachment(
1753  strMessageNym); // Like right here, for example.
1754 
1755  if (!strMessageNym.Exists() ||
1756  !theMessageNym.LoadFromString(strMessageNym)) {
1757  otOut << "Unable to load message nym in "
1758  "OTTransaction::VerifyBalanceReceipt.\n";
1759  return false;
1760  }
1761 
1762  // Finally everything is loaded and verified!
1763  // I have the Nym and Server Nym
1764  // I have the account, inbox, and outbox
1765  // I have the original balance statement, AND the server's reply to it (a
1766  // successful one)
1767  //
1768  // Repeating a note from above:
1769  // -- Verify nym transactions match. (The issued / signed-for ones.)
1770  // -- Verify outbox matches.
1771  // -- Loop through all items on receipt. If outbox item, should match
1772  // exactly.
1773  // -- But for inbox items, total up: the amount of the total of the items
1774  // from the receipt,
1775  // for all those that would actually change the balance (chequeReceipt,
1776  // marketReceipt, paymentReceipt.)
1777  // These should ALL be found in the current version of the inbox. (They
1778  // can only be removed by balance agreement which would update THIS RECEIPT
1779  // to remove them...)
1780  // -- That was the receipt. Now loop through the latest inbox items and do
1781  // the reverse: for each item in the NEW inbox,
1782  // add up the total of those that would change the balance, for receipts
1783  // found on the new but not the old, and account for that exactly as a
1784  // difference in balance.
1785  // Also make sure each receipt in the inbox (new or old) is an issued
1786  // transaction number, signed out to THE_NYM.
1787 
1788  // VERIFY THE LIST OF ISSUED (SIGNED FOR) TRANSACTION NUMBERS ON THE NYM
1789  // AGAINST THE RECEIPT.
1790  // The Nym should match whatever is on the newest receipt (determined just
1791  // above.)
1792  //
1793  // NOTE: I used to VerifyIssuedNumbersOnNym -- but that won't work. Why?
1794  // Because let's say I signed a balance agreement with #s 9, 10, and 11.
1795  // That's my last receipt. Now let's say, using a DIFFERENT ASSET ACCOUNT, I
1796  // do a withdrawal, burning #9. Now my balance agreement says 10, 11 for
1797  // that other account, which correctly matches the server. Now when the
1798  // FIRST ACCOUNT verifies his (formerly valid) receipt, 9 is missing from
1799  // his nym,
1800  // which doesn't match the receipt! Of course that's because there's a
1801  // newer balance receipt -- BUT ON A DIFFERENT ASSET ACCOUNT.
1802  //
1803  // VerifyTransactionStatement (vs VerifyBalanceStatement, where we are now)
1804  // gets around this whole problem with
1805  // VerifyTransactionStatementNumbersOnNym,
1806  // which only verifies that every issued number found on THE_NYM
1807  // (client-side) is definitely also found in the receipt (theMessageNym). It
1808  // does NOT do the reverse.
1809  // In other words, it does NOT make sure that every Trans# on theMessageNym
1810  // (last receipt) is also found on THE_NYM (current client-side nym.)
1811  // Numbers may
1812  // have been cleared since that receipt was signed, due to a balance
1813  // agreement FROM A DIFFERENT ASSET ACCOUNT. This is okay since numbers have
1814  // not been ADDED
1815  // to your list of responsibility (which is the danger.) In order to ADD a
1816  // number to your list, a transaction statement would have to be signed,
1817  // since new
1818  // transaction numbers can only be received through the Nymbox. Since this
1819  // function (VerifyBalanceReceipt) uses the transactionStatement for
1820  // verifying issued
1821  // numbers in cases where it is newer than the balanceStatement, then if a
1822  // new number was added, it will be on the receipt already.
1823  //
1824  // if (!THE_NYM.VerifyIssuedNumbersOnNym(theMessageNym)) // Explained
1825  // above. Balance Statements from other accts might be newer, and have
1826  // burned #s already. Thus I
1828  theMessageNym)) // Can't expect a # on the receipt to still be
1829  // available, though I MUST verify that every
1830  // number on current Nym IS on the receipt (just
1831  // not the other way around.)
1832  {
1833  otOut << "Unable to verify issued numbers on last signed receipt with "
1834  "numbers on THE_NYM in OTTransaction::VerifyBalanceReceipt.\n";
1835  return false;
1836  }
1837 
1838  // LOOP THROUGH THE BALANCE STATEMENT ITEMS (INBOX AND OUTBOX) TO GATHER
1839  // SOME DATA...
1840 
1841  int32_t nInboxItemCount = 0, nOutboxItemCount = 0;
1842 
1843  // otErr << "BEFORE LOOP nInboxItemCount: %d nOutboxItemCount: %d\n",
1844  // nInboxItemCount, nOutboxItemCount);
1845 
1846  const char* szInbox = "Inbox";
1847  const char* szOutbox = "Outbox";
1848  const char* pszLedgerType = nullptr;
1849  int64_t lReceiptBalanceChange =
1850  0; // For measuring the amount of the total of items in the inbox that
1851  // have changed the balance (like cheque receipts)
1852 
1853  // Notice here, I'm back to using pBalanceItem instead of
1854  // pItemWithIssuedList, since this is the inbox/outbox section...
1855  otWarn << "Number of inbox/outbox items on the balance statement: "
1856  << pBalanceItem->GetItemCount() << "\n";
1857 
1858  // TODO: Note: If the balance item shows a FINAL RECEIPT present, then ALL
1859  // the co-related cron receipts in
1860  // the ACTUAL INBOX must ALSO be present on the balance item, just as the
1861  // final receipt is present. IT cannot
1862  // be there unless THEY are also there! (The WHOLE PURPOSE of the final
1863  // receipt is to MAKE SURE that all its
1864  // related paymentReceipts/marketReceipts have been CLOSED OUT.)
1865  //
1866 
1867  for (int32_t i = 0; i < pBalanceItem->GetItemCount(); i++) {
1868  // for outbox calculations. (It's the only case where GetReceiptAmount()
1869  // is wrong and needs -1 multiplication.)
1870  int64_t lReceiptAmountMultiplier = 1;
1871 
1872  OTItem* pSubItem = pBalanceItem->GetItem(i);
1873 
1874  OT_ASSERT(nullptr != pSubItem);
1875 
1876  OTLedger* pLedger = nullptr;
1877 
1878  switch (pSubItem->GetType()) {
1879 
1880  // These types of receipts can actually change your balance.
1881  //
1882  case OTItem::chequeReceipt:
1883  case OTItem::marketReceipt:
1885  case OTItem::basketReceipt:
1886 
1887  lReceiptBalanceChange += pSubItem->GetAmount();
1888 
1889  // otErr << "RECEIPT: lReceiptBalanceChange: %lld
1890  // pSubItem->GetAmount() %lld\n",
1891  // lReceiptBalanceChange, pSubItem->GetAmount());
1892 
1893  // DROPS THROUGH HERE...
1894  case OTItem::transferReceipt: // These types of receipts do NOT change
1895  // your balance.
1897  case OTItem::finalReceipt:
1898 
1899  nInboxItemCount++;
1900  // otErr << "RECEIPT: nInboxItemCount: %d
1901  // nOutboxItemCount: %d\n", nInboxItemCount, nOutboxItemCount);
1902  pLedger = pInbox.get();
1903  pszLedgerType = szInbox;
1904 
1905  // DROPS THROUGH HERE...
1906  case OTItem::transfer:
1907 
1908  break; // we'll handle this in the next switch.
1909 
1910  default: {
1911  OTString strItemType;
1912  pSubItem->GetTypeString(strItemType);
1913  otLog3
1914  << "OTTransaction::VerifyBalanceReceipt: Ignoring "
1915  << strItemType
1916  << " item "
1917  "in balance statement while verifying it against inbox.\n";
1918  }
1919  continue;
1920  }
1921 
1922  switch (pSubItem->GetType()) {
1923  case OTItem::transfer:
1924 
1925  if (pSubItem->GetAmount() < 0) // it's an outbox item
1926  {
1927  lReceiptAmountMultiplier =
1928  -1; // transfers out always reduce your balance.
1929  nOutboxItemCount++;
1930 
1931  // otErr << "GetAmount() negative, OUTBOX
1932  // ITEM: nInboxItemCount: %d nOutboxItemCount: %d\n",
1933  // nInboxItemCount, nOutboxItemCount);
1934 
1935  pLedger = pOutbox.get();
1936  pszLedgerType = szOutbox;
1937  }
1938  else {
1939  lReceiptAmountMultiplier =
1940  1; // transfers in always increase your balance.
1941  nInboxItemCount++;
1942  pLedger = pInbox.get();
1943  pszLedgerType = szInbox;
1944 
1945  // otErr << "GetAmount() POSITIVE, INBOX
1946  // ITEM: nInboxItemCount: %d nOutboxItemCount: %d\n",
1947  // nInboxItemCount, nOutboxItemCount);
1948  }
1949  break;
1950 
1951  case OTItem::finalReceipt: // will have a 0 receipt amount.
1952  case OTItem::transferReceipt: // will have a 0 receipt amount.
1953  case OTItem::voucherReceipt: // will have a 0 receipt amount.
1954  case OTItem::chequeReceipt:
1955  case OTItem::marketReceipt: // will already be negative or positive
1956  // based on whichever is appropriate.
1957  case OTItem::paymentReceipt: // will already be negative or positive
1958  // based on whichever is appropriate.
1959  case OTItem::basketReceipt: // will already be negative or positive
1960  // based on whichever is appropriate.
1961  lReceiptAmountMultiplier = 1;
1962  break;
1963  default:
1964  continue; // This will never happen, due to the first continue above
1965  // in the first switch.
1966  }
1967 
1968  OTTransaction* pTransaction = nullptr;
1969 
1970  int64_t lTempTransactionNum = 0; // Used for the below block.
1971  int64_t lTempReferenceToNum = 0; // Used for the below block.
1972  int64_t lTempNumberOfOrigin = 0; // Used for the below block.
1973 
1974  // What's going on here? In the original balance statement, ONLY IN
1975  // CASES OF OUTOING TRANSFER,
1976  // the user has put transaction # "1" in his outbox, in anticipation
1977  // that
1978  // the server, upon success, will actually put a real pending transfer
1979  // into his outbox, and
1980  // issue a number for it (like "34").
1981  if ((pOutbox.get() ==
1982  pLedger) && // Thus it's understood that whenever the
1983  // balanceStatement
1984  // has a "1" in the outbox, I should find a corresponding "34" (or
1985  // whatever # the
1986  (pSubItem->GetTransactionNum() ==
1987  1) && // server chose) as the GetNewOutboxTransNum member on the
1988  // atBalanceStatement.
1989  // Now here, when verifying the receipt, this allows me to verify
1990  // the
1991  (pResponseBalanceItem->GetNewOutboxTransNum() >
1992  0)) // outbox request '1' against the actual '34' that resulted.
1993  {
1994  lTempTransactionNum = pResponseBalanceItem->GetNewOutboxTransNum();
1995  pTransaction = pLedger->GetTransaction(lTempTransactionNum);
1996 
1997  otLog3 << "OTTransaction::VerifyBalanceReceipt: (This iteration, "
1998  "I'm handling an item listed as '1' in the outbox.)\n";
1999  }
2000  else { // THE ABOVE IS THE *UNUSUAL* CASE, WHEREAS THIS IS THE NORMAL
2001  // CASE:
2002  //
2003  // Make sure that the transaction number of each sub-item is found
2004  // on the appropriate ledger (inbox or outbox).
2005 
2006  lTempTransactionNum = pSubItem->GetTransactionNum();
2007  pTransaction = pLedger->GetTransaction(lTempTransactionNum);
2008  }
2009 
2010  if (nullptr != pTransaction) {
2011  lTempReferenceToNum = pTransaction->GetReferenceToNum();
2012  lTempNumberOfOrigin = pTransaction->GetRawNumberOfOrigin();
2013  }
2014 
2015  bool bSwitchedBoxes = false; // In the event that an outbox pending
2016  // transforms into an inbox
2017  // transferReceipt, I set this true.
2018 
2019  // Let's say I sign a balance receipt showing a 100 clam pending
2020  // transfer, sitting in my outbox.
2021  // That means someday when I VERIFY that receipt, the 100 clam pending
2022  // better still be in that
2023  // outbox, or verification will fail. BUT WAIT -- if the receipient
2024  // accepts the transfer, then it
2025  // will disappear out of my outbox, and show up in my inbox as a
2026  // transferReceipt. So when I go to
2027  // verify my balance receipt, I have to expect that any outbox item
2028  // might be missing, but if that is
2029  // the case, there had better be a matching transferReceipt in the
2030  // inbox. (That wouldn't disappear
2031  // unless I processed my inbox, and signed a new balance agreement to
2032  // get rid of it, so I know it
2033  // has to be there in the inbox if the pending wasn't in the outbox. (If
2034  // the receipt is any good.)
2035  //
2036  // Therefore the code has to specifically allow for this case, for
2037  // outbox items...
2038  if ((nullptr == pTransaction) && (pOutbox.get() == pLedger)) {
2039  otLog4 << "OTTransaction::" << __FUNCTION__
2040  << ": Outbox pending found as inbox transferReceipt. "
2041  "(Normal.)\n";
2042 
2043  // We didn't find the transaction that was expected to be in the
2044  // outbox. (A pending.)
2045  // Therefore maybe it is now a transfer receipt in the Inbox. We
2046  // allow for this case.
2047 
2048  pTransaction =
2049  pInbox->GetTransferReceipt(pSubItem->GetNumberOfOrigin());
2050 
2051  if (nullptr != pTransaction) {
2052  lTempTransactionNum = pTransaction->GetTransactionNum();
2053  lTempNumberOfOrigin = pTransaction->GetRawNumberOfOrigin();
2054 
2055  // re: the code below: lTempReferenceToNum =
2056  // pSubItem->GetReferenceToNum();
2057  //
2058  // If it had been in the outbox, the pending receipt would be
2059  // "in reference to" my original
2060  // transfer.
2061  // But if it's since been processed into a transferReceipt in my
2062  // inbox, that transferReceipt
2063  // is now "in reference to" the recipient's acceptPending, and
2064  // thus is NOT in reference to
2065  // my original transfer.
2066  // Thus, when the ref num is compared (a little farther below)
2067  // to pSubItem->RefNum, it's
2068  // GUARANTEED to fail. That is why we are using
2069  // pSubItem->GetReferenceToNum here instead of
2070  // pTransaction->GetReferenceToNum.
2071  //
2072  // Now you might ask, "Then why, below, are we comparing
2073  // lTempReferenceToNum (containing
2074  // pSubItem->GetReferenceToNum) to pSubItem->GetReferenceToNum
2075  // ?? Aren't we just comparing
2076  // it to itself?"
2077  //
2078  // The answer is yes, in this specific case, we are. But
2079  // remember, in most cases, lTempReferenceToNum
2080  // contains pTransaction->GetReferenceToNum, and so in most
2081  // cases we are NOT comparing it
2082  // to itself. ONLY in this specific case where the receipt has
2083  // changed from an outbox-based
2084  // pending to an inbox-based transferReceipt. And so here,
2085  // lTempReferenceToNum is set to pSubItem's
2086  // version, so that it will not fail the below comparison, which
2087  // would otherwise succeed properly
2088  // in all other cases.
2089  //
2090  // Next you might ask, "But if we are comparing it to itself in
2091  // this specific case, sure it will
2092  // pass the comparison, but then what happens to the security,
2093  // in this specific case?"
2094  //
2095  // The answer is, the very next comparison after that is for the
2096  // NumberOfOrigin, which is unique
2097  // and which still must match. (Therefore we are still
2098  // protected.)
2099  //
2100  lTempReferenceToNum = pSubItem->GetReferenceToNum();
2101 
2102  lReceiptAmountMultiplier = 1;
2103 
2104  nInboxItemCount++;
2105  nOutboxItemCount--;
2106 
2107  // otErr << "PENDING->TransferReceipt.
2108  // nInboxItemCount: %d nOutboxItemCount: %d\n",
2109  // nInboxItemCount, nOutboxItemCount);
2110 
2111  pLedger = pInbox.get();
2112  pszLedgerType = szInbox;
2113 
2114  bSwitchedBoxes =
2115  true; // We need to know this in one place below.
2116  }
2117 
2118  /*
2119  Pending:
2120  Outbox: 1901, referencing 1884
2121  Inbox: 1901, referencing 1884
2122 
2123 
2124  transfer receipt:
2125  Trans 1902, referencing 1884 (That's just the display, however.
2126  Really 1902 refs 781, which refs 1884.)
2127 
2128 
2129  The pending in the outbox REFERENCES the right number.
2130 
2131  The transfer receipt includes (ref string) an acceptPending that
2132  references the right number.
2133 
2134  So for pending in outbox, when failure, get ReferenceNum(), and use
2135  that to find item in Inbox using GetTransferReceipt().
2136  */
2137  }
2138 
2139  // STILL not found??
2140  if (nullptr == pTransaction) {
2141  otOut << "OTTransaction::" << __FUNCTION__ << ": Expected "
2142  << pszLedgerType << " transaction (" << lTempTransactionNum
2143  << ") not found. (Amount " << pSubItem->GetAmount() << ".)\n";
2144  return false;
2145  }
2146 
2147  // subItem is from the balance statement, and pTransaction is from the
2148  // inbox/outbox
2149  if (pSubItem->GetReferenceToNum() != lTempReferenceToNum) {
2150  otOut << "OTTransaction::" << __FUNCTION__ << ": " << pszLedgerType
2151  << " transaction (" << lTempTransactionNum
2152  << ") mismatch Reference Num: "
2153  << pSubItem->GetReferenceToNum() << ", expected "
2154  << lTempReferenceToNum << "\n";
2155  return false;
2156  }
2157 
2158  if (pSubItem->GetRawNumberOfOrigin() != lTempNumberOfOrigin) {
2159  otOut << "OTTransaction::" << __FUNCTION__ << ": " << pszLedgerType
2160  << " transaction (" << lTempTransactionNum
2161  << ") mismatch Number of Origin: "
2162  << pSubItem->GetRawNumberOfOrigin() << ", expected "
2163  << lTempNumberOfOrigin << "\n";
2164  return false;
2165  }
2166 
2167  int64_t lTransactionAmount = pTransaction->GetReceiptAmount();
2168  lTransactionAmount *= lReceiptAmountMultiplier;
2169 
2170  if (pSubItem->GetAmount() != lTransactionAmount) {
2171  otOut << "OTTransaction::" << __FUNCTION__ << ": " << pszLedgerType
2172  << " transaction (" << lTempTransactionNum
2173  << ") "
2174  "amounts don't match: Report says "
2175  << pSubItem->GetAmount() << ", but expected "
2176  << lTransactionAmount
2177  << ". Trans recpt amt: " << pTransaction->GetReceiptAmount()
2178  << ", (pBalanceItem->GetAmount() == "
2179  << pBalanceItem->GetAmount() << ".)\n";
2180  return false;
2181  }
2182 
2183  if ((pSubItem->GetType() == OTItem::transfer) &&
2184  (((bSwitchedBoxes == true) &&
2185  (pTransaction->GetType() != OTTransaction::transferReceipt)) ||
2186  ((pLedger == pOutbox.get()) &&
2187  (pTransaction->GetType() != OTTransaction::pending)) ||
2188  ((pLedger == pInbox.get()) &&
2189  (pTransaction->GetType() != OTTransaction::pending) &&
2190  (pTransaction->GetType() != OTTransaction::transferReceipt)))) {
2191  otOut << "OTTransaction::" << __FUNCTION__ << ": " << pszLedgerType
2192  << " transaction (" << lTempTransactionNum
2193  << ") wrong type. (pending block)\n";
2194  return false;
2195  }
2196 
2197  if ((pSubItem->GetType() == OTItem::chequeReceipt) &&
2198  (pTransaction->GetType() != OTTransaction::chequeReceipt)) {
2199  otOut << "OTTransaction::" << __FUNCTION__ << ": " << pszLedgerType
2200  << " transaction (" << lTempTransactionNum
2201  << ") wrong type. (chequeReceipt block)\n";
2202  return false;
2203  }
2204 
2205  if ((pSubItem->GetType() == OTItem::voucherReceipt) &&
2206  (pTransaction->GetType() != OTTransaction::voucherReceipt)) {
2207  otOut << "OTTransaction::" << __FUNCTION__ << ": " << pszLedgerType
2208  << " transaction (" << lTempTransactionNum
2209  << ") wrong type. (voucherReceipt block)\n";
2210  return false;
2211  }
2212 
2213  if ((pSubItem->GetType() == OTItem::marketReceipt) &&
2214  (pTransaction->GetType() != OTTransaction::marketReceipt)) {
2215  otOut << "OTTransaction::" << __FUNCTION__ << ": " << pszLedgerType
2216  << " transaction (" << lTempTransactionNum
2217  << ") wrong type. (marketReceipt block)\n";
2218  return false;
2219  }
2220 
2221  if ((pSubItem->GetType() == OTItem::paymentReceipt) &&
2222  (pTransaction->GetType() != OTTransaction::paymentReceipt)) {
2223  otOut << "OTTransaction::" << __FUNCTION__ << ": " << pszLedgerType
2224  << " transaction (" << lTempTransactionNum
2225  << ") wrong type. (paymentReceipt block)\n";
2226  return false;
2227  }
2228 
2229  if ((pSubItem->GetType() == OTItem::transferReceipt) &&
2230  (pTransaction->GetType() != OTTransaction::transferReceipt)) {
2231  otOut << "OTTransaction::" << __FUNCTION__ << ": " << pszLedgerType
2232  << " transaction (" << lTempTransactionNum
2233  << ") wrong type. (transferReceipt block)\n";
2234  return false;
2235  }
2236 
2237  if ((pSubItem->GetType() == OTItem::basketReceipt) &&
2238  ((pTransaction->GetType() != OTTransaction::basketReceipt) ||
2239  (pSubItem->GetClosingNum() != pTransaction->GetClosingNum()))) {
2240  otOut << "OTTransaction::" << __FUNCTION__ << ": " << pszLedgerType
2241  << " transaction (" << lTempTransactionNum
2242  << ") wrong type or closing num ("
2243  << pSubItem->GetClosingNum() << "). "
2244  "(basketReceipt block)\n";
2245  return false;
2246  }
2247 
2248  if ((pSubItem->GetType() == OTItem::finalReceipt) &&
2249  ((pTransaction->GetType() != OTTransaction::finalReceipt) ||
2250  (pSubItem->GetClosingNum() != pTransaction->GetClosingNum()))) {
2251  otOut << "OTTransaction::" << __FUNCTION__ << ": " << pszLedgerType
2252  << " transaction (" << lTempTransactionNum
2253  << ") wrong type or closing num ("
2254  << pSubItem->GetClosingNum() << "). "
2255  "(finalReceipt block)\n";
2256  return false;
2257  }
2258  }
2259 
2260  // By this point, I have an accurate count of the inbox items, and outbox
2261  // items, represented
2262  // by *this receipt.
2263  // I also know that I found each item from the receipt on the new inbox or
2264  // outbox (as I should have)
2265  // But do I have to verify that the items are all signed for. I'll do that
2266  // below since this list
2267  // is a subset of that one (supposedly.)
2268 
2269  // otErr << "BEFORE COUNT MATCH. nInboxItemCount: %d nOutboxItemCount:
2270  // %d\n", nInboxItemCount, nOutboxItemCount);
2271 
2272  if (nOutboxItemCount != pOutbox->GetTransactionCount()) {
2273  otOut << "OTTransaction::" << __FUNCTION__
2274  << ": Outbox mismatch in expected transaction count.\n"
2275  " --- THE_INBOX count: " << pInbox->GetTransactionCount()
2276  << " --- THE_OUTBOX count: " << pOutbox->GetTransactionCount()
2277  << "\n"
2278  "--- nInboxItemCount: " << nInboxItemCount
2279  << " --- nOutboxItemCount: " << nOutboxItemCount << "\n\n";
2280 
2281  return false;
2282  }
2283 
2284  // (Notice I don't check inbox item count here, since that actually CAN
2285  // change.)
2286 
2287  // LOOP THROUGH LATEST INBOX AND GATHER DATA / VALIDATE AGAINST LAST
2288  // RECEIPT.
2289 
2290  int64_t lInboxBalanceChange = 0; // Change in the account balance we'd
2291  // expect, based on TOTAL receipts in the
2292  // inbox.
2293  int64_t lInboxSupposedDifference = 0; // Change in the account balance we'd
2294  // expect, based on the NEW receipts
2295  // in the inbox.
2296 
2297  for (int32_t i = 0; i < pInbox->GetTransactionCount(); i++) {
2298  OTTransaction* pTransaction = pInbox->GetTransactionByIndex(i);
2299 
2300  OT_ASSERT(nullptr != pTransaction);
2301 
2302  switch (pTransaction->GetType()) {
2307 
2308  lInboxBalanceChange +=
2309  pTransaction->GetReceiptAmount(); // Here I total ALL relevant
2310  // receipts.
2311 
2312  // otErr << "ON INBOX: lInboxBalanceChange: %lld
2313  // pTransaction->GetReceiptAmount(): %lld\n", // temp remove debugging
2314  // todo
2315  // lInboxBalanceChange,
2316  // pTransaction->GetReceiptAmount());
2317 
2318  case OTTransaction::finalReceipt: // finalReceipt has no amount.
2319  case OTTransaction::pending: // pending has an amount, but it already
2320  // came out of the account and thus isn't
2321  // figured here.
2322  case OTTransaction::transferReceipt: // transferReceipt has an amount,
2323  // but it already came out of
2324  // account and thus isn't figured in here.
2325  case OTTransaction::voucherReceipt: // voucherReceipt has an amount, but
2326  // it already came out of account
2327  // and thus isn't figured in here.
2328  break;
2329  default: {
2330  otLog4 << "OTTransaction::" << __FUNCTION__ << ": Ignoring "
2331  << pTransaction->GetTypeString()
2332  << " item in inbox while verifying it against balance "
2333  "receipt.\n";
2334  }
2335  continue;
2336  }
2337 
2338  // This "for" loop is in the process of iterating the LATEST INBOX...
2339  // ...For each receipt in that inbox, we try and look up a record of the
2340  // exact same receipt in
2341  // the INBOX REPORT (present in the balance agreement from the LAST
2342  // SIGNED TRANSACTION RECEIPT.)
2343  //
2344  // It may or may not be found...
2345 
2346  OTItem* pSubItem = pBalanceItem->GetItemByTransactionNum(
2347  pTransaction->GetTransactionNum());
2348 
2349  // The above loop already verified that all items in the receipt's inbox
2350  // were found in the new inbox.
2351  //
2352  // But THIS item, though found in the new inbox, WAS NOT FOUND in the
2353  // OLD inbox (on the receipt.)
2354  // That means it needs to be accounted for against the account balance!
2355  //
2356  if (nullptr == pSubItem) {
2357  OTItem* pFinalReceiptItem = nullptr;
2358  switch (pTransaction->GetType()) {
2361  //
2362  // New thought: if this transaction is from cron (paymentReceipt
2363  // or marketReceipt), AND THIS BEING A NEW ITEM
2364  // that IS in the latest inbox (but was NOT there before, in the
2365  // receipt), THEN the finalReceipt for THIS
2366  // transaction had BETTER NOT BE in the old inbox from my last
2367  // receipt!!
2368  //
2369  // Logic: Because the whole point of the finalReceipt is to
2370  // prevent any NEW marketReceipts from popping in,
2371  // once it is present! It's like a "red flag" or a "filing date"
2372  // -- once it is triggered, IT IS THE FINAL RECEIPT.
2373  // No other receipts can appear that reference the same
2374  // transaction number!
2375  //
2376  // THEREFORE: If the FINAL RECEIPT is ALREADY in my last signed
2377  // receipt, then WHY IN HELL are NEW marketReceipts or
2378  // paymentReceipts going into the latest inbox ??
2379  //
2380  // That is why I verify here that, IF THIS IS A CRON
2381  // TRANSACTION (payment, market), then the finalReceipt
2382  // should NOT be present in the inbox report from the last
2383  // receipt!
2384  //
2385 
2386  pFinalReceiptItem =
2387  pBalanceItem->GetFinalReceiptItemByReferenceNum(
2388  pTransaction->GetReferenceToNum());
2389 
2390  // If it was FOUND... (bad)
2391  //
2392  if (nullptr != pFinalReceiptItem) {
2393  otOut << "OTTransaction::" << __FUNCTION__
2394  << ": Malicious server? A new cronReceipt has "
2395  "appeared, "
2396  "even though its corresponding \nfinalReceipt was "
2397  "already present in the LAST SIGNED RECEIPT. "
2398  "In reference to: "
2399  << pTransaction->GetReferenceToNum() << "\n";
2400  return false;
2401  }
2402  // else drop-through, since marketReceipts and paymentReceipts DO
2403  // affect the balance...
2404 
2405  case OTTransaction::chequeReceipt: // Every one of these, we have to
2406  // add up the total and reconcile
2407  // against the latest balance.
2409 
2410  lInboxSupposedDifference +=
2411  pTransaction->GetReceiptAmount(); // Here I only total the
2412  // NEW receipts (not found
2413  // in old receipt inbox
2414  // but found in current
2415  // inbox.)
2416 
2417  // otErr << "NOT ON RECEIPT:
2418  // lInboxSupposedDifference: %lld pTransaction->GetReceiptAmount():
2419  // %lld\n", // temp remove debugging todo
2420  // lInboxSupposedDifference,
2421  // pTransaction->GetReceiptAmount());
2422 
2423  case OTTransaction::finalReceipt: // This has no value. 0 amount.
2424  case OTTransaction::pending: // pending has value, why aren't we
2425  // adding it? Because it hasn't changed
2426  // the balance yet.
2427  case OTTransaction::transferReceipt: // transferReceipt has an
2428  // amount, but it already came
2429  // out of
2430  // the account and thus isn't figured in here.
2431  case OTTransaction::voucherReceipt: // voucherReceipt has an amount,
2432  // but it already came out of
2433  // the account and thus isn't figured in here.
2434  break;
2435 
2436  default:
2437  break; // this should never happen due to above switch.
2438  }
2439  }
2440  else // If the transaction from the inbox WAS found as an item on the
2441  // old receipt, let's verify the two against each other...
2442  {
2443  // subItem is from the balance statement, and pTransaction is from
2444  // the inbox
2445  if (pSubItem->GetReferenceToNum() !=
2446  pTransaction->GetReferenceToNum()) {
2447  otOut << "OTTransaction::" << __FUNCTION__
2448  << ": Inbox transaction ("
2449  << pSubItem->GetTransactionNum()
2450  << ") mismatch Reference Num: "
2451  << pSubItem->GetReferenceToNum() << ", expected "
2452  << pTransaction->GetReferenceToNum() << "\n";
2453  return false;
2454  }
2455 
2456  if (pSubItem->GetNumberOfOrigin() !=
2457  pTransaction->GetNumberOfOrigin()) {
2458  otOut << "OTTransaction::" << __FUNCTION__
2459  << ": Inbox transaction ("
2460  << pSubItem->GetTransactionNum()
2461  << ") mismatch Reference Num: "
2462  << pSubItem->GetNumberOfOrigin() << ", expected "
2463  << pTransaction->GetNumberOfOrigin() << "\n";
2464  return false;
2465  }
2466 
2467  // We're looping through the inbox here, so no multiplier is needed
2468  // for the amount
2469  // (that was only for outbox items.)
2470  if (pSubItem->GetAmount() != (pTransaction->GetReceiptAmount())) {
2471  otOut << "OTTransaction::" << __FUNCTION__
2472  << ": Inbox transaction ("
2473  << pSubItem->GetTransactionNum()
2474  << ") "
2475  "amounts don't match: " << pSubItem->GetAmount()
2476  << ", expected " << pTransaction->GetReceiptAmount()
2477  << ". (pBalanceItem->GetAmount() == "
2478  << pBalanceItem->GetAmount() << ".)\n";
2479  return false;
2480  }
2481 
2482  if ((pSubItem->GetType() == OTItem::transfer) &&
2483  (pTransaction->GetType() != OTTransaction::pending)) {
2484  otOut << "OTTransaction::" << __FUNCTION__
2485  << ": Inbox transaction ("
2486  << pSubItem->GetTransactionNum()
2487  << ") wrong type. (pending block)\n";
2488  return false;
2489  }
2490 
2491  if ((pSubItem->GetType() == OTItem::chequeReceipt) &&
2492  (pTransaction->GetType() != OTTransaction::chequeReceipt)) {
2493  otOut << "OTTransaction::" << __FUNCTION__
2494  << ": Inbox transaction ("
2495  << pSubItem->GetTransactionNum()
2496  << ") wrong type. "
2497  "(chequeReceipt block)\n";
2498  return false;
2499  }
2500 
2501  if ((pSubItem->GetType() == OTItem::voucherReceipt) &&
2502  (pTransaction->GetType() != OTTransaction::voucherReceipt)) {
2503  otOut << "OTTransaction:" << __FUNCTION__
2504  << ": Inbox transaction ("
2505  << pSubItem->GetTransactionNum()
2506  << ") wrong type. "
2507  "(voucherReceipt block)\n";
2508  return false;
2509  }
2510 
2511  if ((pSubItem->GetType() == OTItem::marketReceipt) &&
2512  (pTransaction->GetType() != OTTransaction::marketReceipt)) {
2513  otOut << "OTTransaction::" << __FUNCTION__
2514  << ": Inbox transaction ("
2515  << pSubItem->GetTransactionNum()
2516  << ") wrong type. "
2517  "(marketReceipt block)\n";
2518  return false;
2519  }
2520 
2521  if ((pSubItem->GetType() == OTItem::paymentReceipt) &&
2522  (pTransaction->GetType() != OTTransaction::paymentReceipt)) {
2523  otOut << "OTTransaction::" << __FUNCTION__
2524  << ": Inbox transaction ("
2525  << pSubItem->GetTransactionNum()
2526  << ") wrong type. "
2527  "(paymentReceipt block)\n";
2528  return false;
2529  }
2530 
2531  if ((pSubItem->GetType() == OTItem::transferReceipt) &&
2532  (pTransaction->GetType() != OTTransaction::transferReceipt)) {
2533  otOut << "OTTransaction::" << __FUNCTION__
2534  << ": Inbox transaction ("
2535  << pSubItem->GetTransactionNum()
2536  << ") wrong type. "
2537  "(transferReceipt block)\n";
2538  return false;
2539  }
2540 
2541  if ((pSubItem->GetType() == OTItem::basketReceipt) &&
2542  ((pTransaction->GetType() != OTTransaction::basketReceipt) ||
2543  (pSubItem->GetClosingNum() !=
2544  pTransaction->GetClosingNum()))) {
2545  otOut << "OTTransaction::" << __FUNCTION__
2546  << ": Inbox transaction ("
2547  << pSubItem->GetTransactionNum()
2548  << ") wrong type, "
2549  "or mismatched closing num. (basketReceipt block)\n";
2550  return false;
2551  }
2552 
2553  if ((pSubItem->GetType() == OTItem::finalReceipt) &&
2554  ((pTransaction->GetType() != OTTransaction::finalReceipt) ||
2555  (pSubItem->GetClosingNum() !=
2556  pTransaction->GetClosingNum()))) {
2557  otOut << "OTTransaction::" << __FUNCTION__
2558  << ": Inbox transaction ("
2559  << pSubItem->GetTransactionNum()
2560  << ") wrong type, "
2561  "or mismatched closing num. (finalReceipt block)\n";
2562  return false;
2563  }
2564 
2565  } // else pSubItem WAS found on the old receipt
2566 
2567  // Next I need to find out the transaction number that I ORIGINALLY
2568  // used, that's somehow associated with the receipt
2569  // I found in my inbox, by looking up the number from within the
2570  // receipt...
2571  //
2572  OTString strRespTo;
2573  int64_t lIssuedNum = 0; // The number that must STILL be signed out to
2574  // me, in order for this receipt not be warrant
2575  // disputing.
2576  OTTransaction* pFinalReceiptTransaction = nullptr;
2577 
2578  switch (pTransaction->GetType()) {
2579 
2580  case OTTransaction::transferReceipt: // a transfer receipt is in
2581  // reference to some guy's
2582  // acceptPending
2585 
2586  lIssuedNum = pTransaction->GetNumberOfOrigin();
2587  break;
2588 
2589  // ANY cron-related receipts should go here...
2590  //
2592  case OTTransaction::paymentReceipt: // a payment receipt #92 is IN
2593  // REFERENCE TO my payment plan #13,
2594  // which I am still signed out for... UNTIL the final receipt
2595  // appears.
2596  // Once a final receipt appears that is "in reference to" the same
2597  // number as a marketReceipt (or paymentReceipt)
2598  // then the paymentReceipt #92 is now IN REFERENCE TO my payment
2599  // plan #13, WHICH IS CLOSED FOR NEW PAYMENTS, BUT
2600  // THE PAYMENT RECEIPT ITSELF IS STILL VALID UNTIL THE "closing
2601  // transaction num" ON THAT FINAL RECEIPT IS CLOSED.
2602  //
2603  // Therefore I first need to see if the final receipt is PRESENT in
2604  // the inbox, so I can then determine
2605  // which number should be expected to be found on my ISSUED list of
2606  // transaction numbers.
2607  //
2608  pFinalReceiptTransaction =
2609  pInbox->GetFinalReceipt(pTransaction->GetReferenceToNum());
2610 
2611  if (nullptr != pFinalReceiptTransaction) // FINAL RECEIPT WAS FOUND
2612  lIssuedNum = pFinalReceiptTransaction->GetClosingNum();
2613  else // NOT found...
2614  lIssuedNum = pTransaction->GetReferenceToNum();
2615 
2616  // If marketReceipt #15 is IN REFERENCE TO original market offer
2617  // #10,
2618  // then the "ISSUED NUM" that is still open on my "signed out" list
2619  // is #10.
2620  //
2621  // UNLESS!! Unless a final receipt is present in reference to this
2622  // same number, in which
2623  // case the CLOSING TRANSACTION NUMBER stored on that final receipt
2624  // will become my ISSUED NUM
2625  // for the purposes of this code. (Because the original number IS
2626  // closed, but the marketReceipt is
2627  // also still valid until the FINAL RECEIPT is closed.)
2628  //
2629  break;
2630 
2631  // basketReceipt always expects the issued num to be its "closing num".
2632  // The "reference to" is instead
2633  // expected to contain the basketExchange ID (Trans# of the original
2634  // request to exchange, which is already closed.)
2635  //
2636  // Final Receipt expects that its "in reference to" is already closed
2637  // (that's why the final receipt even exists...)
2638  // Its own GetClosingNum() now contains the only valid possible
2639  // transaction number for this receipt (and for any related
2640  // to it in this same inbox, which share the same "in reference to"
2641  // number...
2642 
2645 
2646  lIssuedNum = pTransaction->GetClosingNum();
2647  break;
2648 
2649  default:
2650  continue; // Below this point (inside the loop) is ONLY for receipts
2651  // that somehow represent a transaction number that's
2652  // still issued / signed out to me.
2653  }
2654 
2655  // Whether pSubItem is nullptr or not, pTransaction DEFINITELY exists
2656  // either way, in the newest inbox.
2657  // Therefore, let's verify whether I'm even responsible for that
2658  // transaction number... (Just because I signed
2659  // the instrument at some point in the past does NOT mean that I'm still
2660  // responsible for the transaction number
2661  // that's listed on the instrument. Maybe I already used it up a long
2662  // time ago...)
2663  //
2664  if (!theMessageNym.VerifyIssuedNum(strServerID, lIssuedNum)) {
2665  otErr << "OTTransaction::" << __FUNCTION__
2666  << ": Error verifying if transaction num in inbox ("
2667  << pTransaction->GetTransactionNum()
2668  << ") was actually signed out (" << lIssuedNum << ")\n";
2669  return false;
2670  }
2671 
2672  // NOTE: the above check to VerifyIssuedNum... in the case of
2673  // basketReceipts and finalReceipts, lIssuedNum is the CLOSING num
2674  // (this is already done.)
2675  // With marketReceipts and paymentReceipts, they check for the existence
2676  // of a FINAL receipt, and if it's there, they use its CLOSING
2677  // NUM. Otherwise they use the "in reference to" num. With final
2678  // receipts it uses its CLOSING NUM, since the original is
2679  // presumed closed.
2680 
2681  } // for
2682 
2683  // BY THIS POINT, I have lReceiptBalanceChange with the total change in the
2684  // receipt, and
2685  // lInboxBalanceChange with the total change in the new inbox. The
2686  // difference between the two
2687  // is the difference I should expect also in the account balances! That
2688  // amount should also
2689  // be equal to lInboxSupposedDifference, which is the total of JUST the
2690  // inbox receipts that
2691  // I DIDN'T find in the old receipt (they were ONLY in the new inbox.)
2692  //
2693  // I have looped through all inbox items, and I know they were either found
2694  // in the receipt's inbox record
2695  // (and verified), or their amounts were added to lInboxSupposedDifference
2696  // as appropriate.
2697  //
2698  // I also verified, for each inbox item, IF IT TAKES MONEY, THEN IT MUST
2699  // HAVE A TRANSACTION NUMBER
2700  // SIGNED OUT TO ME... Otherwise I could dispute it. The last code above
2701  // verifies this.
2702  //
2703  // All that's left is to make sure the balance is right...
2704  //
2705 
2706  // VERIFY ACCOUNT BALANCE (RECONCILING WITH NEW INBOX RECEIPTS)
2707 
2708  // lReceiptBalanceChange -- The balance of all the inbox items on the
2709  // receipt (at least, the items that change the balance.)
2710  // lInboxBalanceChange -- The balance of all the inbox items in the
2711  // inbox (at least, the items that change the balance.)
2712  // lInboxSupposedDifference -- The balance of all the inbox items in the
2713  // inbox that were NOT found in the receipt (that change balance.)
2714  // lAbsoluteDifference -- The absolute difference between the inbox
2715  // balance and the receipt balance. (Always positive.)
2716  // lAbsoluteDifference -- The balance of all the inbox items
2717  // (including new items) minus the old ones that were on the receipt.
2718 
2719  // (Helping me to visualize lInboxBalanceChange and lReceiptBalanceChange)
2720  // ACTUAL SIMPLE ADD/SUBTRACT ADD/ABS
2721  // -5 -100 difference == 95 (-5 + -100 == -105) 105
2722  // 5 100 difference == 95 ( 5 + 100 == 105) 105
2723  // -5 100 difference == 105 (-5 + 100 == 95) 95
2724  // 5 -100 difference == 105 ( 5 + -100 == -95) 95
2725 
2726  // -100 -5 difference == 95 (-100 + -5 == -105) 105
2727  // 100 -5 difference == 105 ( 100 + -5 == 95) 95
2728  // -100 5 difference == 105 (-100 + 5 == -95) 95
2729  // 100 5 difference == 95 ( 100 + 5 == 105) 105
2730 
2731  // Above == wrong, Below == right.
2732 
2733  // ***SUBTRACT/ABS***
2734  // -5 -100 difference == 95 (-5 - -100 == 95) 95 *
2735  // 5 100 difference == 95 ( 5 - 100 == -95) 95 *
2736  // -5 100 difference == 105 (-5 - 100 == -105) 105 *
2737  // 5 -100 difference == 105 ( 5 - -100 == 105) 105 *
2738 
2739  // -100 -5 difference == 95 (-100 - -5 == -95) 95 *
2740  // 100 -5 difference == 105 ( 100 - -5 == 105) 105 *
2741  // -100 5 difference == 105 (-100 - 5 == -105) 105 *
2742  // 100 5 difference == 95 ( 100 - 5 == 95) 95 *
2743 
2744  // Based on the above table, the solution is to subtract one value from the
2745  // other,
2746  // and then take the absolute of that to get the actual difference. Then use
2747  // an
2748  // 'if' statement to see which was larger, and based on that, calculate
2749  // whether the
2750  // balance is what would be expected.
2751  //
2752  // -1099 // -99 (example of 1000 absolute difference)
2753 
2754  // How much money came out? (Or went in, if the chequeReceipt was for
2755  // an invoice...) 901 -99 (example of 1000 absolute difference)
2756  const int64_t lAbsoluteDifference =
2757  std::abs(lInboxBalanceChange - lReceiptBalanceChange);
2758  const int64_t lNegativeDifference = (lAbsoluteDifference * (-1));
2759 
2760  // The new (current) inbox has a larger overall value than the balance in
2761  // the old (receipt) inbox. (As shown by subitem.)
2762  const bool bNewInboxWasBigger =
2763  ((lInboxBalanceChange > lReceiptBalanceChange) ? true : false);
2764  const bool bNewInboxWasSmaller =
2765  ((lInboxBalanceChange < lReceiptBalanceChange) ? true : false);
2766 
2767  int64_t lActualDifference;
2768 
2769  if (bNewInboxWasBigger)
2770  lActualDifference = lAbsoluteDifference;
2771  else if (bNewInboxWasSmaller)
2772  lActualDifference = lNegativeDifference;
2773  else
2774  lActualDifference = 0;
2775 
2776  /*
2777  Example for logic:
2778 
2779  Old Inbox on Receipt:
2780  10
2781  15
2782  40
2783  lReceiptBalanceChange: 65
2784  Old Balance (in addition to these inbox items): 1000 (total 1065)
2785 
2786  New Inbox scenario A:
2787  10
2788  15
2789  40
2790  20 (lInboxSupposedDifference==(20)) 20
2791  lInboxBalanceChange: 85
2792 
2793  New Inbox scenario B:
2794  10
2795  15
2796  40
2797  -20 (lInboxSupposedDifference==(-20)) -20
2798  lInboxBalanceChange: 45
2799 
2800 
2801  Inbox A: lAbsoluteDifference=abs(85-65)==abs( 20)==20
2802  Inbox B: lAbsoluteDifference=abs(45-65)==abs(-20)==20
2803 
2804  Inbox A: lNegativeDifference == -20
2805  Inbox B: lNegativeDifference == -20
2806 
2807  Inbox A: bNewInboxWasBigger == TRUE,
2808  bNewInboxWasSmaller == FALSE
2809 
2810  Inbox B: bNewInboxWasBigger == FALSE,
2811  bNewInboxWasSmaller == TRUE
2812 
2813 
2814 
2815  if (
2816  (bNewInboxWasBigger && (lAbsoluteDifference !=
2817  lInboxSupposedDifference)) || // lInboxSupposedDifference should be
2818  positive here.
2819  (bNewInboxWasSmaller && (lNegativeDifference !=
2820  lInboxSupposedDifference)) // lInboxSupposedDifference should be
2821  negative here.
2822  )
2823 
2824  Inbox A:
2825  if (
2826  (TRUE && (20 != 20)) || // lInboxSupposedDifference should be
2827  positive here. ***
2828  (FALSE && (-20 != 20)) // lInboxSupposedDifference should be
2829  negative here.
2830  )
2831 
2832  Inbox B:
2833  if (
2834  (FALSE && (20 != -20)) || // lInboxSupposedDifference should be
2835  positive here.
2836  (TRUE && (-20 != -20)) // lInboxSupposedDifference should be
2837  negative here. ***
2838  )
2839 
2840  ---------------
2841  if (
2842  (lActualDifference != lInboxSupposedDifference)
2843  )
2844 
2845  Inbox A (bigger): (lActualDifference is lAbsoluteDifference)
2846  if ( 20 != 20)
2847 
2848  Inbox B (smaller): (lActualDifference is lNegativeDifference)
2849  if (-20 != -20)
2850 
2851  */
2852 
2853  // If the actual difference between the two totals is not equal to the
2854  // supposed difference from adding up just the new receipts,
2855  // (Which is probably impossible anyway) then return false.
2856  if (lActualDifference != lInboxSupposedDifference) {
2857  otErr << "OTTransaction::" << __FUNCTION__ << ": lActualDifference ("
2858  << lActualDifference
2859  << ") is not equal to lInboxSupposedDifference ("
2860  << lInboxSupposedDifference
2861  << ")\n"
2862  "FYI, Inbox balance on old receipt: " << lReceiptBalanceChange
2863  << " Inbox balance on current inbox: " << lInboxBalanceChange
2864  << "\n";
2865  return false;
2866  }
2867 
2868  // if, according to the two inboxes, they are different (in terms of how
2869  // they would impact balance),
2870  // then therefore, they must have impacted my balance. THEREFORE, my old
2871  // balance MUST be equivalent to
2872  // the current (apparently new) balance, PLUS OR MINUS THE DIFFERENCE,
2873  // ACCORDING TO THE DIFFERENCE BETWEEN THE INBOXES.
2874  // If the actual difference (according to inbox receipts) + actual account
2875  // balance (according to newest copy of account)
2876  // is not equal to the last signed balance agreement, then return false.
2877  //
2878  /*
2879  if (
2880  (bNewInboxWasBigger && (pBalanceItem->GetAmount() !=
2881  (THE_ACCOUNT.GetBalance() + lNegativeDifference))) ||
2882  (bNewInboxWasSmaller && (pBalanceItem->GetAmount() !=
2883  (THE_ACCOUNT.GetBalance() + lAbsoluteDifference)))
2884  )
2885 
2886  Inbox A (bigger):
2887  if (
2888  (TRUE && (1000 != (1020 + -20))) ||
2889  (FALSE && (1000 != (1020 + 20)))
2890  )
2891  ---
2892  Inbox B (smaller):
2893  if (
2894  (FALSE && (1000 != (980 + -20))) ||
2895  (TRUE && (1000 != (980 + 20)))
2896  )
2897  ---------------------------------------------------------------------
2898 
2899  if (pBalanceItem->GetAmount() != (THE_ACCOUNT.GetBalance() +
2900  (lActualDifference*(-1))))
2901 
2902  Inbox A (bigger):
2903  if (1000 != (1020 + -20))
2904 
2905  Inbox B (smaller):
2906  if (1000 != (980 + 20))
2907  */
2908 
2909  if (pBalanceItem->GetAmount() !=
2910  (THE_ACCOUNT.GetBalance() + (lActualDifference * (-1)))) {
2911  // Let's say ActualDifference == 10-3 (prev balance minus current
2912  // balance) == 7.
2913  // If that's the case, then 7 + THE_ACCT.Balance should equal 10 again
2914  // from the last balance statement!
2915 
2916  otErr << "OTTransaction::" << __FUNCTION__
2917  << ": lActualDifference in receipts (" << lActualDifference
2918  << ") "
2919  "plus current acct balance (" << THE_ACCOUNT.GetBalance()
2920  << ") is NOT equal to last signed balance ("
2921  << pBalanceItem->GetAmount() << ")\n";
2922  return false;
2923  }
2924 
2925  // At this point: all good!
2926  //
2927 
2928  return true;
2929 }
2930 
2931 // This doesn't actually delete the box receipt, per se.
2932 // Instead, it adds the string "MARKED_FOR_DELETION" to the bottom
2933 // of the file, so the sysadmin can delete later, at his leisure.
2934 //
2936 {
2937  OTString strFolder1name, strFolder2name, strFolder3name, strFilename;
2938 
2940  theLedger, *this, "OTTransaction::DeleteBoxReceipt", strFolder1name,
2941  strFolder2name, strFolder3name, strFilename))
2942  return false; // This already logs -- no need to log twice, here.
2943 
2944  // See if the box receipt exists before trying to save over it...
2945  //
2946  if (!OTDB::Exists(strFolder1name.Get(), strFolder2name.Get(),
2947  strFolder3name.Get(), strFilename.Get())) {
2948  otInfo
2949  << __FUNCTION__
2950  << ": Box receipt already doesn't exist, thus no need to delete: "
2951  "At location: " << strFolder1name << OTLog::PathSeparator()
2952  << strFolder2name << OTLog::PathSeparator() << strFolder3name
2953  << OTLog::PathSeparator() << strFilename << "\n";
2954  return false;
2955  }
2956 
2957  OTString strFinal;
2958  OTASCIIArmor ascTemp;
2959 
2960  if (m_strRawFile.Exists()) {
2961  ascTemp.SetString(m_strRawFile);
2962 
2963  if (false ==
2964  ascTemp.WriteArmoredString(strFinal, m_strContractType.Get())) {
2965  otErr << __FUNCTION__
2966  << ": Error deleting (writing over) box receipt (failed "
2967  "writing armored string):\n" << strFolder1name
2968  << OTLog::PathSeparator() << strFolder2name
2969  << OTLog::PathSeparator() << strFolder3name
2970  << OTLog::PathSeparator() << strFilename << "\n";
2971  return false;
2972  }
2973  }
2974 
2975  // NOTE: I do the armored string FIRST, THEN add the "marked for deletion"
2976  // part as I save it. (This way, it's still searchable with grep.)
2977 
2978  //
2979  // Try to save the deleted box receipt to local storage.
2980  //
2981  OTString strOutput;
2982 
2983  if (m_strRawFile.Exists())
2984  strOutput.Format("%s\n\n%s\n", strFinal.Get(),
2985  "MARKED_FOR_DELETION"); // todo hardcoded.
2986  else
2987  strOutput.Format("%s\n\n%s\n",
2988  "(Transaction was already empty -- strange.)",
2989  "MARKED_FOR_DELETION"); // todo hardcoded.
2990 
2991  bool bDeleted = OTDB::StorePlainString(
2992  strOutput.Get(), strFolder1name.Get(), strFolder2name.Get(),
2993  strFolder3name.Get(), strFilename.Get());
2994  if (!bDeleted)
2995  otErr << __FUNCTION__
2996  << ": Error deleting (writing over) file: " << strFolder1name
2997  << OTLog::PathSeparator() << strFolder2name
2998  << OTLog::PathSeparator() << strFolder3name
2999  << OTLog::PathSeparator() << strFilename << "\nContents:\n\n"
3000  << m_strRawFile << "\n\n";
3001 
3002  return bDeleted;
3003 }
3004 
3005 bool OTTransaction::SaveBoxReceipt(int64_t lLedgerType)
3006 {
3007 
3008  if (IsAbbreviated()) {
3009  otOut << __FUNCTION__ << ": Unable to save box receipt "
3010  << GetTransactionNum()
3011  << ": "
3012  "This transaction is the abbreviated version (box receipt is "
3013  "supposed to "
3014  "consist of the full version, so we can't save THIS as the "
3015  "box receipt.)\n";
3016  return false;
3017  }
3018 
3019  OTString strFolder1name, strFolder2name, strFolder3name, strFilename;
3020 
3022  lLedgerType, *this, "OTTransaction::SaveBoxReceipt", strFolder1name,
3023  strFolder2name, strFolder3name, strFilename))
3024  return false; // This already logs -- no need to log twice, here.
3025 
3026  // See if the box receipt exists before trying to save over it...
3027  //
3028  if (OTDB::Exists(strFolder1name.Get(), strFolder2name.Get(),
3029  strFolder3name.Get(), strFilename.Get())) {
3030  otOut << __FUNCTION__
3031  << ": Warning -- Box receipt already exists! (Overwriting)"
3032  "At location: " << strFolder1name << OTLog::PathSeparator()
3033  << strFolder2name << OTLog::PathSeparator() << strFolder3name
3034  << OTLog::PathSeparator() << strFilename << "\n";
3035  // return false;
3036  }
3037 
3038  // Try to save the box receipt to local storage.
3039  //
3040  OTString strFinal;
3041  OTASCIIArmor ascTemp(m_strRawFile);
3042 
3043  if (false ==
3044  ascTemp.WriteArmoredString(strFinal, m_strContractType.Get())) {
3045  otErr << __FUNCTION__
3046  << ": Error saving box receipt (failed writing armored string):\n"
3047  << strFolder1name << OTLog::PathSeparator() << strFolder2name
3048  << OTLog::PathSeparator() << strFolder3name
3049  << OTLog::PathSeparator() << strFilename << "\n";
3050  return false;
3051  }
3052 
3053  bool bSaved = OTDB::StorePlainString(
3054  strFinal.Get(), strFolder1name.Get(), strFolder2name.Get(),
3055  strFolder3name.Get(), strFilename.Get());
3056 
3057  if (!bSaved)
3058  otErr << __FUNCTION__ << ": Error writing file: " << strFolder1name
3059  << OTLog::PathSeparator() << strFolder2name
3060  << OTLog::PathSeparator() << strFolder3name
3061  << OTLog::PathSeparator() << strFilename << "\nContents:\n\n"
3062  << m_strRawFile << "\n\n";
3063 
3064  return bSaved;
3065 }
3066 
3067 // This function assumes that theLedger is the owner of this transaction.
3068 // We pass the ledger in so we can determine the proper directory we're
3069 // reading from.
3071 {
3072  int64_t lLedgerType = 0;
3073 
3074  switch (theLedger.GetType()) {
3075  case OTLedger::nymbox:
3076  lLedgerType = 0;
3077  break;
3078  case OTLedger::inbox:
3079  lLedgerType = 1;
3080  break;
3081  case OTLedger::outbox:
3082  lLedgerType = 2;
3083  break;
3084  // case OTLedger::message: lLedgerType = 3; break;
3086  lLedgerType = 4;
3087  break;
3088  case OTLedger::recordBox:
3089  lLedgerType = 5;
3090  break;
3091  case OTLedger::expiredBox:
3092  lLedgerType = 6;
3093  break;
3094  default:
3095  otErr << "OTTransaction::SaveBoxReceipt: Error: unknown box type. "
3096  "(This should never happen.)\n";
3097  return false;
3098  }
3099  return SaveBoxReceipt(lLedgerType);
3100 }
3101 
3103 {
3104  if (!m_bIsAbbreviated || theFullVersion.IsAbbreviated()) {
3105  otErr << "OTTransaction::" << __FUNCTION__
3106  << ": Failure: This transaction "
3107  "isn't abbreviated (val: "
3108  << (m_bIsAbbreviated ? "IS" : "IS NOT")
3109  << "), or the purported full version erroneously is (val: "
3110  << (theFullVersion.IsAbbreviated() ? "IS" : "IS NOT")
3111  << "). "
3112  "Either way, you can't use it in this way, for trans num: "
3113  << GetTransactionNum() << "\n";
3114  return false;
3115  }
3116 
3117  // VERIFY THE HASH
3118  //
3119  OTIdentifier idFullVersion; // Generate a message digest of that string.
3120  theFullVersion.CalculateContractID(idFullVersion);
3121 
3122  // Abbreviated version (*this) stores a hash of the original full version.
3123  // Sooo... let's hash the purported "full version" that was passed in, and
3124  // compare it to the stored one.
3125  //
3126  if (m_Hash != idFullVersion) {
3127  otErr << "OTTransaction::" << __FUNCTION__
3128  << ": Failure: The purported 'full version' of the transaction, "
3129  "passed in for verification fails to match the stored hash "
3130  "value for trans num: " << GetTransactionNum() << "\n";
3131  return false;
3132  }
3133 
3134  // BY THIS POINT, we already know it's a definite match.
3135  // But we check a few more things, just to be safe.
3136  // Such as the TRANSACTION NUMBER...
3137  if (GetTransactionNum() != theFullVersion.GetTransactionNum()) {
3138  otErr << "OTTransaction::" << __FUNCTION__
3139  << ": Failure: The purported 'full version' of the transaction "
3140  "passed in (number " << theFullVersion.GetTransactionNum()
3141  << ") fails to match the actual transaction number: "
3142  << GetTransactionNum() << "\n";
3143  return false;
3144  }
3145 
3146  // THE "IN REFERENCE TO" NUMBER (DISPLAY VERSION)
3147  if (GetAbbrevInRefDisplay() != theFullVersion.GetReferenceNumForDisplay()) {
3148  otErr << "OTTransaction::" << __FUNCTION__
3149  << ": Failure: The purported 'full version' of the transaction "
3150  "passed, GetReferenceNumForDisplay() ("
3151  << theFullVersion.GetReferenceNumForDisplay()
3152  << ") fails to match the GetAbbrevInRefDisplay ("
3153  << GetAbbrevInRefDisplay() << ") on this.\n";
3154  return false;
3155  }
3156 
3157  return true;
3158 }
3159 
3160 // When the items are first loaded up, VerifyContractID() is called on them.
3161 // Therefore, the serverID and account ID have already been verified.
3162 // Now I want to go deeper, before actually processing a transaction, and
3163 // make sure that the items on it also have the right owner, as well as that
3164 // owner's signature, and a matching transaction number to boot.
3165 //
3167 {
3168  const OTIdentifier NYM_ID(theNym);
3169 
3170  if (NYM_ID != GetUserID()) {
3171  otErr << "Wrong owner passed to OTTransaction::VerifyItems\n";
3172  return false;
3173  }
3174 
3175  // I'm not checking signature on transaction itself since that is already
3176  // checked before this function is called. But I AM calling Verify Owner,
3177  // so that when Verify Owner is called in the loop below, it proves the
3178  // items
3179  // and the transaction both have the same owner: Nym.
3180 
3181  // if pointer not null, and it's a withdrawal, and it's an acknowledgement
3182  // (not a rejection or error)
3183  //
3184  for (auto& it : GetItemList()) {
3185  // loop through the ALL items that make up this transaction and check
3186  // to see if a response to deposit.
3187  OTItem* pItem = it;
3188  OT_ASSERT(nullptr != pItem);
3189 
3190  if (GetTransactionNum() != pItem->GetTransactionNum()) return false;
3191 
3192  if (NYM_ID != pItem->GetUserID()) return false;
3193 
3194  if (!pItem->VerifySignature(theNym)) // NO need to call
3195  // VerifyAccount since
3196  // VerifyContractID is
3197  // ALREADY called and now
3198  // here's
3199  // VerifySignature().
3200  return false;
3201  }
3202 
3203  return true;
3204 }
3205 
3206 /*
3207 bool m_bIsAbbreviated;
3208 int64_t m_lAbbrevAmount;
3209 int64_t m_lDisplayAmount;
3210 OTIdentifier m_Hash; // todo: make this const and force it to
3211 be set during construction.
3212 time64_t m_DATE_SIGNED; // The date, in seconds, when the
3213 instrument was last signed.
3214 transactionType m_Type; // blank, pending, processInbox,
3215 transfer, deposit, withdrawal, trade, etc.
3216 */
3217 
3218 // private and hopefully not needed
3219 //
3221  : OTTransactionType()
3222  , m_pParent(nullptr)
3223  , m_bIsAbbreviated(false)
3224  , m_lAbbrevAmount(0)
3225  , m_lDisplayAmount(0)
3226  , m_lInRefDisplay(0)
3227  , m_DATE_SIGNED(OT_TIME_ZERO)
3228  , m_Type(OTTransaction::error_state)
3229  , m_lClosingTransactionNo(0)
3230  , m_lRequestNumber(0)
3231  , m_bReplyTransSuccess(false)
3232  , m_bCancelled(false)
3233 {
3234  InitTransaction();
3235 }
3236 
3237 // Let's say you never knew their UserID, you just loaded the inbox based on
3238 // AccountID.
3239 // Now you want to add a transaction to that inbox. Just pass the inbox into the
3240 // transaction constructor (below) and it will get the rest of the info it needs
3241 // off of
3242 // the inbox itself (which you presumably just read from a file or socket.)
3243 //
3245  : OTTransactionType(theOwner.GetUserID(), theOwner.GetPurportedAccountID(),
3246  theOwner.GetPurportedServerID())
3247  , m_pParent(&theOwner)
3248  , m_bIsAbbreviated(false)
3249  , m_lAbbrevAmount(0)
3250  , m_lDisplayAmount(0)
3251  , m_lInRefDisplay(0)
3252  , m_DATE_SIGNED(OT_TIME_ZERO)
3253  , m_Type(OTTransaction::error_state)
3254  , m_lClosingTransactionNo(0)
3255  , m_lRequestNumber(0)
3256  , m_bReplyTransSuccess(false)
3257  , m_bCancelled(false)
3258 {
3259  InitTransaction();
3260 }
3261 
3262 // By calling this function, I'm saying "I know the real account ID and Server
3263 // ID, and here
3264 // they are, and feel free to compare them with whatever YOU load up, which
3265 // we'll leave
3266 // blank for now unless you generate a transaction, or load one up,
3267 
3268 // ==> or maybe I might need to add a constructor where another transaction or a
3269 // ledger is passed in.
3270 // Then it can grab whatever it needs from those. I'm doing something
3271 // similar in OTItem
3273  const OTIdentifier& theAccountID,
3274  const OTIdentifier& theServerID)
3275  : OTTransactionType(theUserID, theAccountID, theServerID)
3276  , m_pParent(nullptr)
3277  , m_bIsAbbreviated(false)
3278  , m_lAbbrevAmount(0)
3279  , m_lDisplayAmount(0)
3280  , m_lInRefDisplay(0)
3281  , m_DATE_SIGNED(OT_TIME_ZERO)
3282  , m_Type(OTTransaction::error_state)
3283  , m_lClosingTransactionNo(0)
3284  , m_lRequestNumber(0)
3285  , m_bReplyTransSuccess(false)
3286  , m_bCancelled(false)
3287 {
3288  InitTransaction();
3289 
3290  // m_AcctID = theID; // these must be loaded or generated. NOT
3291  // set in constructor, for security reasons.
3292  // m_ServerID = theServerID; // There are only here in ghostly form
3293  // as a WARNING to you!
3294 }
3295 
3297  const OTIdentifier& theAccountID,
3298  const OTIdentifier& theServerID,
3299  int64_t lTransactionNum)
3300  : OTTransactionType(theUserID, theAccountID, theServerID, lTransactionNum)
3301  , m_pParent(nullptr)
3302  , m_bIsAbbreviated(false)
3303  , m_lAbbrevAmount(0)
3304  , m_lDisplayAmount(0)
3305  , m_lInRefDisplay(0)
3306  , m_DATE_SIGNED(OT_TIME_ZERO)
3307  , m_Type(OTTransaction::error_state)
3308  , m_lClosingTransactionNo(0)
3309  , m_lRequestNumber(0)
3310  , m_bReplyTransSuccess(false)
3311  , m_bCancelled(false)
3312 {
3313  InitTransaction();
3314 
3315  // m_lTransactionNum = lTransactionNum; // This is set in
3316  // OTTransactionType's constructor, as are m_ID and m_ServerID
3317  // m_AcctID = theID; // these must be loaded or
3318  // generated. NOT set in constructor, for security reasons.
3319  // m_ServerID = theServerID; // There are only here in
3320  // ghostly form as a WARNING to you!
3321 }
3322 
3323 // all common OTTransaction stuff goes here.
3324 // (I don't like constructor loops, prefer to use a separate function they all
3325 // call.)
3327 {
3328  m_strContractType = "TRANSACTION"; // CONTRACT, MESSAGE, TRANSACTION,
3329  // LEDGER, TRANSACTION ITEM
3330  m_DATE_SIGNED = OT_TIME_ZERO; // Make sure to set this to the current time
3331  // whenever contract is signed.
3334  m_lRequestNumber = 0;
3335  m_bReplyTransSuccess = false;
3336 }
3337 
3338 // This CONSTRUCTOR is used for instantiating "abbreviated" transactions,
3339 // each of which separately load their full contents from a separate datafile
3340 // not during loading but during the subsequent verification process.
3341 // See: bool OTTransaction::VerifyItems(OTPseudonym& theNym)
3342 //
3344  const OTIdentifier& theUserID, const OTIdentifier& theAccountID,
3345  const OTIdentifier& theServerID, const int64_t& lNumberOfOrigin,
3346  const int64_t& lTransactionNum, const int64_t& lInRefTo,
3347  const int64_t& lInRefDisplay, time64_t the_DATE_SIGNED,
3348  transactionType theType, const OTString& strHash,
3349  const int64_t& lAdjustment, const int64_t& lDisplayValue,
3350  const int64_t& lClosingNum, const int64_t& lRequestNum,
3351  bool bReplyTransSuccess, OTNumList* pNumList)
3352  : OTTransactionType(theUserID, theAccountID, theServerID, lTransactionNum)
3353  , m_pParent(nullptr)
3354  , m_bIsAbbreviated(true)
3355  , m_lAbbrevAmount(lAdjustment)
3356  , m_lDisplayAmount(lDisplayValue)
3357  , m_lInRefDisplay(lInRefDisplay)
3358  , m_Hash(strHash)
3359  , m_DATE_SIGNED(the_DATE_SIGNED)
3360  , m_Type(theType)
3361  , m_lClosingTransactionNo(lClosingNum)
3362  , m_lRequestNumber(lRequestNum)
3363  , m_bReplyTransSuccess(bReplyTransSuccess)
3364  , m_bCancelled(false)
3365 {
3366  InitTransaction();
3367 
3368  // This gets zeroed out in InitTransaction() above. But since we set it in
3369  // this
3370  // constructor, I'm setting it back again.
3371  // Then why call it? I don't know, convention? For the sake of future
3372  // subclasses?
3373  //
3374  m_bIsAbbreviated = true;
3375  m_DATE_SIGNED = the_DATE_SIGNED;
3376  m_Type = theType; // This one is same story as date signed. Setting it back.
3377  m_lClosingTransactionNo = lClosingNum;
3378  m_lAbbrevAmount = lAdjustment;
3379  m_lDisplayAmount = lDisplayValue;
3380  m_lInRefDisplay = lInRefDisplay;
3381 
3382  m_lRequestNumber = lRequestNum; // for replyNotice
3383  m_bReplyTransSuccess = bReplyTransSuccess; // for replyNotice
3384 
3385  m_Hash.SetString(strHash);
3386  m_lTransactionNum = lTransactionNum; // This is set in OTTransactionType's
3387  // constructor, as are m_ID and
3388  // m_ServerID
3389 
3390  SetReferenceToNum(lInRefTo);
3391  SetNumberOfOrigin(lNumberOfOrigin);
3392 
3393  // NOTE: For THIS CONSTRUCTOR ONLY, we DO set the purported AcctID and
3394  // purported ServerID.
3395  // (AFTER the constructor has executed, in OTLedger::ProcessXMLNode();
3396  //
3397  // WHY? Normally you set the "real" IDs at construction, and then set the
3398  // "purported" IDs
3399  // when loading from string. But this constructor (only this one) is
3400  // actually used when
3401  // loading abbreviated receipts as you load their inbox/outbox/nymbox.
3402  // Abbreviated receipts are not like real transactions, which have serverID,
3403  // AcctID, userID,
3404  // and signature attached, and the whole thing is base64-encoded and then
3405  // added to the ledger
3406  // as part of a list of contained objects. Rather, with abbreviated
3407  // receipts, there are a series
3408  // of XML records loaded up as PART OF the ledger itself. None of these
3409  // individual XML records
3410  // has its own signature, or its own record of the main IDs -- those are
3411  // assumed to be on the parent
3412  // ledger.
3413  // That's the whole point: abbreviated records don't store redundant info,
3414  // and don't each have their
3415  // own signature, because we want them to be as small as possible inside
3416  // their parent ledger.
3417  // Therefore I will pass in the parent ledger's "real" IDs at construction,
3418  // and immediately thereafter
3419  // set the parent ledger's "purported" IDs onto the abbreviated transaction.
3420  // That way, VerifyContractID()
3421  // will still work and do its job properly with these abbreviated records.
3422 
3423  // Note: I'm going to go ahead and set it in here for now. This is a special
3424  // constructor (abbreviated receipt constructor)
3425  // todo: come back to this during security sweep.
3426  //
3427  SetRealAccountID(theAccountID);
3428  SetPurportedAccountID(theAccountID);
3429 
3430  SetRealServerID(theServerID);
3431  SetPurportedServerID(theServerID);
3432 
3433  SetUserID(theUserID);
3434 
3435  if (nullptr != pNumList) m_Numlist = *pNumList;
3436 }
3437 
3438 // bool GenerateTransaction(const OTIdentifier& theAccountID, const
3439 // OTIdentifier& theServerID, int64_t lTransactionNum);
3440 //
3441 // static
3442 // OTTransaction * GenerateTransaction(const OTIdentifier& theUserID, const
3443 // OTIdentifier& theAccountID,
3444 // const OTIdentifier& theServerID,
3445 // transactionType theType,
3446 // int64_t lTransactionNum=0);
3447 // static
3448 // OTTransaction * GenerateTransaction(const OTLedger& theOwner,
3449 // transactionType theType, int64_t lTransactionNum=0);
3450 
3451 // static
3453  transactionType theType,
3454  int64_t lTransactionNum)
3455 {
3456  OTTransaction* pTransaction = GenerateTransaction(
3457  theOwner.GetUserID(), theOwner.GetPurportedAccountID(),
3458  theOwner.GetPurportedServerID(), theType, lTransactionNum);
3459  if (nullptr != pTransaction) pTransaction->SetParent(theOwner);
3460 
3461  return pTransaction;
3462 }
3463 
3464 // static
3466  const OTIdentifier& theUserID, const OTIdentifier& theAccountID,
3467  const OTIdentifier& theServerID, transactionType theType,
3468  int64_t lTransactionNum)
3469 {
3470  OTTransaction* pTransaction = new OTTransaction(
3471  theUserID, theAccountID, theServerID, lTransactionNum);
3472  OT_ASSERT(nullptr != pTransaction);
3473 
3474  pTransaction->m_Type = theType;
3475 
3476  // Since we're actually generating this transaction, then we can go ahead
3477  // and set the purported account and server IDs (we have already set the
3478  // real ones in the constructor). Now both sets are fill with matching data.
3479  // No need to security check the IDs since we are creating this transaction
3480  // versus loading and inspecting it.
3481  pTransaction->SetPurportedAccountID(theAccountID);
3482  pTransaction->SetPurportedServerID(theServerID);
3483 
3484  return pTransaction;
3485 }
3486 
3487 bool OTTransaction::SaveContractWallet(std::ofstream&) const
3488 {
3489  return true;
3490 }
3491 
3493 {
3494  while (!m_listItems.empty()) {
3495  OTItem* pItem = m_listItems.front();
3496  m_listItems.pop_front();
3497  delete pItem;
3498  }
3499 }
3500 
3502 {
3503  while (!m_listItems.empty()) {
3504  OTItem* pItem = m_listItems.front();
3505  m_listItems.pop_front();
3506  delete pItem;
3507  }
3508 
3510 }
3511 
3512 // You have to allocate the item on the heap and then pass it in as a reference.
3513 // OTTransaction will take care of it from there and will delete it in
3514 // destructor.
3516 {
3517  m_listItems.push_back(&theItem);
3518 }
3519 
3520 // While processing a transaction, you may wish to query it for items of a
3521 // certain type.
3523 {
3524  for (auto& it : m_listItems) {
3525  OTItem* pItem = it;
3526  OT_ASSERT(nullptr != pItem);
3527 
3528  if (pItem->GetType() == theType) return pItem;
3529  }
3530 
3531  return nullptr;
3532 }
3533 
3534 // While processing a transaction, you may wish to query it for items in
3535 // reference to a particular transaction number.
3536 //
3538 {
3539  if (GetItemCountInRefTo(lReference) > 1) {
3540  OT_FAIL_MSG("CAN'T USE GetItemInRefTo! (There are multiple items in "
3541  "reference to the same number...) SWITCH to using "
3542  "NumberOfOrigin?");
3543  }
3544 
3545  for (auto& it : m_listItems) {
3546  OTItem* pItem = it;
3547  OT_ASSERT(nullptr != pItem);
3548 
3549  if (pItem->GetReferenceToNum() == lReference) return pItem;
3550  }
3551 
3552  return nullptr;
3553 }
3554 
3555 // Count the number of items that are IN REFERENCE TO some transaction#.
3556 //
3557 // Might want to change this so that it only counts ACCEPTED receipts.
3558 //
3559 int32_t OTTransaction::GetItemCountInRefTo(int64_t lReference)
3560 {
3561  int32_t nCount = 0;
3562 
3563  for (auto& it : m_listItems) {
3564  OTItem* pItem = it;
3565  OT_ASSERT(nullptr != pItem);
3566 
3567  if (pItem->GetReferenceToNum() == lReference) nCount++;
3568  }
3569 
3570  return nCount;
3571 }
3572 
3573 /*
3574  a processNymbox transaction has a list of items--each one accepting a nymbox
3575  receipt (ottransaction) so as to remove it from the nymbox. It also has a
3576  transaction statement item, which must verify in order for the others to run.
3577 
3578  Here are the types of items:
3579 case OTItem::acceptFinalReceipt:
3580  theReplyItemType = OTItem::atAcceptFinalReceipt;
3581  break;
3582 case OTItem::acceptTransaction:
3583  theReplyItemType = OTItem::atAcceptTransaction;
3584  break;
3585 case OTItem::acceptMessage:
3586  theReplyItemType = OTItem::atAcceptMessage;
3587  break;
3588 case OTItem::acceptNotice:
3589  theReplyItemType = OTItem::atAcceptNotice;
3590  break;
3591 
3592  */
3593 
3594 // OTTransaction::GetSuccess()
3595 //
3596 // Tries to determine, based on items within, whether it was a success or fail.
3597 //
3598 // DONE:
3599 //
3600 // What about a processNymbox message? ALL of its items must be successful,
3601 // for any of them to be (for the transaction statement to make any sense....)
3602 //
3603 // What I NEED to do , in case of atProcessNymbox and maybe others, is loop
3604 // through them ALL and check them ALL for success.
3605 //
3606 // What it does now is, if it sees an item of a certain type, then it
3607 // IMMEDIATELY
3608 // returns success or fail based on its status. Imagine this problem: My
3609 // transaction
3610 // failed (say, due to empty account) but the balance statement itself had
3611 // succeeded
3612 // before it got to that point. The below loop as it exists now will see that
3613 // the
3614 // atBalanceStatement was successful, and IMMEDAITELY RETURNS TRUE! (Even if the
3615 // item for the transaction itself had failed.)
3616 //
3617 // In the case of processNymbox it's worse, since the ENTIRE TRANSACTION must
3618 // fail, if
3619 // ANY of its items do. You have to loop them ALL and make sure they are ALL
3620 // success.
3621 // (regardless of their type.) You can only do this if you know *this is a
3622 // processNymbox
3623 // transaction, yet we can clearly see, that the below code is simply looping
3624 // the items
3625 // REGARDLESS of what type of transaction *this actually is.
3626 //
3627 // Note: (Below is now fixed.)
3628 // What if, as above, the processNymbox failed, but has a successful transaction
3629 // statement
3630 // as one of its items? The below loop would return true!
3631 //
3632 // This is actually a pretty good argument for using polymorphism for the
3633 // various transaction
3634 // and item types, so these sorts of SWITCH STATEMENTS aren't necessary all over
3635 // the transaction
3636 // and ledger code. Although IMO a default implementation should still cover
3637 // most cases.
3638 //
3639 //
3640 // Tries to determine, based on items within, whether it was a success or fail.
3641 //
3643 {
3644  bool bFoundAnActionItem = false, bFoundABalanceAgreement = false;
3645 
3648  for (auto& it : m_listItems) {
3649  OTItem* pItem = it;
3650  OT_ASSERT(nullptr != pItem);
3651 
3652  switch (pItem->GetType()) {
3653 
3654  // BALANCE AGREEMENT / TRANSACTION STATEMENT
3655 
3656  // Even if one of these is a success, it is only the balance
3657  // agreement for
3658  // the transaction itself, which must also be a success. For
3659  // example, if there
3660  // is a transaction for a cash withdrawal, then it will contain 2
3661  // items: one item
3662  // is the withdrawal itself, and the other item is the balance
3663  // agreement for that
3664  // withdrawal. Therefore, even if the balanace agreement item is
3665  // successful, the
3666  // withdrawal item itself must ALSO be successful, for the
3667  // transaction AS A WHOLE
3668  // to be "successful."
3669  // However, if this balance agreement failed, then the rest of the
3670  // transaction has
3671  // definitely failed as well.
3672  // Therefore, here we either return false, or CONTINUE and let the
3673  // decision be made
3674  // from the other items in this transaction otherwise.
3675  //
3676  case OTItem::atBalanceStatement: // processInbox and
3677  // notarizeTransactions. server's
3678  // reply to a
3679  // balance statement. One of these items appears inside any
3680  // transaction reply.
3681  case OTItem::atTransactionStatement: // processNymbox and also for
3682  // starting/stopping any cron
3683  // items. (notarizeTransactions: payment plan, market offer,
3684  // smart contract, trigger clause, cancel cron item, etc.) The
3685  // server's reply to a transaction statement. Like a balance
3686  // statement, except no asset acct is involved.
3687  //
3688 
3689  if (OTItem::acknowledgement == pItem->GetStatus()) {
3690  bFoundABalanceAgreement = true;
3691  }
3692  else if (OTItem::rejection == pItem->GetStatus()) {
3693  return false;
3694  }
3695  // else continue...
3696  //
3697  continue;
3698 
3699  // PROCESS NYMBOX
3700 
3701  // These are only a success if ALL of them (all of the items
3702  // in this processNymbox transaction) are a success.
3703 
3704  // NOTE: these cases only matter if *this is an atProcessNymbox, and
3705  // in THAT case, it requires ALL items
3706  // to verify, not just the first one of a specific type.
3707  //
3708  //
3709  case OTItem::atAcceptTransaction: // processNymbox. server's reply
3710  // to the Nym's attempt to accept
3711  // (sign for) transaction
3712  // numbers that are sitting in his nymbox (since he requested more
3713  // numbers....)
3714  case OTItem::atAcceptMessage: // processNymbox. server's reply to
3715  // nym's accepting a message (from
3716  // another nym) that's in his nymbox.
3717  case OTItem::atAcceptNotice: // processNymbox. server's reply to
3718  // nym's accepting a notice
3719  // from the server, such as a successNotice (success signing
3720  // out new transaction numbers) or a replyNotice, or an
3721  // instrumentNotice.
3722  // For example, some server replies are dropped into your Nymbox, to
3723  // make sure you receive them. Then you accept them, to remove from
3724  // your Nymbox.
3725 
3726  // PROCESS NYMBOX *and* PROCESS INBOX
3727 
3728  // These are only a success if ALL of them (all of the items
3729  // in this processInbox or processNymbox transaction) are a success.
3730 
3731  case OTItem::atAcceptFinalReceipt: // Part of a processInbox or
3732  // processNymbox transaction
3733  // reply from the server.
3734  case OTItem::atDisputeFinalReceipt: // Would be in processNymbox AND
3735  // processInbox. Can these be
3736  // disputed? Think through the process. Todo.
3737 
3738  // PROCESS INBOX
3739 
3740  // These are only a success if ALL of them (all of the items
3741  // in this processInbox transaction) are a success.
3742 
3743  case OTItem::atAcceptPending: // processInbox. server's reply to
3744  // nym's request to accept an incoming
3745  // pending transfer that's sitting in
3746  // his asset acct's inbox.
3747  case OTItem::atRejectPending: // processInbox. Same thing, except
3748  // rejecting that pending transfer
3749  // instead of accepting it.
3750 
3751  case OTItem::atAcceptCronReceipt: // processInbox. Accepting a
3752  // payment receipt or market
3753  // receipt. (Smart contracts also drop payment receipts,
3754  // currently.)
3755  case OTItem::atDisputeCronReceipt: // processInbox. Dispute. (Todo.)
3756 
3757  case OTItem::atAcceptItemReceipt: // processInbox. Accepting a
3758  // transferReceipt, or
3759  // chequeReceipt, etc.
3760  case OTItem::atDisputeItemReceipt: // processInbox. Dispute. (Todo.)
3761 
3762  case OTItem::atAcceptBasketReceipt: // processInbox. Basket Receipt,
3763  // from a basket currency
3764  // exchange (in or out.)
3765  case OTItem::atDisputeBasketReceipt: // processInbox. dispute basket
3766  // receipt.
3767 
3768  // If we found at least one of these, and nothing fails by the
3769  // end of the loop,
3770  // then for processNymbox and processInbox, it's a success. (If
3771  // balance agreement also...)
3772 
3773  if (OTItem::acknowledgement == pItem->GetStatus()) {
3774  bFoundAnActionItem = true;
3775  }
3776  else if (OTItem::rejection == pItem->GetStatus()) {
3777  return false;
3778  }
3779  // else continue...
3780  //
3781  continue;
3782 
3783  default:
3784  otErr << "Wrong transaction type passed to "
3785  "OTTransaction::GetSuccess() "
3786  "for processNymbox or processInbox transaction.\n";
3787  return false;
3788  } // switch
3789  }
3790 
3791  return (bFoundABalanceAgreement && bFoundAnActionItem);
3792 
3793  } // if processNymbox or processInbox.
3794 
3795  // Okay, it's not a processNymbox or processInbox.
3796  //
3797  // Maybe it's one of these other transaction types...
3798 
3799  for (auto& it : m_listItems) {
3800  OTItem* pItem = it;
3801  OT_ASSERT(nullptr != pItem);
3802 
3803  switch (pItem->GetType()) {
3804  // case OTItem::atServerfee: // Fees currently
3805  // aren't coded. Todo.
3806  // case OTItem::atIssuerfee: // Same as above.
3807  // Todo.
3808 
3809  // BALANCE AGREEMENT / TRANSACTION STATEMENT
3810 
3811  // Even if one of these is a success, it is only the balance agreement
3812  // for
3813  // the transaction itself, which must also be a success. For example, if
3814  // there
3815  // is a transaction for a cash withdrawal, then it will contain 2 items:
3816  // one item
3817  // is the withdrawal itself, and the other item is the balance agreement
3818  // for that
3819  // withdrawal. Therefore, even if the balanace agreement item is
3820  // successful, the
3821  // withdrawal item itself must ALSO be successful, for the transaction
3822  // AS A WHOLE
3823  // to be "successful."
3824  // However, if this balance agreement failed, then the rest of the
3825  // transaction has
3826  // definitely failed as well.
3827  // Therefore, here we either return false, or CONTINUE and let the
3828  // decision be made
3829  // from the other items in this transaction otherwise.
3830  //
3831  case OTItem::atBalanceStatement: // processInbox and
3832  // notarizeTransactions. server's reply
3833  // to a
3834  // balance statement. One of these items appears inside any
3835  // transaction reply.
3836  case OTItem::atTransactionStatement: // processNymbox and also for
3837  // starting/stopping any cron
3838  // items.
3839  // (notarizeTransactions: payment plan, market offer, smart
3840  // contract, trigger clause, cancel cron item, etc.) The server's
3841  // reply to a transaction statement. Like a balance statement,
3842  // except no asset acct is involved.
3843 
3844  if (OTItem::acknowledgement == pItem->GetStatus()) {
3845  bFoundABalanceAgreement = true;
3846  }
3847  if (OTItem::rejection == pItem->GetStatus()) {
3848  return false;
3849  }
3850  // else continue...
3851  //
3852  continue;
3853 
3854  /*
3855  atProcessNymbox, // process nymbox reply // comes from
3856  server
3857  atProcessInbox, // process inbox reply // comes from
3858  server
3859 
3860  // Note: the above two transaction types are handled in the switch
3861  block above this one.
3862  // Whereas the below transaction types are handled right here in this
3863  switch block.
3864 
3865  atTransfer, // reply from the server regarding a transfer
3866  request
3867  atDeposit, // reply from the server regarding a deposit request
3868  atWithdrawal, // reply from the server regarding a withdrawal
3869  request
3870  atMarketOffer, // reply from the server regarding a market offer
3871  atPaymentPlan, // reply from the server regarding a payment plan
3872  atSmartContract, // reply from the server regarding a smart contract
3873  atCancelCronItem, // reply from the server regarding said
3874  cancellation.
3875  atExchangeBasket, // reply from the server regarding said exchange.
3876  */
3877 
3878  // NOTARIZE TRANSACTION
3879  // If any of these are a success, then the transaction as a whole is a
3880  // success also.
3881 
3882  case OTItem::atTransfer: // notarizeTransactions. server's reply to
3883  // nym's request to initiate a transfer
3884 
3885  case OTItem::atWithdrawal: // notarizeTransaction. server's reply to
3886  // withdrawal (cash) request.
3887  case OTItem::atDeposit: // notarizeTransaction. server's reply to
3888  // deposit (cash) request.
3889  case OTItem::atWithdrawVoucher: // notarizeTransaction. server's reply
3890  // to "withdraw voucher" request.
3891  case OTItem::atDepositCheque: // notarizeTransaction. server's reply to
3892  // "deposit cheque" request.
3893  case OTItem::atPayDividend: // notarizeTransaction. server's reply to
3894  // "pay dividend" request.
3895  case OTItem::atMarketOffer: // notarizeTransaction. server's reply to
3896  // request to place a market offer.
3897  case OTItem::atPaymentPlan: // notarizeTransaction. server's reply to
3898  // request to activate a payment plan.
3899  case OTItem::atSmartContract: // notarizeTransaction. server's reply to
3900  // request to activate a smart contract.
3901 
3902  case OTItem::atCancelCronItem: // notarizeTransaction. server's reply to
3903  // request to cancel a [ market offer |
3904  // payment plan | smart contract ]
3905  case OTItem::atExchangeBasket: // notarizeTransaction. server's reply to
3906  // request to exchange in or out of a
3907  // basket currency.
3908 
3909  // RECEIPTS
3910 
3911  // 1. ACTUAL RECEIPTS (item attached to similar transaction), and also
3912  // 2. INBOX REPORT ITEMS (sub-item to ANOTHER item, which is used on
3913  // Balance Agreements and Transaction Statements.)
3914  //
3915  // In case of (1), GetSuccess() is relevant.
3916  // But in case of (2) GetSuccess() is NOT relevant. FYI.
3917  //
3918  // Anyway, if a marketReceipt item is attached to a marketReceipt
3919  // transaction, then we
3920  // can return success or failure right away, since such status is set on
3921  // the item, not
3922  // the transaction, and since there are no other items that matter if
3923  // this IS a success.
3924 
3925  // case OTItem::chequeReceipt: // not needed in OTItem.
3926  // Meaning, actual OTTransaction cheque receipts do NOT need a
3927  // chequeReceipt Item attached....
3928  case OTItem::chequeReceipt: // ...but it's here anyway as a type, for
3929  // dual use reasons (balance agreement
3930  // sub-items. Like for an inbox report.)
3932  case OTItem::marketReceipt: // Used for actual market receipts, as well
3933  // as for balance agreement sub-items.
3934  case OTItem::paymentReceipt: // Used for actual payment receipts, as
3935  // well as for balance agreement sub-items.
3936  case OTItem::transferReceipt: // Used for actual transfer receipts, as
3937  // well as for balance
3938  // agreement sub-items. (Hmm does balance agreement need this?)
3939  case OTItem::finalReceipt: // Used for actual final receipt (I think) as
3940  // well as for balance agreement sub item (I
3941  // think.)
3942  case OTItem::basketReceipt: // Used for basket receipt (I think) as well
3943  // as for balance agreement sub-item (I
3944  // think.)
3945 
3946  if (OTItem::acknowledgement == pItem->GetStatus()) {
3947  bFoundAnActionItem = true;
3948  }
3949  else if (OTItem::rejection == pItem->GetStatus()) {
3950  return false;
3951  }
3952 
3953  break;
3954 
3955  default:
3956  otErr << "Wrong transaction type passed to "
3957  "OTTransaction::GetSuccess()\n";
3958  return false;
3959  }
3960  }
3961 
3962  return (bFoundABalanceAgreement && bFoundAnActionItem);
3963 }
3964 
3965 // Todo: eliminate this function since there is already a list of strings at the
3966 // top
3967 // of this file, and a list of enums at the top of the header file.
3968 //
3969 // static
3971  const OTString& strType)
3972 {
3974 
3975  if (strType.Compare("blank"))
3976  theType = OTTransaction::blank;
3977 
3978  else if (strType.Compare("message"))
3979  theType = OTTransaction::message;
3980  else if (strType.Compare("notice"))
3981  theType = OTTransaction::notice;
3982  else if (strType.Compare("replyNotice"))
3983  theType = OTTransaction::replyNotice;
3984  else if (strType.Compare("successNotice"))
3985  theType = OTTransaction::successNotice;
3986 
3987  else if (strType.Compare("pending"))
3988  theType = OTTransaction::pending;
3989 
3990  else if (strType.Compare("transferReceipt"))
3992  else if (strType.Compare("voucherReceipt"))
3994  else if (strType.Compare("chequeReceipt"))
3995  theType = OTTransaction::chequeReceipt;
3996  else if (strType.Compare("marketReceipt"))
3997  theType = OTTransaction::marketReceipt;
3998  else if (strType.Compare("paymentReceipt"))
4000  else if (strType.Compare("finalReceipt"))
4001  theType = OTTransaction::finalReceipt;
4002  else if (strType.Compare("basketReceipt"))
4003  theType = OTTransaction::basketReceipt;
4004 
4005  else if (strType.Compare("instrumentNotice"))
4007  else if (strType.Compare("instrumentRejection"))
4009 
4010  else if (strType.Compare("processNymbox"))
4011  theType = OTTransaction::processNymbox;
4012  else if (strType.Compare("atProcessNymbox"))
4014  else if (strType.Compare("processInbox"))
4015  theType = OTTransaction::processInbox;
4016  else if (strType.Compare("atProcessInbox"))
4018  else if (strType.Compare("transfer"))
4019  theType = OTTransaction::transfer;
4020  else if (strType.Compare("atTransfer"))
4021  theType = OTTransaction::atTransfer;
4022  else if (strType.Compare("deposit"))
4023  theType = OTTransaction::deposit;
4024  else if (strType.Compare("atDeposit"))
4025  theType = OTTransaction::atDeposit;
4026  else if (strType.Compare("withdrawal"))
4027  theType = OTTransaction::withdrawal;
4028  else if (strType.Compare("atWithdrawal"))
4029  theType = OTTransaction::atWithdrawal;
4030  else if (strType.Compare("marketOffer"))
4031  theType = OTTransaction::marketOffer;
4032  else if (strType.Compare("atMarketOffer"))
4033  theType = OTTransaction::atMarketOffer;
4034  else if (strType.Compare("paymentPlan"))
4035  theType = OTTransaction::paymentPlan;
4036  else if (strType.Compare("atPaymentPlan"))
4037  theType = OTTransaction::atPaymentPlan;
4038  else if (strType.Compare("smartContract"))
4039  theType = OTTransaction::smartContract;
4040  else if (strType.Compare("atSmartContract"))
4042  else if (strType.Compare("cancelCronItem"))
4044  else if (strType.Compare("atCancelCronItem"))
4046  else if (strType.Compare("exchangeBasket"))
4048  else if (strType.Compare("atExchangeBasket"))
4050  else if (strType.Compare("payDividend"))
4051  theType = OTTransaction::payDividend;
4052  else if (strType.Compare("atPayDividend"))
4053  theType = OTTransaction::atPayDividend;
4054  else
4055  theType = OTTransaction::error_state;
4056 
4057  return theType;
4058 }
4059 
4060 // return -1 if error, 0 if nothing, and 1 if the node was processed.
4062 {
4063  const OTString strNodeName = xml->getNodeName();
4064 
4065  OTNumList* pNumList = nullptr;
4066  if (strNodeName.Compare("nymboxRecord")) {
4067  pNumList = &m_Numlist;
4068  }
4069 
4070  if (strNodeName.Compare("nymboxRecord") ||
4071  strNodeName.Compare("inboxRecord") ||
4072  strNodeName.Compare("outboxRecord") ||
4073  strNodeName.Compare("paymentInboxRecord") ||
4074  strNodeName.Compare("recordBoxRecord") ||
4075  strNodeName.Compare("expiredBoxRecord")) {
4076  int64_t lNumberOfOrigin = 0;
4077  int64_t lTransactionNum = 0;
4078  int64_t lInRefTo = 0;
4079  int64_t lInRefDisplay = 0;
4080 
4081  time64_t the_DATE_SIGNED = OT_TIME_ZERO;
4082  int theType = OTTransaction::error_state; // default
4083  OTString strHash;
4084 
4085  int64_t lAdjustment = 0;
4086  int64_t lDisplayValue = 0;
4087  int64_t lClosingNum = 0;
4088  int64_t lRequestNumber = 0;
4089  bool bReplyTransSuccess = false;
4090 
4091  int32_t nAbbrevRetVal = LoadAbbreviatedRecord(
4092  xml, lNumberOfOrigin, lTransactionNum, lInRefTo, lInRefDisplay,
4093  the_DATE_SIGNED, theType, strHash, lAdjustment, lDisplayValue,
4094  lClosingNum, lRequestNumber, bReplyTransSuccess, pNumList);
4095 
4096  if ((-1) == nAbbrevRetVal)
4097  return (-1); // The function already logs appropriately.
4098 
4099  m_bIsAbbreviated = true;
4100 
4101  SetNumberOfOrigin(lNumberOfOrigin);
4102  SetTransactionNum(lTransactionNum);
4103  SetReferenceToNum(lInRefTo);
4104  SetClosingNum(lClosingNum);
4105  SetRequestNum(lRequestNumber);
4106 
4107  SetReplyTransSuccess(bReplyTransSuccess);
4108 
4109  m_lInRefDisplay = lInRefDisplay;
4110  m_lAbbrevAmount = lAdjustment;
4111  m_lDisplayAmount = lDisplayValue;
4112  m_DATE_SIGNED = the_DATE_SIGNED;
4113  m_Type = static_cast<OTTransaction::transactionType>(theType);
4114 
4115  if (strHash.Exists())
4116  m_Hash.SetString(strHash);
4117  else
4118  otErr << "OTTransaction::ProcessXMLNode: Missing receiptHash on "
4119  "abbreviated record.\n";
4120 
4121  return 1;
4122  }
4123 
4124  // THIS PART is probably what you're looking for.
4125  else if (strNodeName.Compare("transaction")) // Todo: notice how this "else
4126  // if" uses OTString::Compare,
4127  // where most other
4128  // ProcessXMLNode functions in
4129  // OT use !strcmp()? (That's
4130  // right: Buffer overflow. Need
4131  // to fix elsewhere as it is
4132  // fixed here.)
4133  {
4134 
4135  const OTString strType = xml->getAttributeValue("type");
4136 
4137  if (strType.Exists())
4139  else {
4140  otOut << "OTTransaction::ProcessXMLNode: Failure: unknown "
4141  "transaction type: " << strType << " \n";
4142  return (-1);
4143  }
4144 
4145  OTString strCancelled = xml->getAttributeValue("cancelled");
4146  if (strCancelled.Exists() && strCancelled.Compare("true"))
4147  m_bCancelled = true;
4148  else
4149  m_bCancelled = false;
4150 
4151  OTString strDateSigned = xml->getAttributeValue("dateSigned");
4152  const int64_t lDateSigned =
4153  strDateSigned.Exists() ? atol(strDateSigned.Get()) : 0;
4154  m_DATE_SIGNED = OTTimeGetTimeFromSeconds(lDateSigned); // Todo casting ?
4155 
4156  const OTString strAcctID = xml->getAttributeValue("accountID");
4157  const OTString strServerID = xml->getAttributeValue("serverID");
4158  const OTString strUserID = xml->getAttributeValue("userID");
4159 
4160  if (!strAcctID.Exists() || !strServerID.Exists() ||
4161  !strUserID.Exists()) {
4162  otOut
4163  << "OTTransaction::ProcessXMLNode: Failure: missing strAcctID ("
4164  << strAcctID << ") or strServerID (" << strServerID
4165  << ") or strUserID (" << strUserID << "). \n";
4166  return (-1);
4167  }
4168 
4169  const OTString strOrigin = xml->getAttributeValue("numberOfOrigin");
4170  const OTString strTransNum = xml->getAttributeValue("transactionNum");
4171  const OTString strInRefTo = xml->getAttributeValue("inReferenceTo");
4172 
4173  if (!strTransNum.Exists() || !strInRefTo.Exists()) {
4174  otOut << "OTTransaction::ProcessXMLNode: Failure: missing "
4175  "strTransNum (" << strTransNum << ") or strInRefTo ("
4176  << strInRefTo << "). \n";
4177  return (-1);
4178  }
4179 
4180  // a replyNotice (a copy of the server's reply to one of my messages)
4181  // is often dropped into my Nymbox, to make sure I see it. Usually these
4182  // have a REQUEST NUMBER on them, so I can quickly tell WHICH MESSAGE
4183  // it is in reply to.
4184  //
4186  const OTString strRequestNum =
4187  xml->getAttributeValue("requestNumber");
4188 
4189  if (strRequestNum.Exists())
4190  m_lRequestNumber = atol(strRequestNum.Get());
4191 
4192  const OTString strTransSuccess =
4193  xml->getAttributeValue("transSuccess");
4194 
4195  m_bReplyTransSuccess = strTransSuccess.Compare("true");
4196  }
4197 
4198  if ((OTTransaction::blank == m_Type) ||
4200  const OTString strTotalList =
4201  xml->getAttributeValue("totalListOfNumbers");
4202  m_Numlist.Release();
4203 
4204  if (strTotalList.Exists())
4205  m_Numlist.Add(strTotalList); // (Comma-separated list of numbers
4206  // now becomes std::set<int64_t>.)
4207  }
4208 
4209  OTIdentifier ACCOUNT_ID(strAcctID), SERVER_ID(strServerID),
4210  USER_ID(strUserID);
4211 
4213  ACCOUNT_ID); // GetPurportedAccountID() const { return m_AcctID; }
4214  SetPurportedServerID(SERVER_ID); // GetPurportedServerID() const {
4215  // return m_AcctServerID; }
4216  SetUserID(USER_ID);
4217 
4218  // m_bLoadSecurely defaults to true.
4219  // Normally the RealAccountID and RealServerID are set from above,
4220  // before
4221  // loading. That way, I can compare them to whatever is actually loaded.
4222  // (So people don't swap files on us!!)
4223  // But if the coder SPECIALLY sets m_bLoadSecurely to FALSE, that means
4224  // he
4225  // honestly doesn't know those IDs, and he is loading the file, and he
4226  // wants it
4227  // to load up properly AS IF THE IDs IN THE FILE WERE CORRECT. He only
4228  // does this
4229  // because it's the only way to get the file loaded without knowing
4230  // those IDs in
4231  // advance, and because he takes care, when doing this, to check them
4232  // after the fact
4233  // and see if they are, indeed, the ones he was expecting.
4234  //
4235  // This mechanism was ONLY FINALLY ADDED to get the class factory
4236  // working properly.
4237  // And even in this case, it is still INTERNALLY CONSISTENT. (The
4238  // sub-items will still
4239  // be expected to be correct with their parent items.)
4240  //
4241  if (!m_bLoadSecurely) {
4242  SetRealAccountID(ACCOUNT_ID);
4243  SetRealServerID(SERVER_ID);
4244  }
4245 
4246  if (strOrigin.Exists()) SetNumberOfOrigin(atol(strOrigin.Get()));
4247 
4248  SetTransactionNum(atol(strTransNum.Get()));
4249  SetReferenceToNum(atol(strInRefTo.Get()));
4250 
4251  otLog4 << "Loaded transaction " << GetTransactionNum()
4252  << ", in reference to: " << GetReferenceToNum()
4253  << " type: " << strType << "\n";
4254 
4255  return 1;
4256  }
4257  else if (!strcmp("closingTransactionNumber", xml->getNodeName())) {
4258  OTString strClosingNumber = xml->getAttributeValue("value");
4259 
4260  if (strClosingNumber.Exists() &&
4263  m_lClosingTransactionNo = atol(strClosingNumber.Get());
4264  }
4265  else {
4266  otErr << "Error in OTTransaction::ProcessXMLNode: "
4267  "closingTransactionNumber field without value, or in "
4268  "wrong transaction type.\n";
4269  return (-1); // error condition
4270  }
4271 
4272  return 1;
4273  }
4274  else if (!strcmp("cancelRequest", xml->getNodeName())) {
4275  if (false ==
4277  otErr << "Error in OTTransaction::ProcessXMLNode: cancelRequest "
4278  "field without value.\n";
4279  return (-1); // error condition
4280  }
4281 
4282  return 1;
4283  }
4284  else if (!strcmp("inReferenceTo", xml->getNodeName())) {
4285  if (false ==
4287  otErr << "Error in OTTransaction::ProcessXMLNode: inReferenceTo "
4288  "field without value.\n";
4289  return (-1); // error condition
4290  }
4291 
4292  return 1;
4293  }
4294  else if (!strcmp("item", xml->getNodeName())) {
4295  OTString strData;
4296 
4297  if (!OTContract::LoadEncodedTextField(xml, strData) ||
4298  !strData.Exists()) {
4299  otErr << "Error in OTTransaction::ProcessXMLNode: transaction item "
4300  "field without value.\n";
4301  return (-1); // error condition
4302  }
4303  else {
4304  OTItem* pItem = new OTItem(GetUserID(), *this);
4305  OT_ASSERT(nullptr != pItem);
4306 
4307  if (!m_bLoadSecurely) pItem->SetLoadInsecure();
4308 
4309  // If we're able to successfully base64-decode the string and load
4310  // it up as
4311  // a transaction, then add it to the ledger's list of transactions
4312  if (!pItem->LoadContractFromString(strData)) {
4313  otErr << "ERROR: OTTransaction failed loading item from "
4314  "string: \n\n"
4315  << (strData.Exists() ? strData.Get() : "") << "\n\n";
4316  delete pItem;
4317  pItem = nullptr;
4318  return (-1);
4319  }
4320  else if (!pItem->VerifyContractID()) {
4321  otErr << "ERROR: Failed verifying transaction Item in "
4322  "OTTransaction::ProcessXMLNode: \n\n" << strData
4323  << "\n\n";
4324  delete pItem;
4325  pItem = nullptr;
4326  return (-1);
4327  }
4328  else {
4329  m_listItems.push_back(pItem);
4330  // otLog5 << "Loaded transaction Item and adding
4331  // to m_listItems in OTTransaction\n");
4332  }
4333  }
4334 
4335  return 1;
4336  }
4337 
4338  return 0;
4339 }
4340 
4341 // For "OTTransaction::blank" and "OTTransaction::successNotice"
4342 // which periodically have more numbers added to them.
4343 //
4345 {
4346  return m_Numlist.Add(theAddition);
4347 }
4348 
4349 // This is called automatically by SignContract to make sure what's being signed
4350 // is the most up-to-date
4351 // Before transmission or serialization, this is where the ledger saves its
4352 // contents
4353 // So let's make sure this transaction has the right contents.
4354 //
4356 {
4357  OTString strCancelled;
4358 
4359  if (m_bCancelled) {
4360  strCancelled.Format(" cancelled=\"%s\"\n", "true");
4361  }
4362 
4363  OTString strListOfBlanks; // IF this transaction is "blank" or
4364  // "successNotice" this will serialize the list of
4365  // transaction numbers for it. (They now support
4366  // multiple numbers.)
4367  OTString strRequestNum; // Used by replyNotice only.
4368 
4369  switch (m_Type) {
4371  strRequestNum.Format(" requestNumber=\"%lld\"\n transSuccess=\"%s\"\n",
4373  m_bReplyTransSuccess ? "true" : "false");
4374  break;
4375 
4376  case OTTransaction::blank: // freshly issued transaction number, not
4377  // accepted by the user (yet).
4378  case OTTransaction::successNotice: // A transaction # has successfully been
4379  // signed out.
4380  {
4381  if (m_Numlist.Count() >
4382  0) // This is always 0, except for blanks and successNotices.
4383  {
4384  OTString strNumbers;
4385  if (true == m_Numlist.Output(strNumbers))
4386  strListOfBlanks.Format(" totalListOfNumbers=\"%s\"\n",
4387  strNumbers.Get());
4388  else // (False just means m_Numlist was empty.)
4389  strListOfBlanks.Set("");
4390  }
4391  }
4392  default:
4393  break;
4394  }
4395 
4396  const char* pTypeStr = GetTypeString(); // TYPE
4397  const OTString strType((nullptr != pTypeStr) ? pTypeStr : "error_state"),
4398  strAcctID(GetPurportedAccountID()), strServerID(GetPurportedServerID()),
4399  strUserID(GetUserID());
4400 
4401  m_DATE_SIGNED = OTTimeGetCurrentTime(); // We store the timestamp of when
4402  // this transaction was signed.
4403  const int64_t lDateSigned = OTTimeGetSecondsFromTime(m_DATE_SIGNED);
4404 
4405  // I release this because I'm about to repopulate it.
4407 
4408  m_xmlUnsigned.Concatenate("<transaction type=\"%s\"\n%s"
4409  " dateSigned=\"%lld\"\n"
4410  " accountID=\"%s\"\n"
4411  " userID=\"%s\"\n"
4412  " serverID=\"%s\"\n%s"
4413  " numberOfOrigin=\"%lld\"\n"
4414  " transactionNum=\"%lld\"\n%s"
4415  " inReferenceTo=\"%lld\" >\n\n",
4416  strType.Get(), strCancelled.Get(), lDateSigned,
4417  strAcctID.Get(), strUserID.Get(),
4418  strServerID.Get(), strRequestNum.Get(),
4420  strListOfBlanks.Get(), GetReferenceToNum());
4421 
4422  if (IsAbbreviated()) {
4423  if (nullptr != m_pParent) {
4424 
4425  switch (m_pParent->GetType()) {
4426  case OTLedger::nymbox:
4428  break;
4429  case OTLedger::inbox:
4431  break;
4432  case OTLedger::outbox:
4434  break;
4437  break;
4438  case OTLedger::recordBox:
4440  break;
4441  case OTLedger::expiredBox:
4443  break;
4444  /* --- BREAK --- */
4445  case OTLedger::message:
4446  otErr << "OTTransaction::" << __FUNCTION__
4447  << ": Unexpected message ledger type in 'abbreviated' "
4448  "block. (Error.) \n";
4449  break;
4450  default:
4451  otErr << "OTTransaction::" << __FUNCTION__
4452  << ": Unexpected ledger type in 'abbreviated' block. "
4453  "(Error.) \n";
4454  break;
4455  } /*switch*/
4456  }
4457  else
4458  otErr << "OTTransaction::" << __FUNCTION__
4459  << ": Error: Unable to save abbreviated receipt here, since "
4460  "m_pParent is nullptr.\n";
4461 
4462  }
4463  else // not abbreviated (full details.)
4464  {
4468  "<closingTransactionNumber value=\"%lld\"/>\n\n",
4470  }
4471 
4472  // a transaction contains a list of items, but it is also in reference
4473  // to some item, from someone else
4474  // We include a full copy of that item here.
4476  m_xmlUnsigned.Concatenate("<inReferenceTo>\n%s</inReferenceTo>\n\n",
4478 
4480  m_xmlUnsigned.Concatenate("<cancelRequest>\n%s</cancelRequest>\n\n",
4482 
4483  // loop through the items that make up this transaction and print them
4484  // out here, base64-encoded, of course.
4485  for (auto& it : m_listItems) {
4486  OTItem* pItem = it;
4487  OT_ASSERT(nullptr != pItem);
4488 
4489  OTString strItem;
4490  pItem->SaveContractRaw(strItem);
4491 
4492  OTASCIIArmor ascItem;
4493  ascItem.SetString(strItem, true); // linebreaks = true
4494 
4495  m_xmlUnsigned.Concatenate("<item>\n%s</item>\n\n", ascItem.Get());
4496  }
4497  } // not abbreviated (full details.)
4498 
4499  m_xmlUnsigned.Concatenate("</transaction>\n");
4500 }
4501 
4502 /*
4503  Question note to self: Which of the above transaction types can be found
4504 inside:
4505  paymentInbox ledger, paymentOutbox ledger, and recordBox ledger?
4506 
4507  void SaveAbbrevPaymentInboxRecord(OTString& strOutput);
4508  void SaveAbbrevPaymentOutboxRecord(OTString& strOutput);
4509  void SaveAbbrevRecordBoxRecord(OTString& strOutput);
4510 
4511 
4512  --- paymentInbox ledger:
4513 
4514  "instrumentNotice", // Receive these in paymentInbox, and send in
4515 paymentOutbox. (When done, they go to recordBox to await deletion.)
4516  "instrumentRejection", // When someone rejects your invoice from his
4517 paymentInbox, you get one of these in YOUR paymentInbox.
4518 
4519 
4520  --- paymentOutbox ledger:
4521 
4522  "instrumentNotice", // Receive these in paymentInbox, and send in
4523 paymentOutbox. (When done, they go to recordBox to await deletion.)
4524 
4525 
4526  --- recordBox ledger:
4527 
4528  // These all come from the asset account inbox (where they are transferred from
4529 before they end up in the record box.)
4530  "pending", // Pending transfer, in the inbox/outbox. (This can
4531 end up in your recordBox if you cancel your pending outgoing transfer.)
4532  "transferReceipt", // the server drops this into your inbox, when someone
4533 accepts your transfer.
4534  "chequeReceipt", // the server drops this into your inbox, when someone
4535 cashes your cheque.
4536  "voucherReceipt", // the server drops this into your inbox, when someone
4537 cashes your voucher.
4538  "marketReceipt", // server drops this into inbox periodically, if you
4539 have an offer on the market.
4540  "paymentReceipt", // the server drops this into people's inboxes,
4541 periodically, if they have payment plans.
4542  "finalReceipt", // the server drops this into your inbox(es), when a
4543 CronItem expires or is canceled.
4544  "basketReceipt", // the server drops this into your inboxes, when a
4545 basket exchange is processed.
4546 
4547  // Record box may also store things that came from a Nymbox, and then had to go
4548 somewhere client-side for storage,
4549  // until user decides to delete them. For example:
4550  "notice", // in nymbox, notice from the server. Probably contains
4551 an updated smart contract.
4552 
4553 // Whereas for a recordBox storing paymentInbox/paymentOutbox receipts, once
4554 they are completed, they go here to die.
4555  "instrumentNotice", // Receive these in paymentInbox, and send in
4556 paymentOutbox. (When done, they go to recordBox to await deletion.)
4557  "instrumentRejection", // When someone rejects your invoice from his
4558 paymentInbox, you get one of these in YOUR paymentInbox.
4559 
4560  */
4561 
4562 /*
4563  --- paymentInbox ledger:
4564  "instrumentNotice", // Receive these in paymentInbox, and send in
4565  paymentOutbox. (When done, they go to recordBox to await deletion.)
4566  "instrumentRejection", // When someone rejects your invoice from his
4567  paymentInbox, you get one of these in YOUR paymentInbox.
4568  */
4570 {
4571  int64_t lDisplayValue = 0;
4572 
4573  switch (m_Type) {
4575  if (IsAbbreviated())
4576  lDisplayValue = GetAbbrevDisplayAmount();
4577  else
4578  lDisplayValue = GetReceiptAmount();
4579  break;
4581  if (IsAbbreviated()) // not the actual value of 0.
4582  lDisplayValue = GetAbbrevDisplayAmount();
4583  break;
4584  default: // All other types are irrelevant for payment inbox reports
4585  otErr << "OTTransaction::" << __FUNCTION__ << ": Unexpected "
4586  << GetTypeString() << " transaction "
4587  "in payment inbox while making abbreviated "
4588  "payment inbox record.\n";
4589 
4590  OT_FAIL_MSG("ASSERT: OTTransaction::SaveAbbrevPaymentInboxRecord: "
4591  "Unexpected transaction type.");
4592 
4593  return;
4594  }
4595 
4596  // By this point, we know only the right types of receipts are being saved,
4597  // and
4598  // the adjustment and display value are both set correctly.
4599 
4600  // TYPE
4601  OTString strType;
4602  const char* pTypeStr = GetTypeString();
4603  strType.Set((nullptr != pTypeStr) ? pTypeStr : "error_state");
4604 
4605  // DATE SIGNED
4606  const int64_t lDateSigned = OTTimeGetSecondsFromTime(m_DATE_SIGNED);
4607 
4608  // HASH OF THE COMPLETE "BOX RECEIPT"
4609  // Save abbreviated is only used for receipts in boxes such as inbox,
4610  // outbox, and nymbox.
4611  // (Thus the moniker "Box Receipt", as contrasted with cron receipts or
4612  // normal transaction receipts with balance agreements.)
4613  //
4614  OTString strHash;
4615 
4616  // If this is already an abbreviated record, then save the existing hash.
4617  if (IsAbbreviated()) m_Hash.GetString(strHash);
4618  // Otherwise if it's a full record, then calculate the hash and save it.
4619  else {
4620  OTIdentifier idReceiptHash; // a hash of the actual transaction is
4621  // stored with its
4622  CalculateContractID(idReceiptHash); // abbreviated short-form
4623  // record (in the payment
4624  // inbox, for example.)
4625  idReceiptHash.GetString(strHash);
4626  }
4627 
4628  strOutput.Concatenate("<paymentInboxRecord type=\"%s\"\n"
4629  " dateSigned=\"%lld\"\n"
4630  " receiptHash=\"%s\"\n"
4631  " displayValue=\"%lld\"\n"
4632  " transactionNum=\"%lld\"\n"
4633  " inRefDisplay=\"%lld\"\n"
4634  " inReferenceTo=\"%lld\" />\n\n",
4635  strType.Get(), lDateSigned, strHash.Get(),
4636  lDisplayValue, GetTransactionNum(),
4638 }
4639 
4641 {
4642  int64_t lDisplayValue = 0;
4643 
4644  switch (m_Type) {
4645  // PAYMENT INBOX / PAYMENT OUTBOX
4647  if (IsAbbreviated()) // not the actual value of 0.
4648  lDisplayValue = GetAbbrevDisplayAmount();
4649  else
4650  lDisplayValue = GetReceiptAmount();
4651  break;
4653  if (IsAbbreviated()) // not the actual value of 0.
4654  lDisplayValue = GetAbbrevDisplayAmount();
4655  else
4656  lDisplayValue = 0;
4657  break;
4658  case OTTransaction::notice: // A notice from the server. Used in Nymbox.
4659  // Probably contains an updated smart contract.
4660  if (IsAbbreviated()) // not the actual value of 0.
4661  lDisplayValue = GetAbbrevDisplayAmount();
4662  else
4663  lDisplayValue = 0;
4664  break;
4665  default: // All other types are irrelevant for inbox reports
4666  {
4667  otErr
4668  << "OTTransaction::" << __FUNCTION__ << ": Unexpected "
4669  << GetTypeString()
4670  << " transaction "
4671  "in expired box while making abbreviated expired-box record.\n";
4672 
4673  OT_FAIL_MSG("ASSERT: OTTransaction::SaveAbbrevExpiredBoxRecord: "
4674  "Unexpected transaction type.");
4675  }
4676  return;
4677  }
4678 
4679  // By this point, we know only the right types of receipts are being saved,
4680  // and
4681  // the adjustment and display value are both set correctly.
4682 
4683  // TYPE
4684  OTString strType;
4685  const char* pTypeStr = GetTypeString();
4686  strType.Set((nullptr != pTypeStr) ? pTypeStr : "error_state");
4687 
4688  // DATE SIGNED
4689  const int64_t lDateSigned = OTTimeGetSecondsFromTime(m_DATE_SIGNED);
4690 
4691  // HASH OF THE COMPLETE "BOX RECEIPT"
4692  // Save abbreviated is only used for receipts in boxes such as inbox,
4693  // outbox, and nymbox.
4694  // (Thus the moniker "Box Receipt", as contrasted with cron receipts or
4695  // normal transaction receipts with balance agreements.)
4696  //
4697  OTString strHash;
4698 
4699  // If this is already an abbreviated record, then save the existing hash.
4700  if (IsAbbreviated()) m_Hash.GetString(strHash);
4701  // Otherwise if it's a full record, then calculate the hash and save it.
4702  else {
4703  OTIdentifier idReceiptHash; // a hash of the actual transaction is
4704  // stored with its
4705  CalculateContractID(idReceiptHash); // abbreviated short-form
4706  // record (in the expired box,
4707  // for example.)
4708  idReceiptHash.GetString(strHash);
4709  }
4710 
4711  strOutput.Concatenate("<expiredBoxRecord type=\"%s\"\n"
4712  " dateSigned=\"%lld\"\n"
4713  " receiptHash=\"%s\"\n"
4714  " displayValue=\"%lld\"\n"
4715  " transactionNum=\"%lld\"\n"
4716  " inRefDisplay=\"%lld\"\n"
4717  " inReferenceTo=\"%lld\" />\n\n",
4718  strType.Get(), lDateSigned, strHash.Get(),
4719  lDisplayValue, GetTransactionNum(),
4721 }
4722 
4723 /*
4724  --- recordBox ledger:
4725 
4726  // These all come from the ASSET ACCT INBOX (where they are transferred from
4727 before they end up in the record box.)
4728  "pending", // Pending transfer, in the inbox/outbox. (This can
4729 end up in your recordBox if you cancel your pending outgoing transfer.)
4730  "transferReceipt", // the server drops this into your inbox, when someone
4731 accepts your transfer.
4732  "chequeReceipt", // the server drops this into your inbox, when someone
4733 cashes your cheque.
4734  "voucherReceipt", // the server drops this into your inbox, when someone
4735 cashes your voucher.
4736  "marketReceipt", // server drops this into inbox periodically, if you
4737 have an offer on the market.
4738  "paymentReceipt", // the server drops this into people's inboxes,
4739 periodically, if they have payment plans.
4740  "finalReceipt", // the server drops this into your inbox(es), when a
4741 CronItem expires or is canceled.
4742  "basketReceipt", // the server drops this into your inboxes, when a
4743 basket exchange is processed.
4744 
4745  // Record box may also store things that came from a NYMBOX, and then had to go
4746 somewhere client-side for storage,
4747  // until user decides to delete them. For example:
4748  "notice", // in nymbox, notice from the server. Probably contains
4749 an updated smart contract.
4750 
4751 // Whereas for a recordBox storing PAYMENT-INBOX and PAYMENT-OUTBOX receipts,
4752 once they are completed, they go here to die.
4753  "instrumentNotice", // Receive these in paymentInbox, and send in
4754 paymentOutbox. (When done, they go to recordBox to await deletion.)
4755  "instrumentRejection", // When someone rejects your invoice from his
4756 paymentInbox, you get one of these in YOUR paymentInbox.
4757 
4758 
4759  NOTE: The expiredBox is identical to recordBox (for things that came from
4760 payments inbox or outpayments box.)
4761  Except it's used for expired payments, instead of completed / canceled
4762 payments.
4763  */
4765 {
4766  // Have some kind of check in here, whether the AcctID and UserID match.
4767  // Some recordBoxes DO, and some DON'T (the different kinds store different
4768  // kinds of receipts. See above comment.)
4769 
4770  int64_t lAdjustment = 0, lDisplayValue = 0;
4771 
4772  switch (m_Type) {
4773  // ASSET ACCOUNT INBOX
4774  // -- In inbox, pending hasn't been accepted yet. In outbox, it's already
4775  // gone. Either
4776  // way, it will have a 0 adjustment amount, even though perhaps 500 clams
4777  // display amount. Here I use the 500
4778  // for display, but in SaveAbbrevToOutbox, I multiply it by -1 so it appears
4779  // as -500 (leaving my account.)
4780  // -- In my inbox, the transferReceipt is notice of money that is already
4781  // gone. It thus has adjustment value of 0.
4782  // But the DISPLAY amount is the amount I originally sent. (Already
4783  // multiplied by -1 by GetReceiptAmount())
4784  //
4785  case OTTransaction::pending: // (The pending amount is stored on the
4786  // transfer item in my list of transaction
4787  // items.)
4788  case OTTransaction::transferReceipt: // The transferReceipt and
4789  // voucherReceipt amounts are the
4790  // display value (according to
4791  case OTTransaction::voucherReceipt: // GetReceiptAmount()), and not the
4792  // actual value of 0.
4793  if (IsAbbreviated()) {
4794  lAdjustment = GetAbbrevAdjustment();
4795  lDisplayValue = GetAbbrevDisplayAmount();
4796  }
4797  else {
4798  lAdjustment = 0;
4799  lDisplayValue = GetReceiptAmount();
4800  }
4801  break;
4802  // If chequeReceipt for 100 clams hit my inbox, then my balance is -100 from
4803  // where it was. (Same
4804  // value should be displayed.) Luckily, GetReceiptAmount() already
4805  // multiplies by (-1) for chequeReceipt.
4806  // For these (marketReceipt, paymentReceipt, basketReceipt), the actual
4807  // adjustment is positive OR negative
4808  // already, and the display value should match.
4809  case OTTransaction::chequeReceipt: // the amount is stored on cheque
4810  // (attached to depositCheque item,
4811  // attached.)
4812  case OTTransaction::marketReceipt: // amount is stored on marketReceipt
4813  // item. |
4814  case OTTransaction::paymentReceipt: // amount is stored on paymentReceipt
4815  // item. | and the display value should
4816  // match.
4817  case OTTransaction::basketReceipt: // amount is stored on basketReceipt
4818  // item. |
4819  if (IsAbbreviated()) // not the actual value of 0.
4820  {
4821  lAdjustment = GetAbbrevAdjustment();
4822  lDisplayValue = GetAbbrevDisplayAmount();
4823  }
4824  else {
4825  lAdjustment = GetReceiptAmount();
4826  lDisplayValue = lAdjustment;
4827  }
4828  break;
4829  case OTTransaction::finalReceipt: // amount is 0 according to
4830  // GetReceiptAmount()
4831  if (IsAbbreviated()) // not the actual value of 0.
4832  {
4833  lAdjustment = GetAbbrevAdjustment();
4834  lDisplayValue = GetAbbrevDisplayAmount();
4835  }
4836  else {
4837  lAdjustment = 0;
4838  lDisplayValue = 0;
4839  }
4840  break;
4841  // NYMBOX
4842  case OTTransaction::notice: // A notice from the server. Used in Nymbox.
4843  // Probably contains an updated smart contract.
4844  if (IsAbbreviated()) // not the actual value of 0.
4845  {
4846  lAdjustment = GetAbbrevAdjustment();
4847  lDisplayValue = GetAbbrevDisplayAmount();
4848  }
4849  else {
4850  lAdjustment = 0;
4851  lDisplayValue = 0;
4852  }
4853  break;
4854  // PAYMENT INBOX / PAYMENT OUTBOX
4856  if (IsAbbreviated()) // not the actual value of 0.
4857  {
4858  lAdjustment = GetAbbrevAdjustment();
4859  lDisplayValue = GetAbbrevDisplayAmount();
4860  }
4861  else {
4862  lAdjustment = 0;
4863  lDisplayValue = GetReceiptAmount();
4864  }
4865  break;
4867  if (IsAbbreviated()) // not the actual value of 0.
4868  {
4869  lAdjustment = GetAbbrevAdjustment();
4870  lDisplayValue = GetAbbrevDisplayAmount();
4871  }
4872  else {
4873  lAdjustment = 0;
4874  lDisplayValue = 0;
4875  }
4876  break;
4877  default: // All other types are irrelevant for inbox reports
4878  {
4879  otErr << "OTTransaction::SaveAbbrevRecordBoxRecord: Unexpected "
4880  << GetTypeString()
4881  << " transaction "
4882  "in record box while making abbreviated record-box record.\n";
4883  }
4884  return;
4885  } // why not transfer receipt? Because the amount was already removed from
4886  // your account when you transferred it,
4887 
4888  // By this point, we know only the right types of receipts are being saved,
4889  // and
4890  // the adjustment and display value are both set correctly.
4891 
4892  // TYPE
4893  OTString strType;
4894  const char* pTypeStr = GetTypeString();
4895  strType.Set((nullptr != pTypeStr) ? pTypeStr : "error_state");
4896 
4897  // DATE SIGNED
4898  const int64_t lDateSigned = OTTimeGetSecondsFromTime(m_DATE_SIGNED);
4899 
4900  // HASH OF THE COMPLETE "BOX RECEIPT"
4901  // Save abbreviated is only used for receipts in boxes such as inbox,
4902  // outbox, and nymbox.
4903  // (Thus the moniker "Box Receipt", as contrasted with cron receipts or
4904  // normal transaction receipts with balance agreements.)
4905  //
4906  OTString strHash;
4907 
4908  // If this is already an abbreviated record, then save the existing hash.
4909  if (IsAbbreviated()) m_Hash.GetString(strHash);
4910  // Otherwise if it's a full record, then calculate the hash and save it.
4911  else {
4912  OTIdentifier idReceiptHash; // a hash of the actual transaction is
4913  // stored with its
4914  CalculateContractID(idReceiptHash); // abbreviated short-form
4915  // record (in the record box,
4916  // for example.)
4917  idReceiptHash.GetString(strHash);
4918  }
4919 
4922 
4923  strOutput.Concatenate(
4924  "<recordBoxRecord type=\"%s\"\n"
4925  " dateSigned=\"%lld\"\n"
4926  " receiptHash=\"%s\"\n"
4927  " adjustment=\"%lld\"\n"
4928  " displayValue=\"%lld\"\n"
4929  " numberOfOrigin=\"%lld\"\n"
4930  " transactionNum=\"%lld\"\n"
4931  " closingNum=\"%lld\"\n"
4932  " inRefDisplay=\"%lld\"\n"
4933  " inReferenceTo=\"%lld\" />\n\n",
4934  strType.Get(), lDateSigned, strHash.Get(), lAdjustment,
4935  lDisplayValue, GetRawNumberOfOrigin(), GetTransactionNum(),
4937  else
4938  strOutput.Concatenate("<recordBoxRecord type=\"%s\"\n"
4939  " dateSigned=\"%lld\"\n"
4940  " receiptHash=\"%s\"\n"
4941  " adjustment=\"%lld\"\n"
4942  " displayValue=\"%lld\"\n"
4943  " numberOfOrigin=\"%lld\"\n"
4944  " transactionNum=\"%lld\"\n"
4945  " inRefDisplay=\"%lld\"\n"
4946  " inReferenceTo=\"%lld\" />\n\n",
4947  strType.Get(), lDateSigned, strHash.Get(),
4948  lAdjustment, lDisplayValue,
4951 }
4952 
4953 // All of the actual receipts cannot fit inside the inbox file,
4954 // which can get huge, and bog down network ability to transmit.
4955 // Instead, we save receipts in abbreviated form in the inbox,
4956 // then let the users download those receipts individually. That
4957 // way, each message cannot be too large to download, such as
4958 // a giant inbox can be with 400000 receipts inside of it.
4959 //
4961 {
4962  int64_t lDisplayValue = 0;
4963 
4964  OTString strDisplayValue; // IF this transaction is passing through on its
4965  // way to the paymentInbox, it will have a
4966  // displayValue.
4967  OTString strListOfBlanks; // IF this transaction is "blank" or
4968  // "successNotice" this will serialize the list of
4969  // transaction numbers for it. (They now support
4970  // multiple numbers.)
4971  OTString strRequestNum; // ONLY replyNotice transactions carry a request
4972  // Num.
4973 
4974  switch (m_Type) {
4975  case OTTransaction::blank: // freshly issued transaction number, not
4976  // accepted by the user (yet).
4977  case OTTransaction::successNotice: // A transaction # has successfully been
4978  // signed out.
4979  {
4980  if (m_Numlist.Count() >
4981  0) // This is always 0, except for blanks and successNotices.
4982  {
4983  OTString strNumbers;
4984  if (true == m_Numlist.Output(strNumbers))
4985  strListOfBlanks.Format(" totalListOfNumbers=\"%s\"\n",
4986  strNumbers.Get());
4987  else // (False just means it was empty.)
4988  strListOfBlanks.Set("");
4989  }
4990  }
4991  /* ! CONTINUES FALLING THROUGH HERE!!... */
4992 
4993  case OTTransaction::replyNotice: // A copy of a server reply to a previous
4994  // request you sent. (To make SURE you get
4995  // the reply.)
4996  strRequestNum.Format(" requestNumber=\"%lld\"\n transSuccess=\"%s\"\n",
4998  m_bReplyTransSuccess ? "true" : "false");
4999  break;
5000 
5001  case OTTransaction::message: // A message from one user to another, also in
5002  // the nymbox.
5003  case OTTransaction::notice: // A notice from the server. Used in Nymbox.
5004  // Probably contains an updated smart contract.
5005  case OTTransaction::finalReceipt: // Any finalReceipt in an inbox will also
5006  // drop a copy into the Nymbox.
5007  break;
5008 
5009  // paymentInbox items are transported through the Nymbox.
5010  // Therefore, this switch statement from SaveAbbrevPaymentInbox
5011  // is also found here, to handle those receipts as they pass through.
5012  case OTTransaction::instrumentNotice: // A financial instrument sent from/to
5013  // another nym.
5014  if (IsAbbreviated())
5015  lDisplayValue = GetAbbrevDisplayAmount();
5016  else
5017  lDisplayValue = GetReceiptAmount();
5018  strDisplayValue.Format(" displayValue=\"%lld\"\n", lDisplayValue);
5019  break; // (These last two are just passing through, on their way to the
5020  // paymentInbox.)
5021  case OTTransaction::instrumentRejection: // A rejection notice from the
5022  // intended recipient of an
5023  // instrumentNotice.
5024  lDisplayValue = 0;
5025  break;
5026 
5027  default: // All other types are irrelevant for nymbox reports.
5028  otErr << __FUNCTION__ << ": Unexpected " << GetTypeString()
5029  << " transaction in nymbox while making abbreviated nymbox "
5030  "record.\n";
5031  OT_FAIL_MSG("ASSERT: OTTransaction::SaveAbbreviatedNymboxRecord: "
5032  "Unexpected transaction in this Nymbox.");
5033 
5034  return;
5035  }
5036 
5037  // By this point, we know only the right types of receipts are being saved,
5038  // and
5039  // the adjustment and display value are both set correctly.
5040 
5041  // TYPE
5042  OTString strType;
5043  const char* pTypeStr = GetTypeString();
5044  strType.Set((nullptr != pTypeStr) ? pTypeStr : "error_state");
5045 
5046  // DATE SIGNED
5047  const int64_t lDateSigned = OTTimeGetSecondsFromTime(m_DATE_SIGNED);
5048 
5049  // HASH OF THE COMPLETE "BOX RECEIPT"
5050  // Save abbreviated is only used for receipts in boxes such as inbox,
5051  // outbox, and nymbox.
5052  // (Thus the moniker "Box Receipt", as contrasted with cron receipts or
5053  // normal transaction receipts with balance agreements.)
5054  //
5055  OTString strHash;
5056 
5057  // If this is already an abbreviated record, then save the existing hash.
5058  if (IsAbbreviated()) m_Hash.GetString(strHash);
5059  // Otherwise if it's a full record, then calculate the hash and save it.
5060  else {
5061  OTIdentifier idReceiptHash; // a hash of the actual transaction is
5062  // stored with its
5063  CalculateContractID(idReceiptHash); // abbreviated short-form
5064  // record (in the inbox, for
5065  // example.)
5066  idReceiptHash.GetString(strHash);
5067  }
5068 
5070  (OTTransaction::basketReceipt == m_Type)) // I actually don't think you
5071  // can put a basket receipt
5072  // notice in a nymbox, the way
5073  // you can with a final
5074  // receipt notice. Probably
5075  // can remove this line.
5076 
5077  strOutput.Concatenate("<nymboxRecord type=\"%s\"\n"
5078  " dateSigned=\"%lld\"\n"
5079  " receiptHash=\"%s\"\n"
5080  " transactionNum=\"%lld\"\n"
5081  " closingNum=\"%lld\"\n"
5082  " inRefDisplay=\"%lld\"\n"
5083  " inReferenceTo=\"%lld\" />\n\n",
5084  strType.Get(), lDateSigned, strHash.Get(),
5087 
5088  else
5089  strOutput.Concatenate(
5090  "<nymboxRecord type=\"%s\"\n"
5091  " dateSigned=\"%lld\"\n%s"
5092  " receiptHash=\"%s\"\n%s" // SOMETIMES this is added here by the
5093  // final %s: " displayValue=\"%lld\"\n"
5094  " transactionNum=\"%lld\"\n%s" // SOMETIMES this is added here by
5095  // the final %s: "
5096  // totalListOfNumbers=\"%s\"\n"
5097  " inRefDisplay=\"%lld\"\n"
5098  " inReferenceTo=\"%lld\" />\n\n",
5099  strType.Get(), lDateSigned, strRequestNum.Get(), strHash.Get(),
5100  strDisplayValue.Get(), GetTransactionNum(), strListOfBlanks.Get(),
5102 }
5103 
5105 {
5106  int64_t lAdjustment = 0, lDisplayValue = 0;
5107 
5108  switch (m_Type) {
5110  if (IsAbbreviated()) {
5111  lAdjustment = GetAbbrevAdjustment();
5112  lDisplayValue = GetAbbrevDisplayAmount();
5113  }
5114  else {
5115  lAdjustment =
5116  0; // In the inbox, a pending hasn't been accepted yet.
5117  lDisplayValue = // In the outbox, it's already gone.
5118  (GetReceiptAmount() * (-1)); // Either way, it will have a 0
5119  // adjustment amount, even though
5120  // perhaps 500 clams display
5121  // amount.
5122  }
5123  break; // In this case, since it's the outbox, then it's a MINUS (-500)
5124  // Display amount (since I'm sending, not receiving it.)
5125  default: // All other types are irrelevant for outbox reports.
5126  otErr << "OTTransaction::SaveAbbreviatedOutboxRecord: Unexpected "
5127  << GetTypeString()
5128  << " transaction "
5129  "in outbox while making abbreviated outbox record.\n";
5130 
5131  OT_FAIL_MSG("ASSERT: OTTransaction::SaveAbbreviatedOutboxRecord: "
5132  "unexpected transaction type.");
5133 
5134  return;
5135  }
5136 
5137  // By this point, we know only the right types of receipts are being saved,
5138  // and
5139  // the adjustment and display value are both set correctly.
5140 
5141  // TYPE
5142  OTString strType;
5143  const char* pTypeStr = GetTypeString();
5144  strType.Set((nullptr != pTypeStr) ? pTypeStr : "error_state");
5145 
5146  // DATE SIGNED
5147  const int64_t lDateSigned = OTTimeGetSecondsFromTime(m_DATE_SIGNED);
5148 
5149  // HASH OF THE COMPLETE "BOX RECEIPT"
5150  // Save abbreviated is only used for receipts in boxes such as inbox,
5151  // outbox, and nymbox.
5152  // (Thus the moniker "Box Receipt", as contrasted with cron receipts or
5153  // normal transaction receipts with balance agreements.)
5154  //
5155  OTString strHash;
5156 
5157  // If this is already an abbreviated record, then save the existing hash.
5158  if (IsAbbreviated()) m_Hash.GetString(strHash);
5159  // Otherwise if it's a full record, then calculate the hash and save it.
5160  else {
5161  OTIdentifier idReceiptHash; // a hash of the actual transaction is
5162  // stored with its
5163  CalculateContractID(idReceiptHash); // abbreviated short-form
5164  // record (in the inbox, for
5165  // example.)
5166  idReceiptHash.GetString(strHash);
5167  }
5168 
5169  strOutput.Concatenate("<outboxRecord type=\"%s\"\n"
5170  " dateSigned=\"%lld\"\n"
5171  " receiptHash=\"%s\"\n"
5172  " adjustment=\"%lld\"\n"
5173  " displayValue=\"%lld\"\n"
5174  " numberOfOrigin=\"%lld\"\n"
5175  " transactionNum=\"%lld\"\n"
5176  " inRefDisplay=\"%lld\"\n"
5177  " inReferenceTo=\"%lld\" />\n\n",
5178  strType.Get(), lDateSigned, strHash.Get(),
5179  lAdjustment, lDisplayValue, GetRawNumberOfOrigin(),
5181  GetReferenceToNum());
5182 }
5183 
5185 {
5186  // This is the actual amount that your account is changed BY this receipt.
5187  // Versus the useful amount the user will want to see (lDisplayValue.) For
5188  // example, if you perform
5189  // a transfer of 500 clams, then the money leaves your account at that time,
5190  // and you receive a transaction receipt
5191  // to that effect. LATER ON, when the recipient ACCEPTS the transfer, a
5192  // "transferReceipt" will pop into your inbox,
5193  // which you must accept in order to close out the transaction number. But
5194  // this transferReceipt "adjusts" your account
5195  // by ZERO, since the amount has ALREADY left your account before the
5196  // transferReceipt arrived. In that example, the
5197  // lAdjustment would be 0, while the lDisplayValue would be 500. The first
5198  // value is the actual impact on your balance
5199  // from that specific receipt, whereas the second value is the one that the
5200  // user probably wants to see.
5201 
5202  // NOTE: A similar logic envelops the GetReferenceNumForDisplay() field,
5203  // which, instead of returning the ACTUAL
5204  // ref# that OT needs to use, it will return the one that the user probably
5205  // wants to see.
5206  //
5207  int64_t lAdjustment = 0, lDisplayValue = 0;
5208 
5209  switch (m_Type) {
5210  // -- In inbox, pending hasn't been accepted yet. In outbox, it's already
5211  // gone. Either
5212  // way, it will have a 0 adjustment amount, even though perhaps 500 clams
5213  // display amount. Here I use the 500
5214  // for display, but in SaveAbbrevToOutbox, I multiply it by -1 so it appears
5215  // as -500 (leaving my account.)
5216  // -- In my inbox, the transferReceipt is notice of money that is already
5217  // gone. It thus has adjustment value of 0.
5218  // But the DISPLAY amount is the amount I originally sent. (Already
5219  // multiplied by -1 by GetReceiptAmount())
5220  //
5221  case OTTransaction::pending: // (The pending amount is stored on the
5222  // transfer item in my list of transaction
5223  // items.)
5224  case OTTransaction::transferReceipt: // The transferReceipt and
5225  // voucherReceipt amounts are the
5226  // display value (according to
5227  case OTTransaction::voucherReceipt: // GetReceiptAmount()), and not the
5228  // actual value of 0.
5229  if (IsAbbreviated()) {
5230  lAdjustment = GetAbbrevAdjustment();
5231  lDisplayValue = GetAbbrevDisplayAmount();
5232  }
5233  else {
5234  lAdjustment = 0;
5235  lDisplayValue = GetReceiptAmount();
5236  }
5237  break;
5238  // If chequeReceipt for 100 clams hit my inbox, then my balance is -100 from
5239  // where it was. (Same
5240  // value should be displayed.) Luckily, GetReceiptAmount() already
5241  // multiplies by (-1) for chequeReceipt.
5242  // For these (marketReceipt, paymentReceipt, basketReceipt), the actual
5243  // adjustment is positive OR negative
5244  // already, and the display value should match.
5245  case OTTransaction::chequeReceipt: // the amount is stored on cheque
5246  // (attached to depositCheque item,
5247  // attached.)
5248  case OTTransaction::marketReceipt: // amount is stored on marketReceipt
5249  // item. |
5250  case OTTransaction::paymentReceipt: // amount is stored on paymentReceipt
5251  // item. | and the display value should
5252  // match.
5253  case OTTransaction::basketReceipt: // amount is stored on basketReceipt
5254  // item. |
5255  if (IsAbbreviated()) // not the actual value of 0.
5256  {
5257  lAdjustment = GetAbbrevAdjustment();
5258  lDisplayValue = GetAbbrevDisplayAmount();
5259  }
5260  else {
5261  lAdjustment = GetReceiptAmount();
5262  lDisplayValue = lAdjustment;
5263  }
5264  break;
5265  case OTTransaction::finalReceipt: // amount is 0 according to
5266  // GetReceiptAmount()
5267  if (IsAbbreviated()) // not the actual value of 0.
5268  {
5269  lAdjustment = GetAbbrevAdjustment();
5270  lDisplayValue = GetAbbrevDisplayAmount();
5271  }
5272  else {
5273  lAdjustment = 0;
5274  lDisplayValue = 0;
5275  }
5276  break;
5277  default: // All other types are irrelevant for inbox reports
5278  {
5279  otErr << "OTTransaction::" << __FUNCTION__ << ": Unexpected "
5280  << GetTypeString()
5281  << " transaction "
5282  "in inbox while making abbreviated inbox record.\n";
5283 
5284  OT_FAIL_MSG("ASSERT: OTTransaction::SaveAbbreviatedInboxRecord: "
5285  "unexpected transaction type.");
5286  }
5287  return;
5288  } // why not transfer receipt? Because the amount was already removed from
5289  // your account when you transferred it,
5290 
5291  // By this point, we know only the right types of receipts are being saved,
5292  // and
5293  // the adjustment and display value are both set correctly.
5294 
5295  // TYPE
5296  OTString strType;
5297  const char* pTypeStr = GetTypeString();
5298  strType.Set((nullptr != pTypeStr) ? pTypeStr : "error_state");
5299 
5300  // DATE SIGNED
5301  const int64_t lDateSigned = OTTimeGetSecondsFromTime(m_DATE_SIGNED);
5302 
5303  // HASH OF THE COMPLETE "BOX RECEIPT"
5304  // Save abbreviated is only used for receipts in boxes such as inbox,
5305  // outbox, and nymbox.
5306  // (Thus the moniker "Box Receipt", as contrasted with cron receipts or
5307  // normal transaction receipts with balance agreements.)
5308  //
5309  OTString strHash;
5310 
5311  // If this is already an abbreviated record, then save the existing hash.
5312  if (IsAbbreviated()) m_Hash.GetString(strHash);
5313  // Otherwise if it's a full record, then calculate the hash and save it.
5314  else {
5315  OTIdentifier idReceiptHash; // a hash of the actual transaction is
5316  // stored with its
5317  CalculateContractID(idReceiptHash); // abbreviated short-form
5318  // record (in the inbox, for
5319  // example.)
5320  idReceiptHash.GetString(strHash);
5321  }
5322 
5325 
5326  strOutput.Concatenate(
5327  "<inboxRecord type=\"%s\"\n"
5328  " dateSigned=\"%lld\"\n"
5329  " receiptHash=\"%s\"\n"
5330  " adjustment=\"%lld\"\n"
5331  " displayValue=\"%lld\"\n"
5332  " numberOfOrigin=\"%lld\"\n"
5333  " transactionNum=\"%lld\"\n"
5334  " closingNum=\"%lld\"\n"
5335  " inRefDisplay=\"%lld\"\n"
5336  " inReferenceTo=\"%lld\" />\n\n",
5337  strType.Get(), lDateSigned, strHash.Get(), lAdjustment,
5338  lDisplayValue, GetRawNumberOfOrigin(), GetTransactionNum(),
5340  else
5341  strOutput.Concatenate("<inboxRecord type=\"%s\"\n"
5342  " dateSigned=\"%lld\"\n"
5343  " receiptHash=\"%s\"\n"
5344  " adjustment=\"%lld\"\n"
5345  " displayValue=\"%lld\"\n"
5346  " numberOfOrigin=\"%lld\"\n"
5347  " transactionNum=\"%lld\"\n"
5348  " inRefDisplay=\"%lld\"\n"
5349  " inReferenceTo=\"%lld\" />\n\n",
5350  strType.Get(), lDateSigned, strHash.Get(),
5351  lAdjustment, lDisplayValue,
5354 }
5355 
5356 // The ONE case where an Item has SUB-ITEMS is in the case of Balance Agreement.
5357 // For example, you might have a Withdrawal Transaction (request) that contains
5358 // 2 items: the withdrawal item itself, and the balance agreement item for that
5359 // withdrawal. The balance agreement item contains a LIST OF SUB ITEMS, each of
5360 // which represents a chequeReceipt, marketReceipt, or paymentReceipt from my
5361 // inbox. The Balance Agreement item needs to be able to report on the inbox
5362 // status, so I give it a list of sub-items.
5363 //
5365 {
5366  OTItem::itemType theItemType = OTItem::error_state;
5367 
5368  otLog3 << "Producing statement report item for inbox item type: "
5369  << GetTypeString() << ".\n"; // temp remove.
5370 
5371  switch (m_Type) { // These are the types that have an amount (somehow)
5372  case OTTransaction::pending: // the amount is stored on the transfer item in
5373  // my list.
5374  theItemType = OTItem::transfer;
5375  break;
5376  case OTTransaction::chequeReceipt: // the amount is stored on cheque
5377  // (attached to depositCheque item,
5378  // attached.)
5379  theItemType = OTItem::chequeReceipt;
5380  break;
5381  case OTTransaction::voucherReceipt: // the amount is stored on voucher
5382  // (attached to depositCheque item,
5383  // attached.)
5384  theItemType = OTItem::voucherReceipt;
5385  break;
5386  case OTTransaction::marketReceipt: // the amount is stored on marketReceipt
5387  // item
5388  theItemType = OTItem::marketReceipt;
5389  break;
5390  case OTTransaction::paymentReceipt: // amount is stored on paymentReceipt
5391  // item
5392  theItemType = OTItem::paymentReceipt;
5393  break;
5394  case OTTransaction::transferReceipt: // amount is 0 according to
5395  // GetReceiptAmount()
5396  theItemType = OTItem::transferReceipt;
5397  break;
5398  case OTTransaction::basketReceipt: // amount is stored on basketReceipt
5399  // item.
5400  theItemType = OTItem::basketReceipt;
5401  break;
5402  case OTTransaction::finalReceipt: // amount is 0 according to
5403  // GetReceiptAmount()
5404  theItemType = OTItem::finalReceipt;
5405  break;
5406  default: // All other types are irrelevant for inbox reports
5407  {
5408  otLog3 << "OTTransaction::ProduceInboxReportItem: Ignoring "
5409  << GetTypeString()
5410  << " transaction "
5411  "in inbox while making balance statement.\n";
5412  }
5413  return;
5414  } // why not transfer receipt? Because the amount was already removed from
5415  // your account when you transferred it,
5416  // and you already signed a balance agreement at that time. Thus, nothing in
5417  // your inbox is necessary to prove
5418  // the change in balance -- you already signed off on it. UPDATE: that's
5419  // okay since the below GetReceiptAmount()
5420  // will return 0 for a transfer receipt anyway.
5421 
5422  // In the case of a cron receipt which is in the inbox, but is being
5423  // accepted
5424  // by a notarizeProcessInbox, (if theOwner is a processInbox transaction)
5425  // then
5426  // we don't want to report that item. Why not? Because if the processInbox
5427  // is a
5428  // success, the item would be presumed removed. (That's what the process
5429  // aims to do,
5430  // after all: accept and remove the market receipt.) Therefore, I don't want
5431  // to add
5432  // it to the report, since the server will then think it's supposed to be
5433  // there, when
5434  // in fact it's supposed to be gone. I'm supposed to be showing a picture of
5435  // what would
5436  // be left in the event of a success. And if I successfully processed the
5437  // receipt out of my
5438  // inbox, then I would expect not to see it there anymore, so since that is
5439  // what I would
5440  // expect in that case, that is the picture I need to construct now.
5441  //
5442  // Thus, here we loop through theOwner (IF he's a process inbox transaction)
5443  // and we see
5444  // if he's actually trying to process a receipt off the inbox FOR ME (THIS
5445  // transaction.) If he is, then
5446  // we don't need to add this transaction to the report.
5447  //
5448 
5449  // the item will represent THIS TRANSACTION, and will be added to
5450  // theBalanceItem.
5451 
5452  OTItem* pReportItem = OTItem::CreateItemFromTransaction(*this, theItemType);
5453 
5454  if (nullptr !=
5455  pReportItem) // above line will assert if mem allocation fails.
5456  {
5457  int64_t lAmount = GetReceiptAmount();
5458  pReportItem->SetAmount(lAmount);
5459 
5460  pReportItem->SetTransactionNum(
5461  GetTransactionNum()); // Just making sure these both get set.
5462  pReportItem->SetReferenceToNum(
5463  GetReferenceToNum()); // Especially this one.
5464  pReportItem->SetNumberOfOrigin(GetNumberOfOrigin());
5465 
5466  // The "closing transaction number" is only used on finalReceipts and
5467  // basketReceipts.
5468  // FYI, Any cron receipts need to see if there is a corresponding final
5469  // receipt before checking
5470  // their transaction number for validity (since it changes that
5471  // number)... and also, if the final
5472  // receipt itself is present, then ALL of the cron receipts that it
5473  // corresponds to must be closed!
5474  //
5477  pReportItem->SetClosingNum(GetClosingNum());
5478 
5479  theBalanceItem.AddItem(
5480  *pReportItem); // Now theBalanceItem will handle cleaning it up.
5481 
5482  // No need to sign/save pReportItem, since it is just used for in-memory
5483  // storage, and is
5484  // otherwise saved as part of its owner's data, as part of its owner.
5485  // (As long as theBalanceItem
5486  // is signed and saved, which the caller does, then we're fine.)
5487  }
5488 }
5489 
5490 // No longer using outbox hash :(
5491 // Since I would have to add the pending items to the outbox and calculate
5492 // it myself, and there's no way every single byte would be the same as the
5493 // server
5494 // (Well with this implementation there is, actually, but what one of the items
5495 // in the outbox is SIGNED by me on one side, and by the server on the other?
5496 // the
5497 // hashes won't match!) Therefore I'm sending a real outbox report, the same as
5498 // I do for the inbox. In fact, it's the same report! Just more items being
5499 // added.
5500 //
5502 {
5503  OTItem::itemType theItemType = OTItem::error_state;
5504 
5505  switch (m_Type) {
5507  theItemType = OTItem::transfer;
5508  break;
5509  default: // All other types are irrelevant for outbox reports.
5510  otErr
5511  << "ProduceOutboxReportItem: Error, wrong item type. Returning.\n";
5512  return;
5513  }
5514 
5515  // the item will represent THIS TRANSACTION, and will be added to
5516  // theBalanceItem.
5517 
5518  OTItem* pReportItem = OTItem::CreateItemFromTransaction(*this, theItemType);
5519 
5520  if (nullptr !=
5521  pReportItem) // above line will assert if mem allocation fails.
5522  {
5523  // I get away with "carte blanche" multiplying it by -1 here, because
5524  // I've
5525  // already verified that this is ONLY an OTTransaction::transfer before
5526  // even
5527  // getting this far. There is no other transaction type that I even have
5528  // to
5529  // worry about.
5530  const int64_t lAmount =
5531  GetReceiptAmount() * (-1); // in outbox, a transfer is leaving my
5532  // account. Balance gets smaller.
5533  pReportItem->SetAmount(lAmount);
5534 
5535  pReportItem->SetTransactionNum(
5536  GetTransactionNum()); // Just making sure these both get set.
5537  pReportItem->SetReferenceToNum(
5538  GetReferenceToNum()); // Especially this one.
5539  pReportItem->SetNumberOfOrigin(GetNumberOfOrigin());
5540 
5541  theBalanceItem.AddItem(
5542  *pReportItem); // Now theBalanceItem will handle cleaning it up.
5543 
5544  // No need to sign/save pReportItem, since it is just used for in-memory
5545  // storage, and is
5546  // otherwise saved as part of its owner's data, as part of its owner.
5547  // (As long as theBalanceItem
5548  // is signed and saved, which the caller does, then we're fine.)
5549  }
5550 }
5551 
5552 // A Transaction normally doesn't have an amount. (Only a transaction item
5553 // does.)
5554 // But this function will look up the item, when appropriate, and find out the
5555 // amount.
5556 //
5557 // That way we can record it during a balance agreement.
5558 // NOTE: Not ALL transaction types with an amount are listed here,
5559 // just the ones necessary for balance agreement.
5560 //
5562 {
5563  if (IsAbbreviated()) return GetAbbrevAdjustment();
5564 
5565  int64_t lAdjustment = 0;
5566 
5567  OTItem* pOriginalItem = nullptr;
5568  std::unique_ptr<OTItem> theItemAngel;
5569 
5570  switch (GetType()) { // These are the types that have an amount (somehow)
5571  case OTTransaction::marketReceipt: // amount is stored on ** marketReceipt
5572  // item **, on MY LIST of items.
5573  pOriginalItem = GetItem(OTItem::marketReceipt); // (The Reference string
5574  // contains an
5575  // OTCronItem with the
5576  // Original Trade.)
5577  break; // The "reference to" ID is
5578  case OTTransaction::paymentReceipt: // amount is stored on ** paymentReceipt
5579  // ** item, on MY LIST of items.
5580  pOriginalItem = GetItem(OTItem::paymentReceipt);
5581  break;
5582  case OTTransaction::basketReceipt: // amount is stored on ** basketReceipt
5583  // ** item, on MY LIST of items.
5584  pOriginalItem = GetItem(OTItem::basketReceipt);
5585  break;
5586  case OTTransaction::pending: // amount is stored on the ** transfer item **,
5587  // here as reference string.
5588  case OTTransaction::chequeReceipt: // amount is stored on *cheque* (attached
5589  // to ** depositCheque ITEM **, which is
5590  // here as reference string.)
5591  case OTTransaction::voucherReceipt: // amount is stored on *voucher*
5592  // (attached to ** depositCheque ITEM
5593  // **, which is here as reference string.)
5594  case OTTransaction::transferReceipt: // amount is stored on ** acceptPending
5595  // ITEM **, (here as reference string.)
5596  {
5597  OTString strReference;
5598  GetReferenceString(strReference);
5599 
5600  pOriginalItem = OTItem::CreateItemFromString(
5601  strReference, GetPurportedServerID(), GetReferenceToNum());
5602 
5603  if (nullptr != pOriginalItem) theItemAngel.reset(pOriginalItem);
5604 
5605  break;
5606  }
5607 
5608  default: // All other types have no amount -- return 0.
5609  return 0;
5610  }
5611 
5612  if (nullptr == pOriginalItem) {
5613  otErr << "OTTransaction::" << __FUNCTION__
5614  << ": Unable to find original item. Should never happen.\n";
5615  return 0; // Should never happen, since we always expect one based on
5616  // the transaction type.
5617  }
5618 
5619  OTString strAttachment;
5620  OTCheque theCheque; // allocated on the stack :-)
5621 
5622  switch (GetType()) { // These are the types that have an amount (somehow)
5623  case OTTransaction::chequeReceipt: // amount is stored on cheque (attached
5624  // to depositCheque item, attached.)
5625  case OTTransaction::voucherReceipt: // amount is stored on voucher (attached
5626  // to depositCheque item, attached.)
5627  {
5628  if (pOriginalItem->GetType() != OTItem::depositCheque) {
5629  otErr << __FUNCTION__ << ": Wrong item type attached to "
5631  ? "chequeReceipt"
5632  : "voucherReceipt")
5633  << ". (expected depositCheque)\n";
5634  return 0;
5635  }
5636 
5637  // Get the cheque from the Item and load it up into a Cheque object.
5638  pOriginalItem->GetAttachment(strAttachment);
5639  bool bLoadContractFromString =
5640  theCheque.LoadContractFromString(strAttachment);
5641 
5642  if (!bLoadContractFromString) {
5643  OTString strCheque(theCheque);
5644 
5645  otErr << "ERROR loading cheque from string in OTTransaction::"
5646  << __FUNCTION__ << ":\n" << strCheque << "\n";
5647  }
5648  else {
5649  lAdjustment =
5650  (theCheque.GetAmount() * (-1)); // a cheque reduces my
5651  // balance, unless
5652  // it's negative.
5653  } // So if I wrote a 100 clam cheque, that means -100 hit my
5654  // account
5655  // when I got the
5656  // chequeReceipt, and writing a -100c cheque means 100 went in when
5657  // I
5658  // got the chequeReceipt.
5659  }
5660  break;
5661 
5662  // NOTE: a voucherReceipt (above) doesn't actually change your balance,
5663  // and neither does a transferReceipt. (below) But they both have a
5664  // "receipt amount" for display purposes.
5665 
5666  case OTTransaction::transferReceipt: // amount is stored on acceptPending
5667  // item. (Server refuses acceptPendings
5668  // with wrong amount on them.)
5669 
5670  if (pOriginalItem->GetType() != OTItem::acceptPending) {
5671  otErr << "Wrong item type attached to transferReceipt\n";
5672  }
5673  else { // If I transfer 100 clams to someone, then my account is
5674  // smaller by 100 clams. -100 has hit my account.
5675  // So the pending will show as -100 in my outbox, not 100, because
5676  // that is the adjustment actually made to my account.
5677  // This positive/negative aspect of pending transactions is not
5678  // stored in the data itself, since it switches based
5679  // on whether the pending appears in the inbox or the outbox. It's
5680  // based on context. Whereas the transferReceipt
5681  // is IN REFERENCE TO that same transaction--it appears in my inbox
5682  // when the recipient accepts the pending transfer
5683  // I sent him.) Therefore the transferReceipt is "worth" -100 (just
5684  // as the pending in my outbox was "worth" -100), even
5685  // though its actual value is 0.
5686  // (Since the transferReceipt itself doesn't change my balance, but
5687  // merely is a notice that such has happened.) You could
5688  // say, for example in the SaveAbbreviatedToInbox() function, that
5689  // the transferReceipt has an "actual value" of 0 and a
5690  // "display value" of -100 clams, when it is in reference to an
5691  // original transfer of 100 clams.
5692  // This function is clearly returning the display value, since the
5693  // actual value (of 0) is useless, since balance
5694  // agreements already discount transferReceipts as having any impact
5695  // on the balance.
5696  //
5697  lAdjustment = (pOriginalItem->GetAmount() * (-1));
5698  }
5699  break;
5700  case OTTransaction::pending: // amount is stored on transfer item
5701 
5702  if (pOriginalItem->GetType() != OTItem::transfer) {
5703  otErr << "Wrong item type attached to pending transfer\n";
5704  }
5705  else {
5706  // Pending transfer adds to my account if this is inbox, and removes
5707  // if outbox.
5708  // I'll let the caller multiply by (-1) or not. His choice.
5709  // Note: Indeed, if you look in ProduceOutboxReportItem(), it is
5710  // multiplying by (-1).
5711  lAdjustment = pOriginalItem->GetAmount();
5712  }
5713  break;
5714  case OTTransaction::marketReceipt: // amount is stored on marketReceipt item
5715 
5716  if (pOriginalItem->GetType() != OTItem::marketReceipt) {
5717  otErr << "Wrong item type attached to marketReceipt\n";
5718  }
5719  else {
5720  lAdjustment = pOriginalItem->GetAmount(); // THIS WILL ALSO USE THE
5721  // POSITIVE / NEGATIVE
5722  // THING. (Already.)
5723  }
5724  break;
5725  case OTTransaction::paymentReceipt: // amount is stored on paymentReceipt
5726  // item
5727 
5728  if (pOriginalItem->GetType() != OTItem::paymentReceipt) {
5729  otErr << "Wrong item type attached to paymentReceipt\n";
5730  }
5731  else {
5732  lAdjustment = pOriginalItem->GetAmount(); // THIS WILL ALSO USE THE
5733  // POSITIVE / NEGATIVE
5734  // THING. (Already.)
5735  }
5736  break;
5737  case OTTransaction::basketReceipt: // amount is stored on basketReceipt item
5738 
5739  if (pOriginalItem->GetType() != OTItem::basketReceipt) {
5740  otErr << "Wrong item type attached to basketReceipt\n";
5741  }
5742  else {
5743  lAdjustment = pOriginalItem->GetAmount(); // THIS WILL ALSO USE THE
5744  // POSITIVE / NEGATIVE
5745  // THING. (Already.)
5746  }
5747 
5748  break;
5749  default: // All other types have no amount -- return 0.
5750  return 0;
5751  }
5752 
5753  return lAdjustment;
5754 }
5755 
5756 // Need to know the transaction number of the ORIGINAL transaction? Call this.
5757 // virtual
5759 {
5760 
5761  if (0 == m_lNumberOfOrigin) {
5762  switch (GetType()) {
5763  case transferReceipt: // the server drops this into your inbox, when
5764  // someone accepts your transfer.
5765  case deposit: // this transaction is a deposit (cash or cheque)
5766  case atDeposit: // reply from the server regarding a deposit request
5767  case instrumentNotice: // Receive these in paymentInbox (by way of
5768  // Nymbox), and send in Outpayments.
5769  case instrumentRejection: // When someone rejects your invoice, you get
5770  // one of these in YOUR paymentInbox.
5771 
5772  otErr << __FUNCTION__ << ": In this case, you can't calculate the "
5773  "origin number, you must set it "
5774  "explicitly.\n";
5775  SetNumberOfOrigin(0); // Not applicable.
5776  // Comment this out later so people can't use it to crash the
5777  // server:
5778  OT_FAIL_MSG("In this case, you can't calculate the origin number, "
5779  "you must set it explicitly.");
5780  break;
5781  default:
5782  break;
5783  }
5784 
5786  }
5787 
5788  return m_lNumberOfOrigin;
5789 }
5790 
5792 {
5794 
5795  switch (GetType()) {
5796  case blank: // freshly issued transaction number, not used yet
5797  case message: // A message from one user to another, also in the nymbox.
5798  case notice: // A notice from the server. Used in Nymbox.
5799  case replyNotice: // A copy of a server reply to a previous request you
5800  // sent. (To make SURE you get the reply.)
5801  case successNotice: // A transaction # has successfully been signed out.
5802  case processNymbox: // process nymbox transaction // comes from client
5803  case atProcessNymbox: // process nymbox reply // comes from server
5804  SetNumberOfOrigin(0); // Not applicable.
5805  break;
5806 
5807  case pending: // Server puts this in your outbox (when sending) and
5808  // recipient's inbox.
5809  case marketReceipt: // server periodically drops this into your inbox if an
5810  // offer is live.
5811  case paymentReceipt: // the server drops this into people's inboxes, every
5812  // time a payment processes.
5813  case finalReceipt: // the server drops this into your in/nym box(es), when a
5814  // CronItem expires or is canceled.
5815  case basketReceipt: // the server drops this into your inboxes, when a
5816  // basket exchange is processed.
5817  SetNumberOfOrigin(GetReferenceToNum()); // pending is in
5818  // reference to the
5819  // original
5820  // transfer.
5821  break;
5822 
5823  case transferReceipt: // the server drops this into your inbox, when someone
5824  // accepts your transfer.
5825  case deposit: // this transaction is a deposit (cash or cheque)
5826  case atDeposit: // reply from the server regarding a deposit request
5827  case instrumentNotice: // Receive these in paymentInbox (by way of Nymbox),
5828  // and send in Outpayments.
5829  case instrumentRejection: // When someone rejects your invoice, you get one
5830  // of these in YOUR paymentInbox.
5831  otErr << __FUNCTION__ << ": In this case, you can't calculate the "
5832  "origin number, you must set it explicitly.\n";
5833  SetNumberOfOrigin(0); // Not applicable.
5834  // Comment this out later so people can't use it to crash the server:
5835  OT_FAIL_MSG("In this case, you can't calculate the origin number, you "
5836  "must set it explicitly.");
5837  break;
5838 
5839  case chequeReceipt: // the server drops this into your inbox, when someone
5840  // deposits your cheque.
5841  case voucherReceipt: // the server drops this into your inbox, when someone
5842  // deposits your voucher.
5843  {
5844  OTString strReference;
5845  GetReferenceString(strReference);
5846 
5847  // "In reference to" is the depositor's trans#, which I use here to
5848  // load
5849  // the depositor's
5850  // depositCheque item, which I use to get the cheque, which contains
5851  // the
5852  // number of origin
5853  // as its transaction number.
5854  //
5855  std::unique_ptr<OTItem> pOriginalItem(OTItem::CreateItemFromString(
5856  strReference, GetPurportedServerID(), GetReferenceToNum()));
5857  OT_ASSERT(nullptr != pOriginalItem);
5858 
5859  if (OTItem::depositCheque != pOriginalItem->GetType()) {
5860  otErr << __FUNCTION__ << ": ERROR: Wrong item type attached to "
5861  << ((chequeReceipt == GetType()) ? "chequeReceipt"
5862  : "voucherReceipt")
5863  << " "
5864  "(expected OTItem::depositCheque)\n";
5865  SetNumberOfOrigin(0);
5866  return;
5867  }
5868 
5869  SetNumberOfOrigin(pOriginalItem->GetNumberOfOrigin());
5870  }
5871  break;
5872 
5873  case processInbox: // process inbox transaction // comes from client
5874  case atProcessInbox: // process inbox reply // comes from server
5875 
5876  case transfer: // or "spend". This transaction is a request to transfer from
5877  // one account to another
5878  case atTransfer: // reply from the server regarding a transfer request
5879 
5880  case withdrawal: // this transaction is a withdrawal (cash or voucher)
5881  case atWithdrawal: // reply from the server regarding a withdrawal request
5882 
5883  case marketOffer: // this transaction is a market offer
5884  case atMarketOffer: // reply from the server regarding a market offer
5885 
5886  case paymentPlan: // this transaction is a payment plan
5887  case atPaymentPlan: // reply from the server regarding a payment plan
5888 
5889  case smartContract: // this transaction is a smart contract
5890  case atSmartContract: // reply from the server regarding a smart contract
5891 
5892  case cancelCronItem: // this transaction is intended to cancel a market
5893  // offer or payment plan.
5894  case atCancelCronItem: // reply from the server regarding said cancellation.
5895 
5896  case exchangeBasket: // this transaction is an exchange in/out of a basket
5897  // currency.
5898  case atExchangeBasket: // reply from the server regarding said exchange.
5899 
5900  case payDividend: // this transaction is dividend payment (to all
5901  // shareholders...)
5902  case atPayDividend: // reply from the server regarding said dividend
5903  // payment.
5904 
5905  default:
5907  break;
5908  } // switch
5909 }
5910 
5946 {
5947  if (IsAbbreviated()) return GetAbbrevInRefDisplay();
5948 
5949  int64_t lReferenceNum = 0;
5950 
5951  switch (GetType()) {
5952  // "in ref to #" is stored on me: GetReferenceToNum()
5954  case OTTransaction::notice:
5963  lReferenceNum = GetReferenceToNum();
5964  break;
5965 
5966  // A transferReceipt ACTUALLY references the acceptPending (recipient's
5967  // trans#) that accepted it.
5968  // But I don't care about the recipient's transaction #s! This function is
5969  // for DISPLAY. I am the sender,
5970  // and I want to see a reference to my original transfer that I sent. This
5971  // receipt, as far as I care,
5972  // is for THAT TRANSFER.
5976  lReferenceNum = GetNumberOfOrigin();
5977  break;
5978 
5979  default: // All other types have no amount -- return 0.
5980  return 0;
5981  }
5982 
5983  return lReferenceNum;
5984 }
5985 
5986 // Decoding and understanding the various subtleties of the marketReceipt
5987 // transaction!!!
5988 //
5989 // For a marketReceipt transaction, the transaction itself carries a NEW
5990 // TRANSACTION ID for EACH RECEIPT.
5991 // I might have many trades process against a single offer. Each time, the
5992 // marketReceipt will be a fresh one,
5993 // with its own fresh transaction number that's owned by the server.
5994 //
5995 // The marketReceipt's "reference to" is for the original Trade, placed by the
5996 // trader, owned by the trader.
5997 //
5998 // 1. pTrans1->SetReferenceToNum(theTrade.GetTransactionNum());
5999 // 2. pTrans1->SetReferenceString(strOrigTrade);
6000 //
6001 // In 2, the Reference String contains the ORIGINAL TRADE, signed by the TRADER.
6002 //
6003 // The marketReceipt transaction is SIGNED by the SERVER, AS IS the
6004 // marketReceipt Item on its list.
6005 // but the original trade was signed by the TRADER. The marketReceipt is in
6006 // REFERENCE to that
6007 // original trade, and so references its number and contains its complete string
6008 // as the reference.
6009 //
6010 // The Item is a marketReceipt item, which is on the "my list of items" for the
6011 // marketReceipt transaction.
6012 // It is signed by the server, and it bears a transaction number that's owned by
6013 // the server.
6014 // The ITEM also contains the AMOUNT for the CURRENT RECEIPT. If THIS trade
6015 // deducted 50 clams from your
6016 // account, then THIS ITEM will have an AMOUNT of -50 on THIS RECEIPT!
6017 
6018 // The item has two attachments... The NOTE, which contains the updated
6019 // (server-signed) TRADE, and
6020 // the ATTACHMENT, which contains the updated (server-signed) OFFER. Both should
6021 // have the same transaction
6022 // number as pTrans->ReferenceTo().
6023 //
6024 // 3. pItem1->SetNote(strTrade);
6025 // 4. pItem1->SetAttachment(strOffer);
6026 //
6027 
6029 {
6030  if (IsAbbreviated()) return false;
6031 
6032  bool bSuccess = false;
6033 
6034  OTItem* pOriginalItem = nullptr;
6035  std::unique_ptr<OTItem> theItemAngel;
6036 
6037  OTString strReference;
6038  GetReferenceString(strReference);
6039 
6040  if (strReference.GetLength() < 2) return false;
6041 
6042  switch (GetType()) {
6043  case OTTransaction::paymentReceipt: // for paymentPlans AND smartcontracts.
6044  // (If the smart contract does a
6045  // payment, it leaves a paymentReceipt...)
6046  {
6047  OTString strUpdatedCronItem;
6049 
6050  if (nullptr != pItem)
6051  pItem->GetAttachment(strUpdatedCronItem);
6052  else
6053  otErr << "OTTransaction::" << __FUNCTION__
6054  << ": Failed trying to get paymentReceipt item from "
6055  "paymentReceipt transaction.\n";
6056 
6057  std::unique_ptr<OTCronItem> pCronItem(
6058  OTCronItem::NewCronItem(strUpdatedCronItem));
6059 
6060  OTSmartContract* pSmart =
6061  dynamic_cast<OTSmartContract*>(pCronItem.get());
6062 
6063  if (nullptr != pSmart) // if it's a smart contract...
6064  {
6065  if (!pSmart->GetLastSenderUserID().Exists()) return false;
6066 
6067  theReturnID.SetString(pSmart->GetLastSenderUserID());
6068  return true;
6069  }
6070  else if (nullptr != pCronItem) // else if it is any other kind of
6071  // cron item...
6072  {
6073  theReturnID = pCronItem->GetSenderUserID();
6074  return true;
6075  }
6076  else {
6077  otErr << "OTTransaction::" << __FUNCTION__
6078  << ": Unable to load Cron Item. Should never happen. "
6079  "Receipt: " << GetTransactionNum()
6080  << " Origin: " << GetNumberOfOrigin() << "\n";
6081  return false;
6082  }
6083  break;
6084  }
6085 
6087  /*
6088  Therefore, if I am looping through my Nymbox, iterating through
6089  transactions, and one of them
6090  is an *** instrumentNotice *** then I should expect
6091  GetReferenceString(strOutput) to:
6092 
6093  1. load up from string as an OTMessage of type "sendUserInstrument",
6094  -------------------------------------------------------------------
6095  2. and I should expect the PAYLOAD of that message to contain an
6096  encrypted OTEnvelope,
6097  3. which can be decrypted by Msg.m_strNymID2's private key,
6098  4. And the resulting plaintext can be loaded into memory as an
6099  OTPayment object,
6100  5. ...which contains an instrument of ambiguous type.
6101  -------------------------------------------------------------------
6102  FYI:
6103  OTPayment provides a consistent interface, and consolidation of
6104  handling, for
6105  the several financial instruments that appear on the PAYMENTS page, in
6106  the PaymentsInbox.
6107  For example:
6108  [ Cheques, Invoices, Vouchers ],
6109  Payment Plans, Smart Contracts, ...and Purses.
6110  -------------------------------------------------------------------
6111  (In this block we don't need to go any farther than step 1 above.)
6112  -------------------------------------------------------------------
6113  */
6114  // OTString strReference; // (Already done above.)
6115  // GetReferenceString(strReference); // (Already done above.)
6116 
6117  OTMessage theSentMsg;
6118 
6119  if (strReference.Exists() &&
6120  theSentMsg.LoadContractFromString(strReference)) {
6121  // All we need is this message itself. We aren't going to decrypt
6122  // the payload, we're just going to grab the sender/receiver data
6123  // from the msg.
6124  //
6125  // We can't decrypt the payload (the OTPayment object) but we still
6126  // have sender / recipient.
6127  // todo security need to consider security implications of that and
6128  // maybe improve it a bit.
6129  // (But I do NOT want to get into the messaging business.)
6130 
6131  if (theSentMsg.m_strNymID.Exists()) {
6132  theReturnID.SetString(theSentMsg.m_strNymID);
6133  return true;
6134  }
6135  }
6136  return false;
6137  }
6138 
6142  pOriginalItem = OTItem::CreateItemFromString(
6143  strReference, GetPurportedServerID(), GetReferenceToNum());
6144 
6145  if (nullptr != pOriginalItem) theItemAngel.reset(pOriginalItem);
6146 
6147  break;
6148  }
6149 
6150  default: // All other types are irrelevant here.
6151  return false;
6152  }
6153 
6154  if (nullptr == pOriginalItem) {
6155  otErr << "OTTransaction::GetSenderUserIDForDisplay: original item not "
6156  "found. Should never happen.\n";
6157  return false; // Should never happen, since we always expect one based
6158  // on the transaction type.
6159  }
6160 
6161  OTCheque theCheque; // allocated on the stack :-)
6162  OTString strAttachment;
6163 
6164  switch (GetType()) { // These are the types that have an amount (somehow)
6165  case OTTransaction::chequeReceipt: // amount is stored on cheque (attached
6166  // to depositCheque item, attached.)
6167  case OTTransaction::voucherReceipt: // amount is stored on voucher (attached
6168  // to depositCheque item, attached.)
6169  {
6170  if (pOriginalItem->GetType() != OTItem::depositCheque) {
6171  otErr << __FUNCTION__ << ": Wrong item type attached to "
6173  ? "chequeReceipt"
6174  : "voucherReceipt")
6175  << " (expected depositCheque)\n";
6176  return false;
6177  }
6178 
6179  // Get the cheque from the Item and load it up into a Cheque object.
6180  pOriginalItem->GetAttachment(strAttachment);
6181  bool bLoadContractFromString =
6182  theCheque.LoadContractFromString(strAttachment);
6183 
6184  if (!bLoadContractFromString) {
6185  OTString strCheque(theCheque);
6186 
6187  otErr << "ERROR loading cheque or voucher from string in "
6188  "OTTransaction::" << __FUNCTION__ << ":\n" << strCheque
6189  << "\n";
6190  }
6191  else {
6193  theReturnID = theCheque.GetSenderUserID();
6194  else
6195  theReturnID = theCheque.GetRemitterUserID();
6196 
6197  bSuccess = true;
6198  }
6199  }
6200  break;
6201 
6202  case OTTransaction::pending: // amount is stored on transfer item
6203 
6204  if (pOriginalItem->GetType() != OTItem::transfer) {
6205  otErr << "Wrong item type attached to pending transfer\n";
6206  }
6207  else {
6208  theReturnID = pOriginalItem->GetUserID();
6209  bSuccess = true;
6210  }
6211  break;
6212  default: // All other types have no sender user ID -- return false.
6213  return false;
6214  }
6215 
6216  return bSuccess;
6217 }
6218 
6220 {
6221  if (IsAbbreviated()) return false;
6222 
6223  bool bSuccess = false;
6224 
6225  OTItem* pOriginalItem = nullptr;
6226  std::unique_ptr<OTItem> theItemAngel;
6227 
6228  OTString strReference;
6229  GetReferenceString(strReference);
6230 
6231  switch (GetType()) {
6232  case OTTransaction::paymentReceipt: // Used for paymentPlans AND for smart
6233  // contracts...
6234  {
6235  OTString strUpdatedCronItem;
6237 
6238  if (nullptr != pItem)
6239  pItem->GetAttachment(strUpdatedCronItem);
6240  else
6241  otErr << "OTTransaction::" << __FUNCTION__
6242  << ": Failed trying to get paymentReceipt item from "
6243  "paymentReceipt transaction.\n";
6244 
6245  std::unique_ptr<OTCronItem> pCronItem(
6246  OTCronItem::NewCronItem(strUpdatedCronItem));
6247 
6248  OTSmartContract* pSmart =
6249  dynamic_cast<OTSmartContract*>(pCronItem.get());
6250  OTPaymentPlan* pPlan =
6251  dynamic_cast<OTPaymentPlan*>(pCronItem.get());
6252 
6253  if (nullptr != pSmart) // if it's a smart contract...
6254  {
6255  if (!pSmart->GetLastRecipientUserID().Exists()) return false;
6256 
6257  theReturnID.SetString(pSmart->GetLastRecipientUserID());
6258  return true;
6259  }
6260  else if (nullptr !=
6261  pPlan) // else if it is any other kind of cron item...
6262  {
6263  theReturnID = pPlan->GetRecipientUserID();
6264  return true;
6265  }
6266  else {
6267  otErr << "OTTransaction::" << __FUNCTION__
6268  << ": Unable to load Cron Item. Should never happen. "
6269  "Receipt: " << GetTransactionNum()
6270  << " Origin: " << GetNumberOfOrigin() << "\n";
6271  return false;
6272  }
6273  }
6274  break; // this break never actually happens. Above always returns, if
6275  // triggered.
6276 
6278  /*
6279  Therefore, if I am looping through my Nymbox, iterating through
6280  transactions, and one of them
6281  is an *** instrumentNotice *** then I should expect
6282  GetReferenceString(strOutput) to:
6283 
6284  1. load up from string as an OTMessage of type "sendUserInstrument",
6285  -------------------------------------------------------------------
6286  2. and I should expect the PAYLOAD of that message to contain an
6287  encrypted OTEnvelope,
6288  3. which can be decrypted by Msg.m_strNymID2's private key,
6289  4. And the resulting plaintext can be loaded into memory as an
6290  OTPayment object,
6291  5. ...which contains an instrument of ambiguous type.
6292  -------------------------------------------------------------------
6293  FYI:
6294  OTPayment provides a consistent interface, and consolidation of
6295  handling, for
6296  the several financial instruments that appear on the PAYMENTS page, in
6297  the PaymentsInbox.
6298  For example:
6299  [ Cheques, Invoices, Vouchers ],
6300  Payment Plans, Smart Contracts, ...and Purses.
6301  -------------------------------------------------------------------
6302  (In this block we don't need to go any farther than step 1 above.)
6303  -------------------------------------------------------------------
6304  */
6305 
6306  OTMessage theSentMsg;
6307 
6308  if (strReference.Exists() &&
6309  theSentMsg.LoadContractFromString(strReference)) {
6310  // All we need is this message itself. We aren't going to decrypt
6311  // the payload, we're just going to grab the sender/receiver data
6312  // from the msg.
6313  //
6314  // We can't decrypt the payload (the OTPayment object) but we still
6315  // have sender / recipient.
6316  // todo security need to consider security implications of that and
6317  // maybe improve it a bit.
6318  // (But I do NOT want to get into the messaging business.)
6319 
6320  if (theSentMsg.m_strNymID2.Exists()) {
6321  theReturnID.SetString(theSentMsg.m_strNymID2);
6322  return true;
6323  }
6324  }
6325  return false;
6326  } break;
6327 
6331  pOriginalItem = OTItem::CreateItemFromString(
6332  strReference, GetPurportedServerID(), GetReferenceToNum());
6333 
6334  if (nullptr != pOriginalItem) theItemAngel.reset(pOriginalItem);
6335 
6336  break;
6337  }
6338  default: // All other types have no amount -- return false.
6339  return false;
6340  }
6341 
6342  if (nullptr == pOriginalItem)
6343  return false; // Should never happen, since we always expect one based
6344  // on the transaction type.
6345 
6346  OTCheque theCheque; // allocated on the stack :-)
6347  OTString strAttachment;
6348 
6349  switch (GetType()) {
6351  if (pOriginalItem->GetType() != OTItem::acceptPending) {
6352  otErr << "Wrong item type attached to transferReceipt\n";
6353  return false;
6354  }
6355  else {
6356  theReturnID = pOriginalItem->GetUserID(); // Even though a transfer
6357  // has no recipient user
6358  // (just a recipient acct)
6359  // I still get the User ID
6360  // when he accepts it!
6361  bSuccess = true;
6362  }
6363  } break;
6364 
6365  case OTTransaction::chequeReceipt: // amount is stored on cheque (attached
6366  // to depositCheque item, attached.)
6367  case OTTransaction::voucherReceipt: // amount is stored on voucher (attached
6368  // to depositCheque item, attached.)
6369  {
6370  if (pOriginalItem->GetType() != OTItem::depositCheque) {
6371  otErr << __FUNCTION__ << ": Wrong item type attached to "
6373  ? "chequeReceipt"
6374  : "voucherReceipt")
6375  << " (expected depositCheque)\n";
6376  return false;
6377  }
6378 
6379  // Get the cheque from the Item and load it up into a Cheque object.
6380  pOriginalItem->GetAttachment(strAttachment);
6381  bool bLoadContractFromString =
6382  theCheque.LoadContractFromString(strAttachment);
6383 
6384  if (!bLoadContractFromString) {
6385  OTString strCheque(theCheque);
6386 
6387  otErr << "ERROR loading cheque or voucher from string in "
6388  "OTTransaction::" << __FUNCTION__ << ":\n" << strCheque
6389  << "\n";
6390  }
6391  else if (theCheque.HasRecipient()) {
6392  theReturnID = theCheque.GetRecipientUserID();
6393  bSuccess = true;
6394  }
6395  else {
6396  theReturnID =
6397  pOriginalItem->GetUserID(); // Even though the cheque
6398  // has no recipient, I
6399  // still get the User ID
6400  // when he deposits it!
6401  bSuccess = true;
6402  }
6403  }
6404  break;
6405 
6406  default: // All other types have no recipient user ID -- return false.
6407  return false;
6408  }
6409 
6410  return bSuccess;
6411 }
6412 
6414 {
6415  if (IsAbbreviated()) return false;
6416 
6417  bool bSuccess = false;
6418 
6419  OTItem* pOriginalItem = nullptr;
6420  std::unique_ptr<OTItem> theItemAngel;
6421 
6422  OTString strReference;
6423  GetReferenceString(strReference);
6424 
6425  if (strReference.GetLength() < 2) return false;
6426 
6427  switch (GetType()) {
6429  OTString strUpdatedCronItem;
6431 
6432  if (nullptr != pItem)
6433  pItem->GetAttachment(strUpdatedCronItem);
6434  else
6435  otErr << "OTTransaction::" << __FUNCTION__
6436  << ": Failed trying to get paymentReceipt item from "
6437  "paymentReceipt transaction.\n";
6438 
6439  std::unique_ptr<OTCronItem> pCronItem(
6440  OTCronItem::NewCronItem(strUpdatedCronItem));
6441 
6442  OTSmartContract* pSmart =
6443  dynamic_cast<OTSmartContract*>(pCronItem.get());
6444 
6445  if (nullptr != pSmart) // if it's a smart contract...
6446  {
6447  if (!pSmart->GetLastSenderAcctID().Exists()) return false;
6448 
6449  theReturnID.SetString(pSmart->GetLastSenderAcctID());
6450  return true;
6451  }
6452  else if (nullptr !=
6453  pCronItem) // else if it is any other kind of cron item...
6454  {
6455  theReturnID = pCronItem->GetSenderAcctID();
6456  return true;
6457  }
6458  else {
6459  otErr
6460  << "OTTransaction::" << __FUNCTION__
6461  << ": Unable to load Cron Item. Should never happen. Receipt: "
6462  << GetTransactionNum() << " Origin: " << GetNumberOfOrigin()
6463  << "\n";
6464  return false;
6465  }
6466  } break;
6467  case OTTransaction::pending: // amount is stored on the transfer item, on my
6468  // list of items.
6469  case OTTransaction::chequeReceipt: // amount is stored on cheque (attached
6470  // to depositCheque item, attached.)
6471  case OTTransaction::voucherReceipt: // amount is stored on voucher (attached
6472  // to depositCheque item, attached.)
6473  {
6474  pOriginalItem = OTItem::CreateItemFromString(
6475  strReference, GetPurportedServerID(), GetReferenceToNum());
6476 
6477  if (nullptr != pOriginalItem) theItemAngel.reset(pOriginalItem);
6478 
6479  break;
6480  }
6481  default: // All other types have no sender acct ID -- return false.
6482  return false;
6483  }
6484 
6485  if (nullptr == pOriginalItem) {
6486  otErr << "OTTransaction::" << __FUNCTION__
6487  << ": couldn't load original item, should never happen. \n";
6488  return false; // Should never happen, since we always expect one based
6489  // on the transaction type.
6490  }
6491 
6492  OTCheque theCheque; // allocated on the stack :-)
6493  OTString strAttachment;
6494 
6495  switch (GetType()) { // These are the types that have an amount (somehow)
6496  case OTTransaction::chequeReceipt: // amount is stored on cheque (attached
6497  // to depositCheque item, attached.)
6498  case OTTransaction::voucherReceipt: // amount is stored on voucher (attached
6499  // to depositCheque item, attached.)
6500  {
6501  if (pOriginalItem->GetType() != OTItem::depositCheque) {
6502  otErr << __FUNCTION__ << ": Wrong item type attached to "
6504  ? "chequeReceipt"
6505  : "voucherReceipt")
6506  << " (expected depositCheque)\n";
6507  return false;
6508  }
6509 
6510  // Get the cheque from the Item and load it up into a Cheque object.
6511  pOriginalItem->GetAttachment(strAttachment);
6512  bool bLoadContractFromString =
6513  theCheque.LoadContractFromString(strAttachment);
6514 
6515  if (!bLoadContractFromString) {
6516  OTString strCheque(theCheque);
6517 
6518  otErr << "ERROR loading cheque from string in OTTransaction::"
6519  << __FUNCTION__ << ":\n" << strCheque << "\n";
6520  }
6521  else {
6523  theReturnID = theCheque.GetSenderAcctID();
6524  else
6525  theReturnID = theCheque.GetRemitterAcctID();
6526 
6527  bSuccess = true;
6528  }
6529  }
6530  break;
6531 
6532  case OTTransaction::pending: // amount is stored on transfer item
6533 
6534  if (pOriginalItem->GetType() != OTItem::transfer) {
6535  otErr << "Wrong item type attached to pending transfer\n";
6536  }
6537  else {
6538  theReturnID = pOriginalItem->GetPurportedAccountID();
6539  bSuccess = true;
6540  }
6541  break;
6542 
6543  default: // All other types have no amount -- return 0.
6544  return false;
6545  }
6546 
6547  return bSuccess;
6548 }
6549 
6551 {
6552  if (IsAbbreviated()) return false;
6553 
6554  bool bSuccess = false;
6555 
6556  OTItem* pOriginalItem = nullptr;
6557  std::unique_ptr<OTItem> theItemAngel;
6558 
6559  OTString strReference;
6560  GetReferenceString(strReference);
6561 
6562  switch (GetType()) {
6564  OTString strUpdatedCronItem;
6566 
6567  if (nullptr != pItem)
6568  pItem->GetAttachment(strUpdatedCronItem);
6569  else
6570  otErr << "OTTransaction::" << __FUNCTION__
6571  << ": Failed trying to get paymentReceipt item from "
6572  "paymentReceipt transaction.\n";
6573 
6574  std::unique_ptr<OTCronItem> pCronItem(
6575  OTCronItem::NewCronItem(strUpdatedCronItem));
6576 
6577  OTSmartContract* pSmart =
6578  dynamic_cast<OTSmartContract*>(pCronItem.get());
6579  OTPaymentPlan* pPlan = dynamic_cast<OTPaymentPlan*>(pCronItem.get());
6580 
6581  if (nullptr != pSmart) // if it's a smart contract...
6582  {
6583  if (!pSmart->GetLastRecipientAcctID().Exists()) return false;
6584 
6585  theReturnID.SetString(pSmart->GetLastRecipientAcctID());
6586  return true;
6587  }
6588  else if (nullptr != pPlan) // else if it's a payment plan.
6589  {
6590  theReturnID = pPlan->GetRecipientAcctID();
6591  return true;
6592  }
6593  else // else if it is any other kind of cron item...
6594  {
6595  otErr
6596  << "OTTransaction::" << __FUNCTION__
6597  << ": Unable to load Cron Item. Should never happen. Receipt: "
6598  << GetTransactionNum() << " Origin: " << GetNumberOfOrigin()
6599  << "\n";
6600  return false;
6601  }
6602  } break; // this break never actually happens. Above always returns, if
6603  // triggered.
6604 
6609  pOriginalItem = OTItem::CreateItemFromString(
6610  strReference, GetPurportedServerID(), GetReferenceToNum());
6611 
6612  if (nullptr != pOriginalItem) theItemAngel.reset(pOriginalItem);
6613 
6614  break;
6615  }
6616  default: // All other types have no amount -- return 0.
6617  return false;
6618  }
6619 
6620  if (nullptr == pOriginalItem)
6621  return false; // Should never happen, since we always expect one based
6622  // on the transaction type.
6623 
6624  OTCheque theCheque; // allocated on the stack :-)
6625  OTString strAttachment;
6626 
6627  switch (GetType()) {
6629  if (pOriginalItem->GetType() != OTItem::acceptPending) {
6630  otErr << "Wrong item type attached to transferReceipt\n";
6631  return false;
6632  }
6633  else {
6634  theReturnID = pOriginalItem->GetPurportedAccountID();
6635  bSuccess = true;
6636  }
6637  } break;
6638 
6641  if (pOriginalItem->GetType() != OTItem::depositCheque) {
6642  otErr << __FUNCTION__ << ": Wrong item type attached to "
6644  ? "chequeReceipt"
6645  : "voucherReceipt") << " (expected depositCheque)\n";
6646  return false;
6647  }
6648  else {
6649  theReturnID = pOriginalItem->GetPurportedAccountID(); // Here's the
6650  // depositor's account
6651  // ID (even though the
6652  // cheque was made out
6653  // to a user, not an
6654  // account, it still
6655  // eventually had to be
6656  // DEPOSITED into an
6657  // account... right?)
6658  bSuccess = true;
6659  }
6660  } break;
6661 
6662  case OTTransaction::pending: // amount is stored on transfer item
6663 
6664  if (pOriginalItem->GetType() != OTItem::transfer) {
6665  otErr << "Wrong item type attached to pending transfer\n";
6666  }
6667  else {
6668  theReturnID = pOriginalItem->GetDestinationAcctID();
6669  bSuccess = true;
6670  }
6671  break;
6672 
6673  default: // All other types have no amount -- return 0.
6674  return false;
6675  }
6676 
6677  return bSuccess;
6678 }
6679 
6681 {
6682  if (IsAbbreviated()) return false;
6683 
6684  bool bSuccess = false;
6685 
6686  OTItem* pOriginalItem = nullptr;
6687  std::unique_ptr<OTItem> theItemAngel;
6688 
6689  OTString strReference;
6690  GetReferenceString(strReference);
6691 
6692  switch (GetType()) {
6694  OTString strUpdatedCronItem;
6696 
6697  if (nullptr != pItem)
6698  pItem->GetAttachment(strUpdatedCronItem);
6699  else
6700  otErr << "OTTransaction::" << __FUNCTION__
6701  << ": Failed trying to get paymentReceipt item from "
6702  "paymentReceipt transaction.\n";
6703 
6704  std::unique_ptr<OTCronItem> pCronItem(
6705  OTCronItem::NewCronItem(strUpdatedCronItem));
6706 
6707  OTSmartContract* pSmart =
6708  dynamic_cast<OTSmartContract*>(pCronItem.get());
6709  OTPaymentPlan* pPlan = dynamic_cast<OTPaymentPlan*>(pCronItem.get());
6710 
6711  if (nullptr != pSmart) // if it's a smart contract...
6712  {
6713  // NOTE: smart contracts currently do not have a "memo" field.
6714 
6715  return false;
6716  }
6717  else if (nullptr != pPlan) // else if it is a payment plan.
6718  {
6719  if (pPlan->GetConsideration().Exists())
6720  strMemo.Set(pPlan->GetConsideration());
6721 
6722  return true;
6723  }
6724  else // else if it's any other kind of cron item.
6725  {
6726  otErr
6727  << "OTTransaction::" << __FUNCTION__
6728  << ": Unable to load Cron Item. Should never happen. Receipt: "
6729  << GetTransactionNum() << " Origin: " << GetNumberOfOrigin()
6730  << "\n";
6731  return false;
6732  }
6733  } break; // this break never actually happens. Above always returns, if
6734  // triggered.
6735 
6740  pOriginalItem = OTItem::CreateItemFromString(
6741  strReference, GetPurportedServerID(), GetReferenceToNum());
6742 
6743  if (nullptr != pOriginalItem) theItemAngel.reset(pOriginalItem);
6744 
6745  break;
6746  }
6747  default:
6748  return false;
6749  }
6750 
6751  if (nullptr == pOriginalItem)
6752  return false; // Should never happen, since we always expect one based
6753  // on the transaction type.
6754 
6755  OTCheque theCheque; // allocated on the stack :-)
6756  OTString strAttachment;
6757 
6758  switch (GetType()) {
6760  if (pOriginalItem->GetType() != OTItem::acceptPending) {
6761  otErr << __FUNCTION__
6762  << ": Wrong item type attached to transferReceipt\n";
6763  return false;
6764  }
6765  else {
6766  pOriginalItem->GetNote(strMemo);
6767  bSuccess = strMemo.Exists();
6768  }
6769  } break;
6770 
6773  if (pOriginalItem->GetType() != OTItem::depositCheque) {
6774  otErr << __FUNCTION__ << ": Wrong item type attached to "
6776  ? "chequeReceipt"
6777  : "voucherReceipt") << " (expected depositCheque)\n";
6778  return false;
6779  }
6780  else {
6781  OTCheque theCheque;
6782  OTString strCheque;
6783  pOriginalItem->GetAttachment(strCheque);
6784 
6785  if (!((strCheque.GetLength() > 2) &&
6786  theCheque.LoadContractFromString(strCheque))) {
6787  otErr << __FUNCTION__
6788  << ": Error loading cheque or voucher from string:\n"
6789  << strCheque << "\n";
6790  return false;
6791  }
6792 
6793  // Success loading the cheque.
6794  strMemo = theCheque.GetMemo();
6795  bSuccess = strMemo.Exists();
6796  }
6797  } break;
6798 
6800 
6801  if (pOriginalItem->GetType() != OTItem::transfer) {
6802  otErr << __FUNCTION__
6803  << ": Wrong item type attached to pending transfer\n";
6804  }
6805  else {
6806  pOriginalItem->GetNote(strMemo);
6807  bSuccess = strMemo.Exists();
6808  }
6809  break;
6810 
6811  default:
6812  return false;
6813  }
6814 
6815  return bSuccess;
6816 }
6817 
6818 } // namespace opentxs
virtual void UpdateContents()
void AddItem(OTItem &theItem)
Definition: OTItem.cpp:1052
EXPORT bool StorePlainString(std::string strContents, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:698
EXPORT void GetReferenceString(OTString &theStr) const
const OTString & GetLastRecipientUserID() const
OTLOG_IMPORT OTLogStream otLog4
virtual EXPORT bool LoadContract()
Definition: OTAccount.cpp:372
void SetAmount(int64_t lAmount)
Definition: OTItem.hpp:479
virtual EXPORT ~OTTransaction()
int32_t LoadAbbreviatedRecord(irr::io::IrrXMLReader *&xml, int64_t &lNumberOfOrigin, int64_t &lTransactionNum, int64_t &lInRefTo, int64_t &lInRefDisplay, time64_t &the_DATE_SIGNED, int &theType, OTString &strHash, int64_t &lAdjustment, int64_t &lDisplayValue, int64_t &lClosingNum, int64_t &lRequestNum, bool &bReplyTransSuccess, OTNumList *pNumList=nullptr)
Definition: Helpers.cpp:218
EXPORT bool GetSenderAcctIDForDisplay(OTIdentifier &theReturnID)
static EXPORT OTTransaction * GenerateTransaction(const OTIdentifier &theUserID, const OTIdentifier &theAccountID, const OTIdentifier &theServerID, transactionType theType, int64_t lTransactionNum=0)
void SaveAbbrevExpiredBoxRecord(OTString &strOutput)
static EXPORT OTItem * CreateItemFromString(const OTString &strItem, const OTIdentifier &theServerID, int64_t lTransactionNumber)
Definition: OTItem.cpp:1473
EXPORT void SetNumberOfOrigin(int64_t lTransactionNum)
const OTString & GetLastSenderAcctID() const
EXPORT bool AddNumbersToTransaction(const OTNumList &theAddition)
const OTIdentifier & GetSenderUserID() const
OTItem * GetItem(int32_t nIndex)
Definition: OTItem.cpp:1059
void SaveAbbrevRecordBoxRecord(OTString &strOutput)
EXPORT bool ClawbackTransactionNumber(const OTIdentifier &theServerID, const int64_t &lTransClawback, bool bSave=false, OTPseudonym *pSIGNER_NYM=nullptr)
EXPORT bool LoadFromString(const OTString &strNym, OTString::Map *pMapCredentials=nullptr, OTString *pstrReason=nullptr, const OTPassword *pImportPassword=nullptr)
void SaveAbbreviatedInboxRecord(OTString &strOutput)
EXPORT void GetAttachment(OTString &theStr) const
Definition: OTItem.cpp:1397
bool HarvestClosingNumbers(OTPseudonym &theNym, bool bHarvestingForRetry, bool bReplyWasSuccess, bool bReplyWasFailure, bool bTransactionWasSuccess, bool bTransactionWasFailure)
virtual EXPORT int64_t GetNumberOfOrigin()
virtual void HarvestClosingNumbers(OTPseudonym &theNym)
void SetTransactionNum(int64_t lTransactionNum)
const OTLedger * m_pParent
EXPORT void Release()
Definition: OTNumList.cpp:465
static EXPORT OTTransactionType * TransactionFactory(OTString strInput)
EXPORT int64_t GetBalance() const
Definition: OTAccount.cpp:664
const int64_t & GetAmount() const
Definition: OTCheque.hpp:172
EXPORT bool DeleteBoxReceipt(OTLedger &theLedger)
const OTString & GetLastRecipientAcctID() const
EXPORT bool VerifyIssuedNum(const OTString &strServerID, const int64_t &lTransNum) const
EXPORT bool GetRecipientAcctIDForDisplay(OTIdentifier &theReturnID)
int64_t GetAbbrevAdjustment() const
static EXPORT const char * PathSeparator()
Definition: OTLog.cpp:408
virtual void HarvestOpeningNumber(OTPseudonym &theNym)
EXPORT OTLedger * LoadOutbox(OTPseudonym &nym) const
Definition: OTAccount.cpp:242
virtual bool VerifyAccount(const OTPseudonym &theNym)
int64_t GetNewOutboxTransNum() const
Definition: OTItem.hpp:430
void SaveAbbreviatedNymboxRecord(OTString &strOutput)
EXPORT OTItem * GetItemInRefTo(int64_t lReference)
void SaveAbbrevPaymentInboxRecord(OTString &strOutput)
OTLOG_IMPORT OTLogStream otOut
void SetRealAccountID(const OTIdentifier &theID)
EXPORT void GetNote(OTString &theStr) const
Definition: OTItem.cpp:1430
OTLOG_IMPORT OTLogStream otLog3
EXPORT bool GetSenderUserIDForDisplay(OTIdentifier &theReturnID)
EXPORT bool SaveContractRaw(OTString &strOutput) const
const OTIdentifier & GetRemitterAcctID() const
Definition: OTCheque.hpp:188
EXPORT uint32_t GetLength() const
Definition: OTString.cpp:1040
time64_t OTTimeGetTimeFromSeconds(int64_t seconds)
Definition: Common.hpp:215
bool HasRecipient() const
Definition: OTCheque.hpp:180
EXPORT void Concatenate(const char *arg,...)
Definition: OTString.cpp:1334
int64_t time64_t
Definition: Common.hpp:209
void SetRealServerID(const OTIdentifier &theID)
EXPORT bool WriteArmoredString(OTString &strOutput, const std::string str_type, bool bEscaped=false) const
OTItem * GetFinalReceiptItemByReferenceNum(int64_t lReferenceNumber)
Definition: OTItem.cpp:1110
EXPORT int64_t GetRecipientOpeningNum() const
const OTString & GetMemo() const
Definition: OTCheque.hpp:168
static EXPORT OTItem * CreateItemFromTransaction(const OTTransaction &theOwner, OTItem::itemType theType, const OTIdentifier *pDestinationAcctID=nullptr)
Definition: OTItem.cpp:1451
OTItem * GetItemByTransactionNum(int64_t lTransactionNumber)
Definition: OTItem.cpp:1076
EXPORT bool Exists() const
Definition: OTString.cpp:1035
EXPORT bool SetString(const OTString &theData, bool bLineBreaks=true)
EXPORT void SetString(const char *szString)
const char * GetTypeString() const
int64_t GetClosingNum() const
Definition: OTItem.cpp:2012
EXPORT void Format(const char *fmt,...)
Definition: OTString.cpp:1319
int32_t GetItemCountInRefTo(int64_t lReference)
const OTIdentifier & GetRealAccountID() const
EXPORT bool Compare(const char *compare) const
Definition: OTString.cpp:1102
EXPORT bool GetMemo(OTString &strMemo)
EXPORT OTItem * GetItem(OTItem::itemType theType)
const OTIdentifier & GetPurportedServerID() const
EXPORT void Set(const char *data, uint32_t enforcedMaxLength=0)
Definition: OTString.cpp:1055
virtual int32_t ProcessXMLNode(irr::io::IrrXMLReader *&xml)
time64_t OTTimeGetCurrentTime()
Definition: Common.hpp:211
EXPORT bool VerifyTransactionStatementNumbersOnNym(OTPseudonym &THE_NYM)
EXPORT void SetClosingNum(int64_t lClosingNum)
const OTString & GetLastSenderUserID() const
EXPORT std::string QueryPlainString(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:728
OTASCIIArmor m_ascCancellationRequest
void SetClosingNum(int64_t lClosingNum)
Definition: OTItem.cpp:2017
static EXPORT bool LoadEncodedTextField(irr::io::IrrXMLReader *&xml, OTASCIIArmor &ascOutput)
int64_t GetAmount() const
Definition: OTItem.hpp:475
OTString m_strNymID2
Definition: OTMessage.hpp:200
EXPORT bool Output(std::set< int64_t > &theOutput) const
Definition: OTNumList.cpp:430
EXPORT int64_t GetClosingNum() const
#define OT_ASSERT(x)
Definition: Assert.hpp:150
EXPORT OTLedger * LoadInbox(OTPseudonym &nym) const
Definition: OTAccount.cpp:225
bool HarvestOpeningNumber(OTPseudonym &theNym, bool bHarvestingForRetry, bool bReplyWasSuccess, bool bReplyWasFailure, bool bTransactionWasSuccess, bool bTransactionWasFailure)
static EXPORT const OTString & Receipt()
Definition: OTFolders.cpp:355
bool VerifyBoxReceipt(OTTransaction &theFullVersion)
OTString m_strContractType
Definition: OTContract.hpp:178
const OTIdentifier & GetDestinationAcctID() const
Definition: OTItem.hpp:487
OTLOG_IMPORT OTLogStream otInfo
ledgerType GetType() const
Definition: OTLedger.hpp:212
const OTString & GetConsideration() const
EXPORT bool VerifyBalanceReceipt(OTPseudonym &SERVER_NYM, OTPseudonym &THE_NYM)
EXPORT int32_t Count() const
Definition: OTNumList.cpp:460
static transactionType GetTypeFromString(const OTString &strType)
const OTIdentifier & GetRemitterUserID() const
Definition: OTCheque.hpp:184
void SetReplyTransSuccess(bool bVal)
bool SetupBoxReceiptFilename(int64_t lLedgerType, OTTransaction &theTransaction, const char *szCaller, OTString &strFolder1name, OTString &strFolder2name, OTString &strFolder3name, OTString &strFilename)
Definition: Helpers.cpp:591
OTStringXML m_xmlUnsigned
Definition: OTContract.hpp:174
time64_t GetDateSigned() const
#define OT_FAIL_MSG(s)
Definition: Assert.hpp:144
EXPORT int64_t GetReferenceToNum() const
EXPORT bool SaveBoxReceipt(int64_t lLedgerType)
OTLOG_IMPORT OTLogStream otWarn
EXPORT int64_t GetReferenceNumForDisplay()
int64_t GetAbbrevDisplayAmount() const
EXPORT const char * Get() const
Definition: OTString.cpp:1045
void SetUserID(const OTIdentifier &theID)
void SaveAbbreviatedOutboxRecord(OTString &strOutput)
transactionType GetType() const
void ProduceInboxReportItem(OTItem &theBalanceItem)
OTLOG_IMPORT OTLogStream otErr
OTItem::itemStatus GetStatus() const
Definition: OTItem.hpp:459
const OTIdentifier & GetPurportedAccountID() const
EXPORT int64_t GetReceiptAmount()
virtual bool VerifyAccount(const OTPseudonym &theNym)
EXPORT int64_t GetTransactionNum() const
virtual void HarvestClosingNumbers(OTPseudonym &theNym)
EXPORT void SetReferenceToNum(int64_t lTransactionNum)
bool IsAbbreviated() const
virtual EXPORT void HarvestClosingNumbers(OTPseudonym &theNym)
void SetRequestNum(const int64_t &lNum)
void SetPurportedServerID(const OTIdentifier &theID)
EXPORT void GetString(OTString &theStr) const
virtual EXPORT bool VerifySignature(const OTPseudonym &theNym, const OTPasswordData *pPWData=nullptr) const
Definition: OTContract.cpp:818
const OTIdentifier & GetRecipientUserID() const
const OTIdentifier & GetSenderAcctID() const
virtual EXPORT bool VerifyContractID() const
transactionType m_Type
EXPORT bool Exists(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:584
int32_t GetItemCount() const
Definition: OTItem.hpp:413
const OTIdentifier & GetRecipientAcctID() const
OTItem::itemType GetType() const
Definition: OTItem.hpp:467
const OTIdentifier & GetUserID() const
int64_t OTTimeGetSecondsFromTime(time64_t time)
Definition: Common.hpp:230
EXPORT bool LoadContractFromString(const OTString &theStr)
void ProduceOutboxReportItem(OTItem &theBalanceItem)
#define OT_TIME_ZERO
Definition: Common.hpp:180
void GetTypeString(OTString &strType) const
Definition: OTItem.hpp:504
virtual EXPORT void CalculateContractID(OTIdentifier &newID) const
Definition: OTContract.cpp:367
const OTIdentifier & GetRecipientUserID() const
Definition: OTCheque.hpp:176
listOfItems & GetItemList()
virtual EXPORT int64_t GetNumberOfOrigin()
Definition: OTItem.cpp:1132
void SetPurportedAccountID(const OTIdentifier &theID)
virtual EXPORT void Release()
Definition: OTString.cpp:765
const OTIdentifier & GetRealServerID() const
EXPORT bool VerifyItems(OTPseudonym &theNym)
static EXPORT OTCronItem * NewCronItem(const OTString &strCronItem)
Definition: OTCronItem.cpp:165
EXPORT void AddItem(OTItem &theItem)
virtual bool SaveContractWallet(std::ofstream &ofs) const
int64_t GetAbbrevInRefDisplay() const
void SetParent(const OTLedger &theParent)
EXPORT OTTransaction * GetTransaction(OTTransaction::transactionType theType)
Definition: OTLedger.cpp:1215
EXPORT int64_t GetRawNumberOfOrigin() const
EXPORT bool GetRecipientUserIDForDisplay(OTIdentifier &theReturnID)
virtual EXPORT void CalculateNumberOfOrigin()