Open-Transactions  0.93.0-ge03d287
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
opentxs::Notary Class Reference

#include <Notary.hpp>

Public Member Functions

 Notary (OTServer *server)
 
void NotarizeTransaction (OTPseudonym &nym, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
 
void NotarizeTransfer (OTPseudonym &nym, OTAccount &fromAccount, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
 
void NotarizeDeposit (OTPseudonym &nym, OTAccount &account, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
 for depositing a cheque or cash. More...
 
void NotarizeWithdrawal (OTPseudonym &nym, OTAccount &account, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
 
void NotarizeProcessInbox (OTPseudonym &nym, OTAccount &account, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
 
void NotarizeProcessNymbox (OTPseudonym &nym, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
 
void NotarizeMarketOffer (OTPseudonym &nym, OTAccount &assetAccount, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
 
void NotarizePaymentPlan (OTPseudonym &nym, OTAccount &depositorAccount, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
 
void NotarizeSmartContract (OTPseudonym &nym, OTAccount &activatingAccount, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
 
void NotarizeCancelCronItem (OTPseudonym &nym, OTAccount &assetAccount, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
 
void NotarizeExchangeBasket (OTPseudonym &nym, OTAccount &sourceAccount, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
 
void NotarizePayDividend (OTPseudonym &nym, OTAccount &account, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
 

Detailed Description

Definition at line 144 of file Notary.hpp.

Constructor & Destructor Documentation

opentxs::Notary::Notary ( OTServer server)
explicit

Definition at line 169 of file Notary.cpp.

170  : server_(server)
171 {
172 }

Member Function Documentation

void opentxs::Notary::NotarizeCancelCronItem ( OTPseudonym nym,
OTAccount assetAccount,
OTTransaction tranIn,
OTTransaction tranOut,
bool &  outSuccess 
)

Definition at line 5536 of file Notary.cpp.

5540 {
5541  // The outgoing transaction is an "atCancelCronItem", that is, "a reply to
5542  // the cancelCronItem request"
5543  tranOut.SetType(OTTransaction::atCancelCronItem);
5544 
5545  OTItem* pItem = nullptr;
5546  OTItem* pBalanceItem = nullptr;
5547  OTItem* pResponseItem = nullptr;
5548  OTItem* pResponseBalanceItem = nullptr;
5549 
5550  // The incoming transaction may be sent to inboxes and outboxes, and it
5551  // will definitely be bundled in our reply to the user as well. Therefore,
5552  // let's grab it as a string.
5553  OTString strInReferenceTo;
5554  OTString strBalanceItem;
5555 
5556  // Grab the actual server ID from this object, and use it as the server ID
5557  // here.
5558  const OTIdentifier SERVER_ID(server_->m_strServerID), USER_ID(theNym);
5559 
5560  const OTString strUserID(USER_ID);
5561 
5562  pBalanceItem = tranIn.GetItem(OTItem::transactionStatement);
5563  pResponseItem =
5565  pResponseItem->SetStatus(OTItem::rejection); // the default.
5566  tranOut.AddItem(*pResponseItem); // the Transaction's destructor will
5567  // cleanup the item. It "owns" it now.
5568 
5569  pResponseBalanceItem = OTItem::CreateItemFromTransaction(
5571  pResponseBalanceItem->SetStatus(OTItem::rejection); // the default.
5572  tranOut.AddItem(*pResponseBalanceItem); // the Transaction's destructor will
5573  // cleanup the item. It "owns" it
5574  // now.
5575  if (!NYM_IS_ALLOWED(strUserID.Get(),
5578  0, "%s: User %s cannot do this transaction "
5579  "(CancelCronItem messages are disallowed in server.cfg)\n",
5580  __FUNCTION__, strUserID.Get());
5581  }
5582  else if (nullptr == pBalanceItem) {
5583  OTString strTemp(tranIn);
5585  0, "%s: Expected transaction statement in trans# %ld: \n\n%s\n\n",
5586  __FUNCTION__, tranIn.GetTransactionNum(),
5587  strTemp.Exists() ? strTemp.Get()
5588  : " (ERROR LOADING TRANSACTION INTO STRING) ");
5589  }
5590  // For now, there should only be one of these cancelCronItem items inside
5591  // the transaction.
5592  // So we treat it that way... I either get it successfully or not.
5593  else if (nullptr != (pItem = tranIn.GetItem(OTItem::cancelCronItem))) {
5594  // The response item will contain a copy of the request item. So I save
5595  // it into a string
5596  // here so it can be saved into the "in reference to" field.
5597  pItem->SaveContractRaw(strInReferenceTo);
5598  pBalanceItem->SaveContractRaw(strBalanceItem);
5599 
5600  // ASSET_ACCT_ID is the ID on the "from" Account that was passed in.
5601  //
5602  const OTIdentifier ASSET_ACCT_ID(theAssetAccount);
5603 
5604  // Server response item being added to server response transaction
5605  // (tranOut)
5606  // They're getting SOME sort of response item.
5607 
5608  pResponseItem->SetReferenceString(strInReferenceTo); // the response
5609  // item carries a
5610  // copy of what
5611  // it's responding
5612  // to.
5613  pResponseItem->SetReferenceToNum(
5614  pItem->GetTransactionNum()); // This response item is IN RESPONSE to
5615  // pItem and its Owner Transaction.
5616 
5617  pResponseBalanceItem->SetReferenceString(
5618  strBalanceItem); // the response item carries a copy of what it's
5619  // responding to.
5620  pResponseBalanceItem->SetReferenceToNum(
5621  pItem->GetTransactionNum()); // This response item is IN RESPONSE to
5622  // pItem and its Owner Transaction.
5623 
5624  if (!(pBalanceItem->VerifyTransactionStatement(
5625  theNym, tranIn))) // isRealTransaction=true
5626  {
5627  OTLog::vOutput(0, "ERROR verifying transaction statement in "
5628  "NotarizeCancelCronItem.\n");
5629  }
5630  else {
5631  pResponseBalanceItem->SetStatus(
5632  OTItem::acknowledgement); // the transaction agreement was
5633  // successful.
5634 
5635  const int64_t lReferenceToNum = pItem->GetReferenceToNum();
5636 
5637  // I'm using the operator== because it exists. (Although now I
5638  // believe != exists also)
5639  // If the ID on the "from" account that was passed in,
5640  // does not match the "Acct From" ID on this transaction item
5641  if (!(ASSET_ACCT_ID == pItem->GetPurportedAccountID())) {
5642  OTLog::Output(0, "Error: Asset account ID on the transaction "
5643  "does not match asset account "
5644  "ID on the transaction item.\n");
5645  }
5646  else // LET'S SEE IF WE CAN REMOVE IT THEN...
5647  {
5648  OTCronItem* pCronItem =
5649  server_->m_Cron.GetItemByValidOpeningNum(lReferenceToNum);
5650 
5651  // Check for the closing number here (that happens in
5652  // OTCronItem, since it's polymorphic.)
5653 
5654  bool bSuccess = false;
5655 
5656  if ((nullptr != pCronItem) &&
5657  (pCronItem->CanRemoveItemFromCron(theNym))) // see if theNym
5658  // has right to
5659  // remove the
5660  // cronItem from
5661  // processing.
5662  {
5663  bSuccess = server_->m_Cron.RemoveCronItem(
5664  pCronItem->GetTransactionNum(), theNym); // <=====
5665  }
5666 
5667  // If we were just successful in removing the offer from the
5668  // market, that means a finalReceipt was
5669  // just dropped into the inboxes for the relevant asset
5670  // accounts. Once I process that receipt out of my
5671  // inbox, (which will require my processing out all related
5672  // marketReceipts) then the closing number
5673  // will be removed from my list of responsibility.
5674 
5675  if (bSuccess) {
5676  // Now we can set the response item as an acknowledgement
5677  // instead of the default (rejection)
5678  pResponseItem->SetStatus(OTItem::acknowledgement);
5679 
5680  bOutSuccess =
5681  true; // The "cancel cron item" was successful.
5682 
5683  OTLog::vOutput(2, "Successfully removed Cron Item from "
5684  "Cron object, based on ID: %ld\n",
5685  (nullptr != pCronItem)
5686  ? pCronItem->GetTransactionNum()
5687  : lReferenceToNum);
5688 
5689  // Any transaction numbers that need to be cleared, happens
5690  // inside RemoveCronItem().
5691  }
5692  else {
5693  OTLog::Output(0, "Unable to remove Cron Item from Cron "
5694  "object "
5695  "Notary::NotarizeCancelCronItem\n");
5696  }
5697  }
5698  } // transaction statement verified.
5699  }
5700  else {
5701  OTString strTemp(tranIn);
5703  0, "Error, expected OTItem::cancelCronItem "
5704  "in Notary::NotarizeCancelCronItem for trans# %ld:\n\n%s\n\n",
5705  tranIn.GetTransactionNum(),
5706  strTemp.Exists() ? strTemp.Get()
5707  : " (ERROR LOADING TRANSACTION FROM STRING) ");
5708  }
5709  // sign the response item before sending it back (it's already been added to
5710  // the transaction above)
5711  // Now, whether it was rejection or acknowledgement, it is set properly and
5712  // it is signed, and it
5713  // is owned by the transaction, who will take it from here.
5714  pResponseItem->SignContract(server_->m_nymServer);
5715  pResponseItem->SaveContract(); // the signing was of no effect because I
5716  // forgot to save.
5717 
5718  pResponseBalanceItem->SignContract(server_->m_nymServer);
5719  pResponseBalanceItem->SaveContract();
5720 }
static EXPORT void Output(int32_t nVerbosity, const char *szOutput)
Definition: OTLog.cpp:710
#define NYM_IS_ALLOWED(SZ_NYM_ID, BOOL_VAR_NAME)
Definition: Macros.hpp:146
EXPORT OTCronItem * GetItemByValidOpeningNum(int64_t lOpeningNum)
Definition: OTCron.cpp:968
static bool __transact_cancel_cron_item
static EXPORT OTItem * CreateItemFromTransaction(const OTTransaction &theOwner, OTItem::itemType theType, const OTIdentifier *pDestinationAcctID=nullptr)
Definition: OTItem.cpp:1451
static EXPORT void vOutput(int32_t nVerbosity, const char *szOutput,...)
Definition: OTLog.cpp:768
EXPORT bool RemoveCronItem(int64_t lTransactionNum, OTPseudonym &theRemover)
Definition: OTCron.cpp:839
void opentxs::Notary::NotarizeDeposit ( OTPseudonym nym,
OTAccount account,
OTTransaction tranIn,
OTTransaction tranOut,
bool &  outSuccess 
)

for depositing a cheque or cash.

Definition at line 2256 of file Notary.cpp.

2259 {
2260  // The outgoing transaction is an "atDeposit", that is, "a reply to the
2261  // deposit request"
2262  tranOut.SetType(OTTransaction::atDeposit);
2263 
2264  OTItem* pItem = nullptr;
2265  OTItem* pItemCheque = nullptr;
2266  OTItem* pItemCash = nullptr;
2267  OTItem* pBalanceItem = nullptr;
2268  OTItem* pResponseItem = nullptr;
2269  OTItem* pResponseBalanceItem = nullptr;
2270 
2271  // The incoming transaction may be sent to inboxes and outboxes, and it
2272  // will probably be bundled in our reply to the user as well. Therefore,
2273  // let's grab it as a string.
2274  OTString strInReferenceTo;
2275  OTString strBalanceItem;
2276 
2277  // Grab the actual server ID from this object, and use it as the server ID
2278  // here.
2279  const OTIdentifier SERVER_ID(server_->m_strServerID), USER_ID(theNym),
2280  ACCOUNT_ID(theAccount), SERVER_USER_ID(server_->m_nymServer),
2281  ASSET_TYPE_ID(theAccount.GetAssetTypeID());
2282 
2283  const OTString strUserID(USER_ID), strAccountID(ACCOUNT_ID);
2284 
2285  Mint* pMint = nullptr; // the Mint itself.
2286  OTAccount* pMintCashReserveAcct =
2287  nullptr; // the Mint's funds for cash withdrawals.
2288  // Here we find out if we're depositing cash, or a cheque
2289  //
2290  OTItem::itemType theReplyItemType = OTItem::error_state;
2291 
2292  pItemCheque = tranIn.GetItem(OTItem::depositCheque);
2293 
2294  if (nullptr == pItemCheque) {
2295  pItemCash = tranIn.GetItem(OTItem::deposit);
2296  pItem = pItemCash;
2297  theReplyItemType = OTItem::atDeposit;
2298  }
2299  else {
2300  pItem = pItemCheque;
2301  theReplyItemType = OTItem::atDepositCheque;
2302  }
2303  pResponseItem =
2304  OTItem::CreateItemFromTransaction(tranOut, theReplyItemType);
2305  pResponseItem->SetStatus(OTItem::rejection); // the default.
2306  tranOut.AddItem(*pResponseItem); // the Transaction's destructor will
2307  // cleanup the item. It "owns" it now.
2308 
2309  pResponseBalanceItem =
2311  pResponseBalanceItem->SetStatus(OTItem::rejection); // the default.
2312  tranOut.AddItem(*pResponseBalanceItem); // the Transaction's destructor will
2313  // cleanup the item. It "owns" it
2314  // now.
2315  if (nullptr == pItem) {
2316  OTString strTemp(tranIn);
2317  OTLog::vOutput(0, "Notary::NotarizeDeposit: Expected OTItem::deposit "
2318  "or OTItem::depositCheque in trans# %ld: \n\n%s\n\n",
2319  tranIn.GetTransactionNum(),
2320  strTemp.Exists()
2321  ? strTemp.Get()
2322  : " (ERROR LOADING TRANSACTION INTO STRING) ");
2323  }
2324  // Below this point, we know that pItem is good, and that either pItemCheque
2325  // OR pItemCash is good,
2326  // and that pItem points to the good one. Therefore next, let's verify
2327  // permissions:
2328 
2329  // This permission has to do with ALL deposits (cash or cheque)
2330  else if (!NYM_IS_ALLOWED(strUserID.Get(),
2332  OTLog::vOutput(0, "Notary::NotarizeDeposit: User %s cannot do this "
2333  "transaction (All deposits are disallowed in "
2334  "server.cfg)\n",
2335  strUserID.Get());
2336  }
2337  // This permission has to do with vouchers.
2338  else if ((nullptr != pItemCheque) &&
2339  (false ==
2340  NYM_IS_ALLOWED(strUserID.Get(),
2342  OTLog::vOutput(0, "Notary::NotarizeDeposit: User %s cannot do this "
2343  "transaction (depositCheque is disallowed in "
2344  "server.cfg)\n",
2345  strUserID.Get());
2346  }
2347  // This permission has to do with cash.
2348  else if ((nullptr != pItemCash) &&
2349  (false ==
2350  NYM_IS_ALLOWED(strUserID.Get(),
2352  OTLog::vOutput(0, "Notary::NotarizeDeposit: User %s cannot do this "
2353  "transaction (deposit cash is disallowed in "
2354  "server.cfg)\n",
2355  strUserID.Get());
2356  }
2357  // Check for a balance agreement...
2358  //
2359  else if (nullptr ==
2360  (pBalanceItem = tranIn.GetItem(OTItem::balanceStatement))) {
2361  OTString strTemp(tranIn);
2363  0, "Notary::NotarizeDeposit: Expected OTItem::balanceStatement, "
2364  "but not found in trans # %ld: \n\n%s\n\n",
2365  tranIn.GetTransactionNum(),
2366  strTemp.Exists() ? strTemp.Get()
2367  : " (ERROR LOADING TRANSACTION INTO STRING) ");
2368  }
2369  // DEPOSIT CHEQUE (Deposit Cash is the bottom half of the function, deposit
2370  // cheque is the top half.)
2371  else if (pItem->GetType() == OTItem::depositCheque) {
2372  // The response item, as well as the sender's inbox, will soon contain a
2373  // copy
2374  // of the request item. So I save it into a string here so they can grab
2375  // a copy of it
2376  // into their "in reference to" fields.
2377  pItem->SaveContractRaw(strInReferenceTo);
2378  pBalanceItem->SaveContractRaw(strBalanceItem);
2379 
2380  // Server response item being added to server response transaction
2381  // (tranOut)
2382  // They're getting SOME sort of response item.
2383 
2384  pResponseItem->SetReferenceString(strInReferenceTo); // the response
2385  // item carries a
2386  // copy of what
2387  // it's responding
2388  // to.
2389  pResponseItem->SetReferenceToNum(
2390  pItem->GetTransactionNum()); // This response item is IN RESPONSE to
2391  // pItem and its Owner Transaction.
2392 
2393  pResponseBalanceItem->SetReferenceString(
2394  strBalanceItem); // the response item carries a copy of what it's
2395  // responding to.
2396  pResponseBalanceItem->SetReferenceToNum(
2397  pItem->GetTransactionNum()); // This response item is IN RESPONSE to
2398  // pItem and its Owner Transaction.
2399  std::unique_ptr<OTLedger> pInbox(
2400  theAccount.LoadInbox(server_->m_nymServer));
2401  std::unique_ptr<OTLedger> pOutbox(
2402  theAccount.LoadOutbox(server_->m_nymServer));
2403 
2404  if (nullptr ==
2405  pInbox) // || !pInbox->VerifyAccount(server_->m_nymServer)) Verified
2406  // in OTAccount::Load
2407  {
2408  OTLog::Error("Notary::NotarizeDeposit: Error loading or "
2409  "verifying inbox for depositor account.\n");
2410  }
2411  else if (nullptr ==
2412  pOutbox) // || !pOutbox->VerifyAccount(server_->m_nymServer))
2413  // Verified in OTAccount::Load
2414  {
2415  OTLog::Error("Notary::NotarizeDeposit: Error loading or "
2416  "verifying outbox for depositor account.\n");
2417  }
2418  // NOTE: Below this point, pInbox and pOutbox are both available, AND
2419  // will be properly
2420  // cleaned up automatically upon scope exit.
2421  // If the ID on the "from" account that was passed in,
2422  // does not match the "Acct From" ID on this transaction item
2423  else if (ACCOUNT_ID != pItem->GetPurportedAccountID()) {
2424  // TODO: Verify that this if block is unnecessary, and if so, remove
2425  // it.
2426  // (The item should already have been verified when the transaction
2427  // itself was
2428  // verified, before this function was even called. I think this is
2429  // just an oversight.)
2430  OTLog::Output(0, "Notary::NotarizeDeposit: Error: account ID "
2431  "does not match account ID on the deposit "
2432  "item.\n");
2433  }
2434  else {
2435  // Get the cheque from the Item and load it up into a Cheque object.
2436  OTString strCheque;
2437  pItem->GetAttachment(strCheque);
2438  OTCheque theCheque(SERVER_ID,
2439  ASSET_TYPE_ID); // allocated on the stack :-)
2440  bool bLoadContractFromString =
2441  theCheque.LoadContractFromString(strCheque);
2442 
2443  if (!bLoadContractFromString) {
2444  OTLog::vError("%s: ERROR loading cheque from string:\n%s\n",
2445  __FUNCTION__, strCheque.Get());
2446  }
2447  // See if the cheque is drawn on the same server as the deposit
2448  // account
2449  // (the server running this code right now.)
2450  //
2451  else if (SERVER_ID != theCheque.GetServerID()) {
2452  const OTString strSenderUserID(theCheque.GetSenderUserID());
2453  const OTString strRecipientUserID(
2454  theCheque.GetRecipientUserID());
2455  OTLog::vOutput(0, "%s: Cheque rejected (%ld): "
2456  "Incorrect Server ID on cheque. Sender User "
2457  "ID: %s\nRecipient User ID is: %s\n",
2458  __FUNCTION__, theCheque.GetTransactionNum(),
2459  strSenderUserID.Get(), strRecipientUserID.Get());
2460  }
2461  // See if the cheque is already expired or otherwise not within it's
2462  // valid date range.
2463  else if (!theCheque.VerifyCurrentDate()) {
2464  const OTString strSenderUserID(theCheque.GetSenderUserID());
2465  const OTString strRecipientUserID(
2466  theCheque.GetRecipientUserID());
2467  OTLog::vOutput(0, "%s: Cheque rejected (%ld): "
2468  "Not within valid date range. Sender User "
2469  "ID: %s\nRecipient User ID: %s\n",
2470  __FUNCTION__, theCheque.GetTransactionNum(),
2471  strSenderUserID.Get(), strRecipientUserID.Get());
2472  }
2473  // You can't deposit a cheque into the same account that it's drawn
2474  // on. (Otherwise, in loading
2475  // both accounts, I would cause one of them to be overwritten. I'm
2476  // not willing to do the same
2477  // pointer magic that I'm doing with Nyms... instead I just disallow
2478  // this entirely.)
2479  //
2480  // UPDATE: New rule: If you deposit a cheque into the same account
2481  // it's drawn on,
2482  // the effect is the cancellation of the cheque. (If we are in this
2483  // block, it means
2484  // the original cheque writer is now trying to cancel the cheque
2485  // before the recipient
2486  // has a chance to deposit it.)
2487  //
2488  // CANCELLATION OF CHEQUES:
2489  //
2490  else if (ACCOUNT_ID ==
2491  theCheque.GetSenderAcctID()) // Depositor ACCOUNT_ID is
2492  // recipient's acct. (theNym.)
2493  // But pSenderNym is normally
2494  // someone else (the sender).
2495  {
2496  // UPDATE: This block is now for cancelling the cheque before
2497  // the original
2498  // recipient manages to deposit it.
2499 
2500  const OTString strSenderUserID(theCheque.GetSenderUserID());
2501  const OTString strRecipientUserID(
2502  theCheque.GetRecipientUserID());
2503  if (theCheque.GetSenderUserID() != USER_ID) {
2505  0,
2506  "%s: Failure verifying cheque: Strange: while the "
2507  "depositing account has the "
2508  "same ID as the cheque sender acct, somehow the user "
2509  "IDs do not match. (Should never happen.)\n"
2510  "Cheque Sender User ID: %s\n Depositor User ID: %s\n",
2511  __FUNCTION__, strSenderUserID.Get(), strUserID.Get());
2512  }
2513  else if (theCheque.GetAmount() != 0) {
2515  0, "%s: Failure verifying cheque: While attempting to "
2516  "perform cancellation, "
2517  "the cheque has a non-zero amount.\n"
2518  "Sender User ID: %s\nRecipient User ID: %s\n",
2519  __FUNCTION__, strSenderUserID.Get(),
2520  strRecipientUserID.Get());
2521  }
2522  // Make sure the transaction number on the cheque is still
2523  // available and valid for use by theNym.
2524  //
2525  else if (false ==
2526  server_->transactor_.verifyTransactionNumber(
2527  theNym, theCheque.GetTransactionNum())) {
2529  0, "%s: Failure verifying cheque: Bad transaction "
2530  "number.\n"
2531  "Sender User ID: %s\nRecipient User ID: %s\n",
2532  __FUNCTION__, strSenderUserID.Get(),
2533  strRecipientUserID.Get());
2534  }
2535  // Let's see if the sender's signature matches the one on the
2536  // cheque...
2537  else if (!theCheque.VerifySignature(theNym)) {
2538  OTLog::vOutput(0,
2539  "%s: Failure verifying cheque signature for "
2540  "sender ID: %s\nRecipient User ID: %s\n "
2541  "Cheque:\n\n%s\n\n",
2542  __FUNCTION__, strSenderUserID.Get(),
2543  strRecipientUserID.Get(), strCheque.Get());
2544  }
2545  else if (!(pBalanceItem->VerifyBalanceStatement(
2546  theCheque.GetAmount(), // This amount is always
2547  // zero in the case of
2548  // cheque cancellation.
2549  theNym, *pInbox, *pOutbox, theAccount,
2550  tranIn))) {
2551  OTLog::vOutput(0, "%s: ERROR verifying balance statement "
2552  "while cancelling cheque %ld. Acct "
2553  "ID:\n%s\n",
2554  __FUNCTION__, theCheque.GetTransactionNum(),
2555  strAccountID.Get());
2556  }
2557  else {
2558  pResponseBalanceItem->SetStatus(
2559  OTItem::acknowledgement); // the transaction agreement
2560  // was successful.
2561 
2562  if ( // Clear the transaction number. Sender Nym was
2563  // responsible for it (and still is, until
2564  // he signs to accept the cheque reecipt). Still,
2565  // however, he HAS used the cheque, so
2566  // I'm removing his ability to use that number
2567  // twice. It will remain on his issued list
2568  // until he signs for the receipt.
2569  //
2570  (false ==
2571  server_->transactor_.removeTransactionNumber(
2572  theNym, theCheque.GetTransactionNum(),
2573  true)) // bSave=true
2574  ) {
2575  OTLog::vError("%s: Failed marking the transaction "
2576  "number as in use. (Should never "
2577  "happen.)\n",
2578  __FUNCTION__);
2579  }
2580  else {
2581  // Generate new transaction number (for putting the
2582  // check receipt in the sender's inbox.)
2583  // todo check this generation for failure (can it fail?)
2584  int64_t lNewTransactionNumber = 0;
2585 
2586  server_->transactor_.issueNextTransactionNumber(
2587  server_->m_nymServer, lNewTransactionNumber,
2588  false); // bStoreTheNumber = false
2589 
2590  OTTransaction* pInboxTransaction =
2593  lNewTransactionNumber);
2594 
2595  // The depositCheque request OTItem is saved as a "in
2596  // reference to" field,
2597  // on the inbox chequeReceipt transaction.
2598  // todo put these two together in a method.
2599  pInboxTransaction->SetReferenceString(strInReferenceTo);
2600  pInboxTransaction->SetReferenceToNum(
2601  pItem->GetTransactionNum());
2602 
2603  pInboxTransaction->SetAsCancelled();
2604 
2605  // Now we have created a new transaction from the server
2606  // to the sender's inbox
2607  // Let's sign and save it...
2608  pInboxTransaction->SignContract(server_->m_nymServer);
2609  pInboxTransaction->SaveContract();
2610 
2611  // Here the transaction we just created is actually
2612  // added to the source acct's inbox.
2613  pInbox->AddTransaction(*pInboxTransaction);
2614 
2615  // Release any signatures that were there before (They
2616  // won't
2617  // verify anymore anyway, since the content has
2618  // changed.)
2619  //
2620  pInbox->ReleaseSignatures();
2621  pInbox->SignContract(server_->m_nymServer);
2622  pInbox->SaveContract();
2623 
2624  theAccount.SaveInbox(*pInbox);
2625 
2626  // Any inbox/nymbox/outbox ledger will only itself
2627  // contain
2628  // abbreviated versions of the receipts, including their
2629  // hashes.
2630  //
2631  // The rest is stored separately, in the box receipt,
2632  // which is created
2633  // whenever a receipt is added to a box, and deleted
2634  // after a receipt
2635  // is removed from a box.
2636  //
2637  pInboxTransaction->SaveBoxReceipt(*pInbox);
2638  // AT THIS POINT, the sender/depositor's inbox has had
2639  // the cheque transaction added to it,
2640  // as his receipt. (He must perform a balance agreement
2641  // in order to get it out of his inbox.)
2642  //
2643  // THERE IS NOTHING LEFT TO DO BUT SAVE THE FILES!!
2644 
2645  theAccount.ReleaseSignatures();
2646  theAccount.SignContract(server_->m_nymServer);
2647  theAccount.SaveContract();
2648  theAccount.SaveAccount();
2649 
2650  // Now we can set the response item as an
2651  // acknowledgement instead of the default (rejection)
2652  // otherwise, if we never entered this block, then it
2653  // would still be set to rejection, and the
2654  // new item would never have been added to the inbox,
2655  // and the inbox file would never have had
2656  // its signatures released, or been re-signed or
2657  // re-saved back to file.
2658  // BUT... if the message comes back with
2659  // acknowledgement--then all of these actions must have
2660  // happened, and here is the server's signature to prove
2661  // it.
2662  // Otherwise you get no items and no signature. Just a
2663  // rejection item in the response transaction.
2664  //
2665  pResponseItem->SetStatus(OTItem::acknowledgement);
2666 
2667  bOutSuccess =
2668  true; // The cheque cancellation was successful.
2669 
2671  0, "%s: SUCCESS cancelling cheque %ld, which had "
2672  "been drawn from account: %s\n",
2673  __FUNCTION__, theCheque.GetTransactionNum(),
2674  strAccountID.Get());
2675 
2676  tranOut.SetAsCancelled();
2677 
2678  // TODO: Our code that actually saves the new balance
2679  // statement receipt should go here
2680  // (that is, only after ultimate success.) Otherwise we
2681  // still want to store the old receipt.
2682  // For now I'm verifying it, but not storing it. This
2683  // means the security for it works, but
2684  // in a dispute, I can't prove it / cover my ass. So
2685  // very soon a receipt WILL be saved here
2686  // that is, a copy of the user's signed
2687  // BalanceAgreement.
2688  // Note: if I'm saving the entire outgoing transaction
2689  // reply, or message reply, (versus just
2690  // the reply to a certain item) then I think I have the
2691  // balance agreement already? Double check.
2692  }
2693  } // "else"
2694  } // ABOVE: Cheque cancellation
2695  else // BELOW: Cheque deposit
2696  {
2697  const OTIdentifier& SOURCE_ACCT_ID(
2698  theCheque.GetSenderAcctID()); // relevant for both vouchers
2699  // AND cheques.
2700  const OTIdentifier& SENDER_USER_ID(theCheque.GetSenderUserID());
2701 
2702  const OTIdentifier& REMITTER_ACCT_ID(
2703  theCheque.GetRemitterAcctID()); // only relevant in case of
2704  // vouchers.
2705  const OTIdentifier& REMITTER_USER_ID(
2706  theCheque.GetRemitterUserID());
2707 
2708  // If the cheque has a remitter ...and the depositor IS the
2709  // remitter...
2710  // (Then the remitter is cancelling the voucher.)
2711  //
2712  const bool bHasRemitter = theCheque.HasRemitter();
2713  const bool bRemitterCancelling =
2714  (bHasRemitter &&
2715  (USER_ID == theCheque.GetRemitterUserID()));
2716 
2717  // The point of the logic here is to enable remitters to deposit
2718  // vouchers. Basically allows
2719  // them to "cancel" the voucher, and get their money back.
2720  //
2721  const OTIdentifier& RECIPIENT_USER_ID(
2722  bRemitterCancelling ? USER_ID
2723  : theCheque.GetRecipientUserID());
2724 
2725  // (Note that we allow the remitter of a voucher to deposit that
2726  // voucher.)
2727 
2728  const OTString strSenderUserID(SENDER_USER_ID),
2729  strSourceAcctID(SOURCE_ACCT_ID),
2730  strRecipientUserID(RECIPIENT_USER_ID),
2731  strRemitterUserID(REMITTER_USER_ID),
2732  strRemitterAcctID(REMITTER_ACCT_ID);
2733  OTLedger theSenderInbox(SENDER_USER_ID, SOURCE_ACCT_ID,
2734  SERVER_ID); // chequeReceipt goes here.
2735  OTLedger theRemitterInbox(
2736  REMITTER_USER_ID, REMITTER_ACCT_ID,
2737  SERVER_ID); // voucherReceipt goes here.
2738  OTLedger* pSenderInbox = &theSenderInbox;
2739  OTLedger* pRemitterInbox = &theRemitterInbox;
2740  OTAccount* pRemitterAcct =
2741  nullptr; // Only used in the case of vouchers.
2742  std::unique_ptr<OTAccount> theRemitterAcctGuardian;
2743  OTAccount* pSourceAcct =
2744  nullptr; // We'll load this up and change
2745  // its balance, save it then
2746  // delete the instance.
2747  std::unique_ptr<OTAccount> theSourceAcctGuardian;
2748  // OTAccount::LoadExistingAccount().
2749  OTPseudonym theRemitterNym(REMITTER_USER_ID);
2750  OTPseudonym* pRemitterNym = &theRemitterNym;
2751  OTPseudonym theSenderNym(SENDER_USER_ID);
2752  OTPseudonym* pSenderNym = &theSenderNym;
2753 
2754  // Don't want to overwrite files or db records in cases where
2755  // the sender is also the depositor.
2756  // (Similar concern if the server is also the depositor, but
2757  // that's already partly handled
2758  // before we get to this point... theNym is already substituted
2759  // for m_nymServer,
2760  // if the IDs match, before any of the commands are processed.)
2761  //
2762  // The conundrum is in the multiplicity of combinations. The
2763  // server COULD be the sender
2764  // OR the depositor, or he could be BOTH, or the server might
2765  // NOT be the sender OR depositor,
2766  // yet they could still be the same person. Normally all 3 are
2767  // separate entities. That's a
2768  // lot of combinations. I want to make sure that I don't
2769  // overwrite ANY files while juggling the
2770  // respective nymfiles, transaction numbers, request numbers,
2771  // etc.
2772  //
2773  // Solution: When commands are first processed, and the Request
2774  // Number is processed, theNym
2775  // is ALREADY replaced with m_nymServer IF the IDs match and the
2776  // signature verifies. It is then
2777  // passed that way to all of the commands (including the one we
2778  // are in now.)
2779  //
2780  // I THEN do the logic BELOW as additional to that. Make sure if
2781  // you change anything that you
2782  // think int64_t and hard about what you are doing!!
2783  //
2784  // Here's the logic:
2785  // -- theNym is the depositor (for sure.)
2786  // -- m_nymServer is the server nym (for sure.)
2787  // -- By the time we get here, IF the ServerUserID and UserID
2788  // match,
2789  // then theNym IS ALREADY m_nymServer, literally a
2790  // reference to it.
2791  // (This is performed before we even get to this point, so
2792  // that the
2793  // same problem doesn't occur with request numbers.)
2794  // -- In cases where the "server is also the depositor", it's
2795  // therefore
2796  // ALREADY handled, since theNym already points to
2797  // m_nymServer.
2798  // -- theSenderNym is used to load the sender nym in cases where
2799  // we have
2800  // to load it from file or db ourselves. (Most normal
2801  // cases.)
2802  // -- In those normal cases, pSenderNym will point to
2803  // theSenderNym and
2804  // we load it up from file or database.
2805  // -- In cases where the sender is also the user (the
2806  // depositor), then
2807  // pSenderNym will point to theNym instead of to
2808  // theSenderNym, and we
2809  // no longer bother loading it, since the user is already
2810  // loaded.
2811  // -- In cases where the sender is also the server, then
2812  // pSenderNym will
2813  // point to m_nymServer instead of to theSenderNym, and we
2814  // no longer
2815  // bother loading it, since the server's nym is already
2816  // loaded.
2817 
2818  bool bDepositorIsServer = (USER_ID == SERVER_USER_ID);
2819  bool bDepositorIsSender = (USER_ID == SENDER_USER_ID);
2820  bool bDepositorIsRemitter = (USER_ID == REMITTER_USER_ID);
2821  bool bDepositAcctIsRemitter = (ACCOUNT_ID == REMITTER_ACCT_ID);
2822  bool bSourceAcctIsRemitter =
2823  (SOURCE_ACCT_ID == REMITTER_ACCT_ID);
2824  bool bSenderIsServer = (SENDER_USER_ID == SERVER_USER_ID);
2825  bool bRemitterIsServer = (REMITTER_USER_ID == SERVER_USER_ID);
2826  bool bSenderUserAlreadyLoaded = false;
2827  bool bSourceAcctAlreadyLoaded = false;
2828  bool bRemitterUserAlreadyLoaded = false;
2829  bool bRemitterAcctAlreadyLoaded = false;
2830 
2831  // The depositor is already loaded, (for sure.)
2832 
2833  // The server is already loaded, (for sure.)
2834 
2835  // If the depositor IS the server, then it already points there
2836  // (for sure.)
2837  if (bDepositorIsServer) {
2838  // OTPseudonym & theNym = m_nymServer; // Already handled in
2839  // the code that calls IncrementRequestNum().
2840 
2841  // bSenderUserAlreadyLoaded = false; // Sender is either
2842  // determined to be already loaded (directly below) or
2843  // it is loaded as part of the cheque verification process
2844  // below that.
2845  // At this point I can't set it because I just don't know
2846  // yet.
2847  }
2848  // If the depositor IS the sender, pSenderNym points to
2849  // depositor, and we're already loaded.
2850  if (bDepositorIsSender) {
2851  pSenderNym = &theNym;
2852  bSenderUserAlreadyLoaded = true;
2853  }
2854  // If the server IS the sender, pSenderNym points to the server,
2855  // and we're already loaded.
2856  if (bSenderIsServer) {
2857  pSenderNym = &server_->m_nymServer;
2858  bSenderUserAlreadyLoaded = true;
2859  }
2860  bool bSuccessLoadSenderInbox = false;
2861  bool bSuccessLoadRemitterInbox = false;
2862 
2863  if (bHasRemitter) {
2864  pSenderInbox = nullptr;
2865 
2866  // If the depositor IS the remitter, pRemitterNym points to
2867  // depositor, and we're already loaded.
2868  if (bDepositorIsRemitter) {
2869  pRemitterNym = &theNym;
2870  bRemitterUserAlreadyLoaded = true;
2871  }
2872  // If the server IS the remitter, pRemitterNym points to the
2873  // server, and we're already loaded.
2874  if (bRemitterIsServer) {
2875  pRemitterNym = &server_->m_nymServer;
2876  bRemitterUserAlreadyLoaded = true;
2877  }
2878  // If the account IS the remitter's account, pRemitterNym
2879  // points to the server, and we're already loaded.
2880  if (bDepositAcctIsRemitter) {
2881  pRemitterAcct = &theAccount;
2882  pRemitterInbox = pInbox.get();
2883 
2884  bRemitterAcctAlreadyLoaded = true;
2885  bSuccessLoadRemitterInbox = true;
2886 
2887  // Just for completeness. In this case ALL THREE
2888  // accounts would be the same account,
2889  // which is probably disallowed later on anyway.
2890  //
2891  if (bSourceAcctIsRemitter) {
2892  pSourceAcct = pRemitterAcct;
2893  pSenderInbox = pRemitterInbox;
2894 
2895  bSourceAcctAlreadyLoaded = true;
2896  bSuccessLoadSenderInbox = true;
2897  }
2898  }
2899  }
2900  else // Definitely has no remitter. Therefore definitely NOT a
2901  // voucher.
2902  { // (If it's not a voucher, that means we should DEFINITELY be
2903  // able to load the sender's inbox.)
2904  // Load source account's inbox
2905 
2906  bSuccessLoadSenderInbox = pSenderInbox->LoadInbox();
2907 
2908  // ...If it loads, verify it. Otherwise, generate it...
2909  if (bSuccessLoadSenderInbox)
2910  bSuccessLoadSenderInbox =
2911  pSenderInbox->VerifyAccount(server_->m_nymServer);
2912  else
2913  OTLog::vOutput(0, "Notary::%s: Failed loading inbox "
2914  "for %s source account.\n",
2915  __FUNCTION__,
2916  (bHasRemitter) ? "cheque" : "voucher");
2917  // else
2918  // bSuccessLoadSenderInbox =
2919  // pSenderInbox->GenerateLedger(SOURCE_ACCT_ID, SERVER_ID,
2920  // OTLedger::inbox, true); // bGenerateFile=true
2921  }
2922  // To deposit a cheque, need to verify: (in no special order)
2923  //
2924  // -- DONE Load the source account and verify it exists.
2925  // -- DONE Make sure the source acct is verified for the server
2926  // signature.
2927  // -- DONE Make sure the Asset Type of the cheque matches the
2928  // Asset Type of BOTH source and recipient accts.
2929  // -- DONE See if there is a Recipient User ID. If so, MAKE SURE
2930  // it matches the user depositing the cheque!
2931  // -- DONE See if the Sender User even exists.
2932  // -- DONE See if the Sender User ID matches the hash of the
2933  // actual public key in the sender's pubkey file.
2934  // -- DONE Make sure the cheque has the right server ID.
2935  // -- DONE Make sure the cheque has not yet EXPIRED.
2936  // -- DONE Make sure the cheque signature is verified with the
2937  // sender's pubkey.
2938  // -- DONE Make sure the account ID on the transaction item
2939  // matches the depositor account ID.
2940  // -- DONE Verify the funds are in the source acct.
2941  //
2942  // -- DONE Plus deal with sender's inbox.
2943 
2944  // If there's a remitter, then it's a voucher, and thus the
2945  // sender MUST be the server.
2946  // (If the sender on a voucher is NOT the server, then it's very
2947  // suspicious.)
2948  //
2949  if (bHasRemitter && !bSenderIsServer) {
2950  OTLog::vOutput(0, "Notary::%s: Failure: Voucher has a "
2951  "'sender' who is not the server: %s\n",
2952  __FUNCTION__, strSenderUserID.Get());
2953  }
2954 
2955  // See if we can load the sender's public key (to verify cheque
2956  // signature,
2957  // and to remove transaction number if it's not a voucher.)
2958  // if !bSenderUserAlreadyLoaded since the server already had its
2959  // public key loaded at boot-time.
2960  // (also since the depositor and sender might be the same
2961  // person.)
2962  else if (!bSenderUserAlreadyLoaded &&
2963  (false ==
2964  theSenderNym.LoadPublicKey()) // Old style (The call
2965  // on this line is
2966  // deprecated.) NOTE:
2967  // LoadPublicKey already
2968  // calls LoadCredentials
2969  // at its top, though
2970  // eventually we'll just
2971  // call it here
2972  // directly, once
2973  // LoadPublicKey is
2974  // removed for good.
2975  ) {
2977  0, "Notary::%s: Error loading public key for %s "
2978  "signer during "
2979  "deposit: %s\nRecipient User ID: %s\n",
2980  __FUNCTION__, (bHasRemitter) ? "cheque" : "voucher",
2981  strSenderUserID.Get(), strRecipientUserID.Get());
2982  }
2983 
2984  // See if the Nym ID (User ID) that we have matches the message
2985  // digest of his public key.
2986  else if (!pSenderNym->VerifyPseudonym()) {
2988  0, "Notary::%s: Failure verifying %s: "
2989  "Bad Sender User ID (fails hash check of pubkey)"
2990  ": %s\nRecipient User ID: %s\n",
2991  __FUNCTION__, (bHasRemitter) ? "cheque" : "voucher",
2992  strSenderUserID.Get(), strRecipientUserID.Get());
2993  }
2994 
2995  // See if we can load the sender's nym file (to verify the
2996  // transaction # on the cheque)
2997  // if !bSenderUserAlreadyLoaded since the server already had its
2998  // nym file loaded at boot-time.
2999  // (also since the depositor and sender might be the same
3000  // person.)
3001  else if (!bSenderUserAlreadyLoaded &&
3002  (false ==
3003  theSenderNym.LoadSignedNymfile(
3004  server_->m_nymServer))) {
3006  0, "Notary::%s: Error loading nymfile for %s signer "
3007  "during deposit, user ID: %s\n"
3008  "Recipient User ID: %s\n",
3009  __FUNCTION__, (bHasRemitter) ? "cheque" : "voucher",
3010  strSenderUserID.Get(), strRecipientUserID.Get());
3011  }
3012  // See if we can load the remitter's public key (if it's a
3013  // voucher.)
3014  // if !bRemitterAlreadyLoaded since the server already had its
3015  // public key loaded at boot-time.
3016  // (also since the depositor or server, and remitter, might be
3017  // the same person.)
3018  else if (bHasRemitter && !bRemitterUserAlreadyLoaded &&
3019  (false ==
3020  theRemitterNym.LoadPublicKey()) // Old style (The call
3021  // on this line is
3022  // deprecated.) NOTE:
3023  // LoadPublicKey
3024  // already calls
3025  // LoadCredentials at
3026  // its top, though
3027  // eventually we'll
3028  // just call it here
3029  // directly, once
3030  // LoadPublicKey is
3031  // removed for good.
3032  ) {
3034  0, "Notary::%s: Error loading public key for "
3035  "remitter during "
3036  "voucher deposit: %s\nRecipient User ID: %s\n",
3037  __FUNCTION__, strRemitterUserID.Get(),
3038  strRecipientUserID.Get());
3039  }
3040 
3041  // See if the Nym ID (User ID) that we have matches the message
3042  // digest of his public key.
3043  else if (bHasRemitter && !pRemitterNym->VerifyPseudonym()) {
3045  0, "Notary::%s: Failure verifying voucher: "
3046  "Bad Remitter User ID (fails hash check of pubkey)"
3047  ": %s\nRecipient User ID: %s\n",
3048  __FUNCTION__, strRemitterUserID.Get(),
3049  strRecipientUserID.Get());
3050  }
3051 
3052  // See if we can load the remitter's nym file (to verify the
3053  // transaction # on the cheque)
3054  // if !bRemitterUserAlreadyLoaded since the server already had
3055  // its nym file loaded at boot-time.
3056  // (also since the depositor and remitter might be the same
3057  // person.)
3058  else if (bHasRemitter && !bRemitterUserAlreadyLoaded &&
3059  (false ==
3060  theRemitterNym.LoadSignedNymfile(
3061  server_->m_nymServer))) {
3062  OTLog::vOutput(0, "Notary::%s: Error loading nymfile for "
3063  "remitter during voucher deposit: %s\n"
3064  "Recipient User ID: %s\n",
3065  __FUNCTION__, strRemitterUserID.Get(),
3066  strRecipientUserID.Get());
3067  }
3068  // Make sure they're not double-spending this cheque.
3069  //
3070  else if (false ==
3071  server_->transactor_.verifyTransactionNumber(
3072  *(bHasRemitter ? pRemitterNym : pSenderNym),
3073  theCheque.GetTransactionNum())) {
3074  OTLog::vOutput(0, "Notary::%s: Failure verifying %s: Bad "
3075  "transaction number.\n"
3076  "Recipient User ID: %s\n",
3077  __FUNCTION__,
3078  (bHasRemitter) ? "cheque" : "voucher",
3079  strRecipientUserID.Get());
3080  }
3081  // Let's see if the sender's signature matches the one on the
3082  // cheque...
3083  else if (false ==
3084  theCheque.VerifySignature(*pSenderNym)) // This is same
3085  // for cheques
3086  // and vouchers.
3087  {
3089  0, "Notary::%s: Failure verifying %s signature for "
3090  "sender ID: %s Recipient User ID: %s",
3091  __FUNCTION__, (bHasRemitter) ? "cheque" : "voucher",
3092  strSenderUserID.Get(), strRecipientUserID.Get());
3093  if (bHasRemitter)
3094  OTLog::vOutput(0, " Remitter User ID: %s\n",
3095  strRemitterUserID.Get());
3096  else
3097  OTLog::Output(0, "\n");
3098  }
3099  // If there is a recipient user ID on the check, it must match
3100  // the user depositing the cheque.
3101  // (But if there is NO recipient user ID, then it's a blank
3102  // cheque and ANYONE can deposit it.)
3103  else if (theCheque.HasRecipient() &&
3104  !(USER_ID == RECIPIENT_USER_ID)) {
3105  OTLog::vOutput(0, "%s: Failure matching %s recipient to "
3106  "depositor. Depositor User ID: %s "
3107  "Recipient User ID: %s\n",
3108  __FUNCTION__,
3109  (bHasRemitter) ? "cheque" : "voucher",
3110  strUserID.Get(), strRecipientUserID.Get());
3111  }
3112  // Try to load the source account (that cheque is drawn on) up
3113  // into memory.
3114  // We'll need to debit funds from it... Also, set the cleanup
3115  // object onto this pointer.
3116  else if (!bSourceAcctAlreadyLoaded &&
3117  ((nullptr ==
3118  (pSourceAcct = OTAccount::LoadExistingAccount(
3119  SOURCE_ACCT_ID, SERVER_ID))) ||
3120  (theSourceAcctGuardian.reset(pSourceAcct),
3121  false // I want this to eval to false, but I want
3122  // SetCleanup to call.
3123  )) // Also, SetCleanup() is safe even if pointer is
3124  // nullptr.
3125  ) {
3127  0, "%s: %s deposit failure, "
3128  "trying to load source acct, ID: %s Recipient User "
3129  "ID: %s",
3130  __FUNCTION__, (bHasRemitter) ? "Cheque" : "Voucher",
3131  strSourceAcctID.Get(), strRecipientUserID.Get());
3132  if (bHasRemitter)
3133  OTLog::vOutput(0, " Remitter User ID: %s\n",
3134  strRemitterUserID.Get());
3135  else
3136  OTLog::Output(0, "\n");
3137  }
3138  // If the cheque is a voucher (drawn on an internal server
3139  // account) then there is no need to
3140  // load any "sender inbox" (which will not exist anyway.)
3141  // Whereas if the source account is NOT
3142  // an internal server account (but rather, is a NORMAL account)
3143  // then it had better have
3144  // successfully loaded that inbox, or we have a problem.
3145  //
3146  else if (!bSuccessLoadSenderInbox &&
3147  !pSourceAcct->IsInternalServerAcct()) {
3148  OTLog::vError("%s: ERROR verifying inbox ledger for source "
3149  "acct ID: %s\n",
3150  __FUNCTION__, strSourceAcctID.Get());
3151  }
3152  // Does the source account verify?
3153  // I call VerifySignature here since VerifyContractID was
3154  // already called in LoadExistingAccount().
3155  // (Otherwise I might normally call VerifyAccount(), which does
3156  // both...)
3157  //
3158  // Someone can't just alter an account file, because then the
3159  // server's signature
3160  // won't verify anymore on that file and transactions will fail
3161  // such as right here:
3162  //
3163  else if (!pSourceAcct->VerifySignature(server_->m_nymServer)) {
3165  0, "%s: ERROR verifying signature on source account "
3166  "while depositing %s. Acct ID: %s\n",
3167  __FUNCTION__, (bHasRemitter) ? "cheque" : "voucher",
3168  strAccountID.Get());
3169  }
3170  // Need to make sure the signer is the owner of the source
3171  // account...
3172  else if (!pSourceAcct->VerifyOwner(*pSenderNym)) {
3173  OTLog::vOutput(0, "Notary::%s: ERROR verifying signer's "
3174  "ownership of source account while "
3175  "depositing %s. Source Acct ID: %s\n",
3176  __FUNCTION__,
3177  (bHasRemitter) ? "cheque" : "voucher",
3178  strAccountID.Get());
3179  }
3180  else {
3181  if (bSourceAcctIsRemitter) {
3182  pRemitterAcct = pSourceAcct;
3183  bRemitterAcctAlreadyLoaded = true;
3184 
3185  pRemitterInbox = pSenderInbox;
3186 
3187  if (nullptr != pRemitterInbox) // This part is here for
3188  // completeness only. It
3189  // will never actually
3190  // happen,
3191  bSuccessLoadRemitterInbox =
3192  true; // since a voucher source account is owned
3193  // by server and has no inbox.
3194  }
3195 
3196  // Try to load the remitter account (that voucher was
3197  // originally financed from) up into memory.
3198  // We'll need to verify it so we can drop the receipt into
3199  // its inbox. Also, set the cleanup object onto this
3200  // pointer.
3201  //
3202  if (bHasRemitter && !bRemitterAcctAlreadyLoaded &&
3203  ((nullptr ==
3204  (pRemitterAcct = OTAccount::LoadExistingAccount(
3205  REMITTER_ACCT_ID, SERVER_ID))) ||
3206  (theRemitterAcctGuardian.reset(pRemitterAcct),
3207  false // I want this to eval to false, but I want
3208  // SetCleanup to call.
3209  ) // Also, SetCleanup() is safe even if pointer is
3210  // nullptr.
3211  )) {
3213  0, "%s: Voucher deposit, failure "
3214  "trying to load remitter acct, ID: %s Recipient "
3215  "User ID: %s Remitter User ID: %s\n",
3216  __FUNCTION__, strRemitterAcctID.Get(),
3217  strRecipientUserID.Get(), strRemitterUserID.Get());
3218  }
3219  // Does the remitter account verify?
3220  // I call VerifySignature here since VerifyContractID was
3221  // already called in LoadExistingAccount().
3222  // (Otherwise I might normally call VerifyAccount(), which
3223  // does both...)
3224  //
3225  else if (bHasRemitter &&
3226  !pRemitterAcct->VerifySignature(
3227  server_->m_nymServer)) {
3228  OTLog::vOutput(0, "%s: ERROR verifying signature on "
3229  "remitter account while depositing "
3230  "voucher. "
3231  "Remitter Acct ID: %s\n",
3232  __FUNCTION__, strRemitterAcctID.Get());
3233  }
3234  // Need to make sure the remitter is the owner of the
3235  // remitter account...
3236  else if (bHasRemitter &&
3237  !pRemitterAcct->VerifyOwner(*pRemitterNym)) {
3239  0, "Notary::%s: ERROR verifying remitter's "
3240  "ownership of remitter account while "
3241  "depositing voucher. Remitter Acct ID: %s\n",
3242  __FUNCTION__, strRemitterAcctID.Get());
3243  }
3244  else if (bHasRemitter && // If it's a voucher, and the
3245  // source account isn't the
3246  // remitter account...
3247  !bSourceAcctIsRemitter && // (if it was, there'd
3248  // definitely be no
3249  // remitter inbox, since
3250  // it'd be a server
3251  // acct.)
3252  !bSuccessLoadRemitterInbox && // ...and if we
3253  // haven't
3254  // successfully
3255  // loaded the
3256  // remitter's inbox
3257  // yet...
3258  (!pRemitterInbox->LoadInbox() ||
3259  !pRemitterInbox->VerifyAccount(
3260  server_->m_nymServer))) // Then load and
3261  // verify it.
3262  {
3263  OTLog::vError("%s: ERROR loading or verifying inbox "
3264  "ledger for remitter acct ID: %s\n",
3265  __FUNCTION__, strRemitterAcctID.Get());
3266  }
3267  // Are all of the accounts, AND the cheque, all of the same
3268  // Asset Type?
3269  else if (!(theCheque.GetAssetID() ==
3270  pSourceAcct->GetAssetTypeID()) ||
3271  !(theCheque.GetAssetID() ==
3272  theAccount.GetAssetTypeID()) ||
3273  (bHasRemitter &&
3274  !(theCheque.GetAssetID() ==
3275  pRemitterAcct->GetAssetTypeID()))) {
3276  OTString strSourceAssetID(
3277  pSourceAcct->GetAssetTypeID()),
3278  strRecipientAssetID(theAccount.GetAssetTypeID());
3280  0, "Notary::%s: ERROR - user attempted to "
3281  "deposit cheque between accounts of different "
3282  "asset types. Source Acct: %s\nType: "
3283  "%s\nRecipient Acct: %s\nType: %s\n",
3284  __FUNCTION__, strSourceAcctID.Get(),
3285  strSourceAssetID.Get(), strAccountID.Get(),
3286  strRecipientAssetID.Get());
3287 
3288  if (bHasRemitter) {
3289  OTString strRemitterAssetID(
3290  pRemitterAcct->GetAssetTypeID());
3291  OTLog::vOutput(0, "Remitter Acct: %s\nType: %s\n",
3292  strRemitterAcctID.Get(),
3293  strRemitterAssetID.Get());
3294  }
3295  }
3296 
3297  // The BALANCE AGREEMENT includes a signed and dated:
3298  /*
3299  user ID, server ID, account ID, transaction ID.
3300 
3301  BY THE TIME you are ever inside the procesing for ANY
3302  transaction. we know for
3303  a fact that NotarizeTransaction has ALREADY checked all
3304  the items on the transaction
3305  (the ones in its list) to make sure they ALL have the same
3306  owner, and signature,
3307  and transaction number, and account ID, and server ID.
3308  This happens when the items
3309  first load via VerifyContractID(), and then in
3310  NotarizeTransaction() with a call to
3311  VerifyItems(). Therefore I can consider the above
3312  variables COVERED for pItem as
3313  well as pBalanceItem.
3314 
3315  Balance Agreement also includes:
3316  -- A copy of all the transaction numbers that should still
3317  be issued to the Nym,
3318  AFTER one is removed from depositing this cheque. (The
3319  same number on tranIn and pItem.)
3320  NEED TO VERIFY BOTH LISTS ARE THE SAME AFTER REMOVING ONE
3321  ON MY SIDE.
3322  -- Account balance.
3323  (NEED TO VERIFY BALANCE WOULD BE THE SAME AFTER PROCESSING
3324  TRANSACTION.
3325  -- Inbox and Outbox reports on a single list of sub-items.
3326  (NEED TO VERIFY INBOX AND OUTBOX ITEMS MATCH BY
3327  RE-CREATING AND THEN COMPARING.)
3328 
3329  All these are now done in VerifyBalanceStatement().
3330 
3331  */
3332  else if (!(pBalanceItem->VerifyBalanceStatement(
3333  theCheque.GetAmount(), theNym, *pInbox,
3334  *pOutbox, theAccount, tranIn))) {
3335  OTLog::vOutput(0, "Notary::%s: ERROR verifying "
3336  "balance statement while depositing "
3337  "cheque. Acct ID:\n%s\n",
3338  __FUNCTION__, strAccountID.Get());
3339  }
3340 
3341  // Debit Source account, Credit Recipient Account, add to
3342  // Sender's inbox.
3343  //
3344  // Also clear the transaction number so this cheque can't be
3345  // deposited again.
3346  //
3347  else {
3348  pResponseBalanceItem->SetStatus(
3349  OTItem::acknowledgement); // the transaction
3350  // agreement was
3351  // successful.
3352 
3353  // Deduct the amount from the source account, and add it
3354  // to the recipient account...
3355  if (false ==
3356  pSourceAcct->Debit(theCheque.GetAmount())) {
3357  OTLog::vError("Notary::%s: Failed debiting "
3358  "source account.\n",
3359  __FUNCTION__);
3360  }
3361  else if (false ==
3362  theAccount.Credit(theCheque.GetAmount())) {
3363  OTLog::vError("Notary::%s: Failed crediting "
3364  "destination account.\n",
3365  __FUNCTION__);
3366 
3367  if (false ==
3368  pSourceAcct->Credit(theCheque.GetAmount()))
3369  OTLog::vError("Notary::%s: Failed crediting "
3370  "back source account.\n",
3371  __FUNCTION__);
3372  }
3373  else if ( // Clear the transaction number. Sender Nym
3374  // was responsible for it (and still is,
3375  // until
3376  // he signs to accept the cheque
3377  // reecipt). Alternately, remitter Nym is
3378  // responsible for
3379  // it, until he signs to accept the
3380  // voucher receipt. At this point, the
3381  // cheque is USED,
3382  // so I'm removing his ability to use
3383  // that number twice. It will remain on
3384  // his issued
3385  // list until he signs for the receipt.
3386  //
3387  false ==
3388  server_->transactor_.removeTransactionNumber(
3389  *(bHasRemitter ? pRemitterNym : pSenderNym),
3390  theCheque.GetTransactionNum(),
3391  true) // bSave=true
3392  ) {
3393  OTLog::vError("%s: Strange: Failed removing "
3394  "transaction number from sender or "
3395  "remitter, even though "
3396  "it verified just earlier...\n",
3397  __FUNCTION__);
3398  if (false ==
3399  pSourceAcct->Credit(theCheque.GetAmount()))
3400  OTLog::vError("Notary::%s: Failed "
3401  "crediting-back source "
3402  "account.\n",
3403  __FUNCTION__);
3404 
3405  if (false ==
3406  theAccount.Debit(theCheque.GetAmount()))
3407  OTLog::vError("Notary::%s: Failed "
3408  "debiting-back destination "
3409  "account.\n",
3410  __FUNCTION__);
3411  }
3412  else { // need to be able to "roll back" if anything
3413  // inside this block fails.
3414  // update: actually does pretty good roll-back as it
3415  // is. The debits and credits
3416  // don't save unless everything is a success.
3417 
3418  OTAccount* pAcctWhereReceiptGoes = nullptr;
3419  OTLedger* pInboxWhereReceiptGoes = nullptr;
3420  if (bHasRemitter) // voucher
3421  {
3422  pAcctWhereReceiptGoes = pRemitterAcct;
3423  pInboxWhereReceiptGoes = pRemitterInbox;
3424  }
3425  else // normal cheque
3426  {
3427  pAcctWhereReceiptGoes = pSourceAcct;
3428  pInboxWhereReceiptGoes = pSenderInbox;
3429  }
3430  // Add the chequeReceipt to the inbox of the signer
3431  // on the cheque.
3432  // (Or add the voucherReceipt to the inbox of the
3433  // remitter of the voucher.)
3434  //
3435  // The original sender (or remitter, whichever is
3436  // applicable) can close out the
3437  // transaction number associated with the cheque by
3438  // signing-off on that chequeReceipt or
3439  // voucherReceipt.
3440  //
3441  if (pAcctWhereReceiptGoes
3442  ->IsInternalServerAcct()) // Must be a
3443  // voucher
3444  // remitted by the
3445  // server.
3446  // (Unusual, but
3447  // possible...
3448  // Typically a
3449  // voucher is
3450  // remitted by a
3451  // normal user,
3452  // but this can
3453  // happen in the
3454  // case of
3455  // dividends.)
3456  {
3457  if (!bHasRemitter || !bRemitterIsServer)
3458  OTLog::vError(
3459  "%s: Error: Apparently this is a "
3460  "voucher remitted directly by the "
3461  "server (such as a dividend payment) "
3462  "but one of these values is false: "
3463  "bHasRemitter (), "
3464  "bRemitterIsServer()\n",
3465  __FUNCTION__,
3466  bHasRemitter ? "true" : "false",
3467  bRemitterIsServer ? "true" : "false");
3468  else {
3469  // If bHasRemitter is true, which it is,
3470  // then we KNOW the server is the sender,
3471  // since
3472  // we explicitly verified that already
3473  // above. But the receipt doesn't go to the
3474  // sender's inbox,
3475  // but rather, to the remitter's inbox.
3476  // However, in this block, clearly
3477  // IsInternalServerAcct is true,
3478  // where the receipt is supposed to go,
3479  // which means the server is also the
3480  // remitter! And we verified
3481  // that also in the above 'if' statement, so
3482  // we explicitly know that
3483  // bRemitterIsServer. And in that
3484  // case, we can't just drop a receipt into
3485  // his inbox, since the server has no inbox,
3486  // and that means
3487  // he will never be able to close out the
3488  // transaction number by accepting the
3489  // receipt, like a normal
3490  // user would be able to do.
3491  //
3492  // Therefore, we explicitly remove the
3493  // issued number here from the remitter
3494  // (whom we know to actually
3495  // be the server.) He has no inbox, and he
3496  // won't get any receipt -- but the number
3497  // will be closed out
3498  // properly. Before this fix, the server was
3499  // probably keeping every voucher number
3500  // open for eternity.
3501  //
3502  if (!server_->transactor_
3504  *pRemitterNym,
3505  theCheque.GetTransactionNum(),
3506  true)) // bSave=true
3507  OTLog::vError(
3508  "%s: Strange: Failed removing "
3509  "issued number from remitter (the "
3510  "server nym, in this case), "
3511  "even though the number verified "
3512  "just earlier...\n",
3513  __FUNCTION__);
3514  }
3515  }
3516  else // For normal cheques, and for normal
3517  // vouchers (where the remitter is a normal
3518  // user.)
3519  {
3520  // Generate new transaction number (for putting
3521  // the check receipt in the sender's inbox.)
3522  // todo check this generation for failure (can
3523  // it fail?)
3524  int64_t lNewTransactionNumber = 0;
3525 
3526  server_->transactor_.issueNextTransactionNumber(
3527  server_->m_nymServer, lNewTransactionNumber,
3528  false); // bStoreTheNumber = false
3529 
3530  OTTransaction* pInboxTransaction =
3532  *pInboxWhereReceiptGoes,
3533  theCheque.HasRemitter()
3536  lNewTransactionNumber);
3537 
3538  // The depositCheque request OTItem is saved as
3539  // a "in reference to" field,
3540  // on the inbox chequeReceipt or voucherReceipt
3541  // transaction.
3542  // todo put these two together in a method.
3543  pInboxTransaction->SetReferenceString(
3544  strInReferenceTo);
3545  pInboxTransaction->SetReferenceToNum(
3546  pItem->GetTransactionNum());
3547  pInboxTransaction->SetNumberOfOrigin(
3548  theCheque.GetTransactionNum());
3549 
3550  if (bRemitterCancelling)
3551  pInboxTransaction->SetAsCancelled();
3552 
3553  // Now we have created a new transaction from
3554  // the server to the sender's inbox (or
3555  // remitter's inbox.)
3556  // Let's sign and save it...
3557  pInboxTransaction->SignContract(
3558  server_->m_nymServer);
3559  pInboxTransaction->SaveContract();
3560 
3561  // Here the transaction we just created is
3562  // actually added to the source acct's or
3563  // remitter's inbox.
3564  pInboxWhereReceiptGoes->AddTransaction(
3565  *pInboxTransaction);
3566 
3567  // Release any signatures that were there before
3568  // (They won't
3569  // verify anymore anyway, since the content has
3570  // changed.)
3571  //
3572  pInboxWhereReceiptGoes->ReleaseSignatures();
3573  pInboxWhereReceiptGoes->SignContract(
3574  server_->m_nymServer);
3575  pInboxWhereReceiptGoes->SaveContract();
3576 
3577  pAcctWhereReceiptGoes->SaveInbox(
3578  *pInboxWhereReceiptGoes);
3579 
3580  // if there's NOT a remitter, then the source
3581  // account is ALREADY saved below this block.
3582  // (Otherwise we need to save his acct here.)
3583  //
3584  if (bHasRemitter &&
3585  !bRemitterIsServer) // If remitter is also
3586  // server, then no need
3587  // to save here, since
3588  // source acct is
3589  // ALREADY saved below.
3590  {
3591  // If there IS a remitter who is NOT the
3592  // server, then we save his
3593  // account here, so it will contain the
3594  // updated inbox hash (since
3595  // we just added a receipt to its inbox.)
3596  //
3597  pAcctWhereReceiptGoes->ReleaseSignatures();
3598  pAcctWhereReceiptGoes->SignContract(
3599  server_->m_nymServer);
3600  pAcctWhereReceiptGoes->SaveContract();
3601  pAcctWhereReceiptGoes->SaveAccount();
3602  }
3603 
3604  // Any inbox/nymbox/outbox ledger will only
3605  // itself contain
3606  // abbreviated versions of the receipts,
3607  // including their hashes.
3608  //
3609  // The rest is stored separately, in the box
3610  // receipt, which is created
3611  // whenever a receipt is added to a box, and
3612  // deleted after a receipt
3613  // is removed from a box.
3614  //
3615  pInboxTransaction->SaveBoxReceipt(
3616  *pInboxWhereReceiptGoes);
3617  }
3618  // AT THIS POINT, the source account is debited, the
3619  // recipient account is credited,
3620  // and the sender's (or remitter's) inbox has had
3621  // the chequeReceipt or voucherReceipt added to it.
3622  // (He must perform a balance agreement in order to
3623  // get it out of his inbox.)
3624  //
3625  // THERE IS NOTHING LEFT TO DO BUT SAVE THE FILES!!
3626 
3627  pSourceAcct->ReleaseSignatures();
3628  theAccount.ReleaseSignatures();
3629 
3630  pSourceAcct->SignContract(server_->m_nymServer);
3631  theAccount.SignContract(server_->m_nymServer);
3632 
3633  pSourceAcct->SaveContract();
3634  theAccount.SaveContract();
3635 
3636  pSourceAcct->SaveAccount();
3637  theAccount.SaveAccount();
3638 
3639  // Now we can set the response item as an
3640  // acknowledgement instead of the default
3641  // (rejection)
3642  // otherwise, if we never entered this block, then
3643  // it would still be set to rejection, and the
3644  // new item would never have been added to the
3645  // inbox, and the inbox file, along with the
3646  // account files, would never have had their
3647  // signatures released, or been re-signed or
3648  // re-saved back to file. The debit failed, so all
3649  // of those other actions would fail also.
3650  // BUT... if the message comes back with
3651  // acknowledgement--then all of these actions must
3652  // have
3653  // happened, and here is the server's signature to
3654  // prove it.
3655  // Otherwise you get no items and no signature. Just
3656  // a rejection item in the response transaction.
3657  //
3658  pResponseItem->SetStatus(OTItem::acknowledgement);
3659 
3660  bOutSuccess =
3661  true; // The cheque deposit was successful.
3662 
3663  if (bRemitterCancelling) {
3664  tranOut.SetAsCancelled();
3665  OTLog::vOutput(1, "Notary::%s: SUCCESS "
3666  "crediting remitter account "
3667  "from voucher "
3668  "cancellation.\n",
3669  __FUNCTION__);
3670  }
3671  else
3672  OTLog::vOutput(1, "Notary::%s: SUCCESS "
3673  "crediting account from "
3674  "cheque deposit.\n",
3675  __FUNCTION__);
3676 
3677  // TODO: Our code that actually saves the new
3678  // balance statement receipt should go here
3679  // (that is, only after ultimate success.) Otherwise
3680  // we still want to store the old receipt.
3681  // For now I'm verifying it, but not storing it.
3682  // This means the security for it works, but
3683  // in a dispute, I can't prove it / cover my ass.
3684  // So very soon a receipt WILL be saved here
3685  // that is, a copy of the user's signed
3686  // BalanceAgreement.
3687  // Note: if I'm saving the entire outgoing
3688  // transaction reply, or message reply, (versus just
3689  // the reply to a certain item) then I think I have
3690  // the balance agreement already? Double check.
3691  }
3692 
3693  } // "else"
3694  } // "else"
3695  } // successfully loaded cheque from string
3696  } // account ID DOES match item's account ID
3697  } // deposit cheque
3698 
3699  // BELOW -- DEPOSIT CASH
3700 
3701  // For now, there should only be one of these deposit items inside the
3702  // transaction.
3703  // So we treat it that way... I either get it successfully or not.
3704  //
3705  // Deposit (the transaction) now supports deposit (the item) and
3706  // depositCheque (the item)
3707  else if (pItem->GetType() == OTItem::deposit) {
3708  // The response item, as well as the inbox and outbox items, will
3709  // contain a copy
3710  // of the request item. So I save it into a string here so they can all
3711  // grab a copy of it
3712  // into their "in reference to" fields.
3713  pItem->SaveContractRaw(strInReferenceTo);
3714  pBalanceItem->SaveContractRaw(strBalanceItem);
3715 
3716  // Server response item being added to server response transaction
3717  // (tranOut)
3718  // They're getting SOME sort of response item.
3719 
3720  pResponseItem->SetReferenceString(strInReferenceTo); // the response
3721  // item carries a
3722  // copy of what
3723  // it's responding
3724  // to.
3725  pResponseItem->SetReferenceToNum(
3726  pItem->GetTransactionNum()); // This response item is IN RESPONSE to
3727  // pItem and its Owner Transaction.
3728 
3729  pResponseBalanceItem->SetReferenceString(
3730  strBalanceItem); // the response item carries a copy of what it's
3731  // responding to.
3732  pResponseBalanceItem->SetReferenceToNum(
3733  pItem->GetTransactionNum()); // This response item is IN RESPONSE to
3734  // pItem and its Owner Transaction.
3735 
3736  // If the ID on the "from" account that was passed in,
3737  // does not match the "Acct From" ID on this transaction item
3738  if (ACCOUNT_ID != pItem->GetPurportedAccountID()) {
3739  OTLog::vOutput(0, "Notary::NotarizeDeposit: Error: 'From' "
3740  "account ID on the transaction does not match "
3741  "'from' account ID on the deposit item.\n");
3742  }
3743  else {
3744  std::unique_ptr<OTLedger> pInbox(
3745  theAccount.LoadInbox(server_->m_nymServer));
3746  std::unique_ptr<OTLedger> pOutbox(
3747  theAccount.LoadOutbox(server_->m_nymServer));
3748 
3749  if (nullptr == pInbox) {
3750  OTLog::Error("Notary::NotarizeDeposit: Error loading or "
3751  "verifying inbox.\n");
3752  OT_FAIL;
3753  }
3754  else if (nullptr == pOutbox) {
3755  OTLog::Error("Notary::NotarizeDeposit: Error loading or "
3756  "verifying outbox.\n");
3757  OT_FAIL;
3758  }
3759  OTString strPurse;
3760  pItem->GetAttachment(strPurse);
3761 
3762  Purse thePurse(SERVER_ID, ASSET_TYPE_ID);
3763 
3764  bool bLoadContractFromString =
3765  thePurse.LoadContractFromString(strPurse);
3766 
3767  if (!bLoadContractFromString) {
3768  OTLog::vError("Notary::NotarizeDeposit: ERROR loading purse "
3769  "from string:\n%s\n",
3770  strPurse.Get());
3771  }
3772  else if (!(pBalanceItem->VerifyBalanceStatement(
3773  thePurse.GetTotalValue(), theNym, *pInbox, *pOutbox,
3774  theAccount, tranIn))) {
3775  OTLog::vOutput(0, "Notary::NotarizeDeposit: ERROR verifying "
3776  "balance statement while depositing cash. "
3777  "Acct ID:\n%s\n",
3778  strAccountID.Get());
3779  }
3780 
3781  // TODO: double-check all verification stuff all around on the purse
3782  // and token, transaction, mint, etc.
3783  else // the purse loaded successfully from the string
3784  {
3785  pResponseBalanceItem->SetStatus(
3786  OTItem::acknowledgement); // the transaction agreement was
3787  // successful.
3788 
3789  bool bSuccess = false;
3790 
3791  // Pull the token(s) out of the purse that was received from the
3792  // client.
3793  while (true) {
3794  std::unique_ptr<Token> pToken(
3795  thePurse.Pop(server_->m_nymServer));
3796  if (!pToken) {
3797  break;
3798  }
3799 
3800  pMint = server_->transactor_.getMint(ASSET_TYPE_ID,
3801  pToken->GetSeries());
3802 
3803  if (nullptr == pMint) {
3804  OTLog::Error("Notary::NotarizeDeposit: Unable to get "
3805  "or load Mint.\n");
3806  break;
3807  }
3808  else if ((pMintCashReserveAcct =
3809  pMint->GetCashReserveAccount()) !=
3810  nullptr) {
3811  OTString strSpendableToken;
3812  bool bToken = pToken->GetSpendableString(
3813  server_->m_nymServer, strSpendableToken);
3814 
3815  if (!bToken) // if failure getting the spendable token
3816  // data from the token object
3817  {
3818  bSuccess = false;
3819  OTLog::vOutput(0, "Notary::NotarizeDeposit: "
3820  "ERROR verifying token: Failure "
3821  "retrieving token data. \n");
3822  break;
3823  }
3824  else if (!(pToken->GetAssetID() ==
3825  ASSET_TYPE_ID)) // or if failure verifying
3826  // asset type
3827  {
3828  bSuccess = false;
3829  OTLog::vOutput(0, "Notary::NotarizeDeposit: "
3830  "ERROR verifying token: Wrong "
3831  "asset type. \n");
3832  break;
3833  }
3834  else if (!(pToken->GetServerID() ==
3835  SERVER_ID)) // or if failure verifying
3836  // server ID
3837  {
3838  bSuccess = false;
3839  OTLog::vOutput(0, "Notary::NotarizeDeposit: "
3840  "ERROR verifying token: Wrong "
3841  "server ID. \n");
3842  break;
3843  }
3844  // This call to VerifyToken verifies the token's Series
3845  // and From/To dates against the
3846  // mint's, and also verifies that the CURRENT date is
3847  // inside that valid date range.
3848  //
3849  // It also verifies the Lucre coin data itself against
3850  // the key for that series and
3851  // denomination. (The signed and unblinded Lucre coin is
3852  // finally verified in Lucre
3853  // using the appropriate Mint private key.)
3854  //
3855  else if (!(pMint->VerifyToken(
3856  server_->m_nymServer, strSpendableToken,
3857  pToken->GetDenomination()))) {
3858  bSuccess = false;
3859  OTLog::vOutput(0, "Notary::NotarizeDeposit: "
3860  "ERROR verifying token: Token "
3861  "verification failed. \n");
3862  break;
3863  }
3864  // Lookup the token in the SPENT TOKEN DATABASE, and
3865  // make sure
3866  // that it hasn't already been spent...
3867  else if (pToken->IsTokenAlreadySpent(
3868  strSpendableToken)) {
3869  // TODO!!!! Need to store the spent token database
3870  // in multiple places, on multiple media!
3871  // Furthermore need to CHECK those multiple
3872  // places inside IsTokenAlreadySpent.
3873  // In fact, that should all be configurable
3874  // in the server config file!
3875  // Related: make sure IsTokenAlreadySpent
3876  // differentiates between ACTUALLY not finding
3877  // a token as spent (successfully), versus
3878  // some error state with the storage.
3879  bSuccess = false;
3880  OTLog::vOutput(0, "Notary::NotarizeDeposit: "
3881  "ERROR verifying token: Token "
3882  "was already spent. \n");
3883  break;
3884  }
3885  else {
3886  OTLog::Output(3, "Notary::NotarizeDeposit: "
3887  "SUCCESS verifying token... "
3888  "\n");
3889 
3890  // need to be able to "roll back" if anything inside
3891  // this block fails.
3892  // so unless bSuccess is true, I don't save the
3893  // account below.
3894  //
3895 
3896  // two defense mechanisms here: mint cash reserve
3897  // acct, and spent token database
3898  //
3899  if (false ==
3900  pMintCashReserveAcct->Debit(
3901  pToken->GetDenomination())) {
3902  OTLog::Error("Notary::NotarizeDeposit: Error "
3903  "debiting the mint cash reserve "
3904  "account. "
3905  "SHOULD NEVER HAPPEN...\n");
3906  bSuccess = false;
3907  break;
3908  }
3909  // CREDIT the amount to the account...
3910  else if (false ==
3911  theAccount.Credit(
3912  pToken->GetDenomination())) {
3913  OTLog::Error("Notary::NotarizeDeposit: Error "
3914  "crediting the user's asset "
3915  "account...\n");
3916 
3917  if (false ==
3918  pMintCashReserveAcct->Credit(
3919  pToken->GetDenomination()))
3920  OTLog::Error("Notary::NotarizeDeposit: "
3921  "Failure crediting-back "
3922  "mint's cash reserve account "
3923  "while depositing cash.\n");
3924  bSuccess = false;
3925  break;
3926  }
3927  // Spent token database. This is where the call is
3928  // made to add
3929  // the token to the spent token database.
3930  else if (false ==
3931  pToken->RecordTokenAsSpent(
3932  strSpendableToken)) {
3933  OTLog::Error("Notary::NotarizeDeposit: "
3934  "Failed recording token as "
3935  "spent...\n");
3936 
3937  if (false ==
3938  pMintCashReserveAcct->Credit(
3939  pToken->GetDenomination()))
3940  OTLog::Error("Notary::NotarizeDeposit: "
3941  "Failure crediting-back "
3942  "mint's cash reserve account "
3943  "while depositing cash.\n");
3944 
3945  if (false ==
3946  theAccount.Debit(pToken->GetDenomination()))
3947  OTLog::Error("Notary::NotarizeDeposit: "
3948  "Failure debiting-back user's "
3949  "asset account while "
3950  "depositing cash.\n");
3951 
3952  bSuccess = false;
3953  break;
3954  }
3955  else // SUCCESS!!! (this iteration)
3956  {
3957  OTLog::vOutput(2, "Notary::NotarizeDeposit: "
3958  "SUCCESS crediting account "
3959  "with cash token...\n");
3960  bSuccess = true;
3961 
3962  // No break here -- we allow the loop to carry
3963  // on through.
3964  }
3965  }
3966  }
3967  else {
3968  OTLog::Error("Notary::NotarizeDeposit: Unable to get "
3969  "cash reserve account for Mint.\n");
3970  bSuccess = false;
3971  break;
3972  }
3973  } // while success popping token from purse
3974 
3975  if (bSuccess) {
3976  // Release any signatures that were there before (They won't
3977  // verify anymore anyway, since the content has changed.)
3978  theAccount.ReleaseSignatures();
3979 
3980  // Sign
3981  theAccount.SignContract(server_->m_nymServer);
3982 
3983  // Save
3984  theAccount.SaveContract();
3985 
3986  // Save to file
3987  theAccount.SaveAccount();
3988 
3989  // We also need to save the Mint's cash reserve.
3990  // (Any cash issued by the Mint is automatically backed by
3991  // this reserve
3992  // account. If cash is deposited, it comes back out of this
3993  // account. If the
3994  // cash expires, then after the expiry period, if it remains
3995  // in the account,
3996  // it is now the property of the transaction server.)
3997  pMintCashReserveAcct->ReleaseSignatures();
3998  pMintCashReserveAcct->SignContract(server_->m_nymServer);
3999  pMintCashReserveAcct->SaveContract();
4000  pMintCashReserveAcct->SaveAccount();
4001 
4002  pResponseItem->SetStatus(OTItem::acknowledgement);
4003 
4004  bOutSuccess = true; // The cash deposit was successful.
4005 
4006  OTLog::Output(1, "Notary::NotarizeDeposit: .....SUCCESS "
4007  "-- crediting account from cash "
4008  "deposit.\n");
4009 
4010  // TODO: Right here, again, I need to save the receipt from
4011  // the new balance agreement, since we have
4012  // "ultimate success". Also need to save the Nym, since he
4013  // had a transaction number removed in
4014  // the above call to VerifyBalanceAgreement. If we failed
4015  // here, then we wouldn't WANT to save, since
4016  // that number should stay on him! Same reason we don't save
4017  // the accounts if anything goes wrong.
4018  }
4019  } // the purse loaded successfully from the string
4020  } // the account ID matches correctly to the acct ID on the item.
4021  }
4022  else {
4023  OTString strTemp(tranIn);
4024  OTLog::vOutput(0, "%s: Expected OTItem::deposit or "
4025  "OTItem::depositCheque on trans# %ld: \n\n%s\n\n",
4026  __FUNCTION__, tranIn.GetTransactionNum(),
4027  strTemp.Exists()
4028  ? strTemp.Get()
4029  : " (ERROR CREATING STRING FROM TRANSACTION.) ");
4030  }
4031 
4032  // sign the response item before sending it back (it's already been added to
4033  // the transaction above)
4034  // Now, whether it was rejection or acknowledgement, it is set properly and
4035  // it is signed, and it
4036  // is owned by the transaction, who will take it from here.
4037  pResponseItem->SignContract(server_->m_nymServer);
4038  pResponseItem->SaveContract(); // the signing was of no effect because I
4039  // forgot to save.
4040 
4041  pResponseBalanceItem->SignContract(server_->m_nymServer);
4042  pResponseBalanceItem->SaveContract();
4043 }
static EXPORT void vError(const char *szError,...)
Definition: OTLog.cpp:800
static EXPORT OTTransaction * GenerateTransaction(const OTIdentifier &theUserID, const OTIdentifier &theAccountID, const OTIdentifier &theServerID, transactionType theType, int64_t lTransactionNum=0)
static EXPORT void Output(int32_t nVerbosity, const char *szOutput)
Definition: OTLog.cpp:710
bool issueNextTransactionNumber(OTPseudonym &nym, int64_t &txNumber, bool storeNumber=true)
Definition: Transactor.cpp:211
#define NYM_IS_ALLOWED(SZ_NYM_ID, BOOL_VAR_NAME)
Definition: Macros.hpp:146
bool verifyTransactionNumber(OTPseudonym &nym, const int64_t &transactionNumber)
Definition: Transactor.cpp:278
bool removeTransactionNumber(OTPseudonym &nym, const int64_t &transactionNumber, bool save=false)
Definition: Transactor.cpp:320
static EXPORT OTItem * CreateItemFromTransaction(const OTTransaction &theOwner, OTItem::itemType theType, const OTIdentifier *pDestinationAcctID=nullptr)
Definition: OTItem.cpp:1451
static EXPORT void Error(const char *szError)
Definition: OTLog.cpp:831
Mint * getMint(const OTIdentifier &assetTypeId, int32_t seriesCount)
Lookup the current mint for any given asset type ID and series.
Definition: Transactor.cpp:565
EXPORT void SetReferenceString(const OTString &theStr)
bool removeIssuedNumber(OTPseudonym &nym, const int64_t &transactionNumber, bool save=false)
Definition: Transactor.cpp:354
#define OT_FAIL
Definition: Assert.hpp:139
static bool __transact_deposit_cash
static bool __transact_deposit_cheque
static EXPORT void vOutput(int32_t nVerbosity, const char *szOutput,...)
Definition: OTLog.cpp:768
static EXPORT OTAccount * LoadExistingAccount(const OTIdentifier &accountId, const OTIdentifier &serverId)
Definition: OTAccount.cpp:480
void opentxs::Notary::NotarizeExchangeBasket ( OTPseudonym theNym,
OTAccount theAccount,
OTTransaction tranIn,
OTTransaction tranOut,
bool &  bOutSuccess 
)

a user is exchanging in or out of a basket. (Ex. He's trading 2 gold and 3 silver for 10 baskets, or vice-versa.)

Definition at line 5724 of file Notary.cpp.

5727 {
5728  // The outgoing transaction is an "atExchangeBasket", that is, "a reply to
5729  // the exchange basket request"
5730  tranOut.SetType(OTTransaction::atExchangeBasket);
5731 
5732  OTItem* pItem = tranIn.GetItem(OTItem::exchangeBasket);
5733  OTItem* pBalanceItem = tranIn.GetItem(OTItem::balanceStatement);
5734  OTItem* pResponseItem = nullptr;
5735  OTItem* pResponseBalanceItem = nullptr;
5736 
5737  // The incoming transaction may be sent to inboxes and outboxes, and it
5738  // will probably be bundled in our reply to the user as well. Therefore,
5739  // let's grab it as a string.
5740  OTString strInReferenceTo;
5741  OTString strBalanceItem;
5742 
5743  const OTIdentifier USER_ID(theNym), SERVER_ID(server_->m_strServerID),
5744  BASKET_CONTRACT_ID(theAccount.GetAssetTypeID()), ACCOUNT_ID(theAccount);
5745 
5746  const OTString strUserID(USER_ID);
5747 
5748  std::unique_ptr<OTLedger> pInbox(
5749  theAccount.LoadInbox(server_->m_nymServer));
5750  std::unique_ptr<OTLedger> pOutbox(
5751  theAccount.LoadOutbox(server_->m_nymServer));
5752 
5753  pResponseItem =
5755  pResponseItem->SetStatus(OTItem::rejection); // the default.
5756  tranOut.AddItem(*pResponseItem); // the Transaction's destructor will
5757  // cleanup the item. It "owns" it now.
5758 
5759  pResponseBalanceItem =
5761  pResponseBalanceItem->SetStatus(OTItem::rejection); // the default.
5762  tranOut.AddItem(*pResponseBalanceItem); // the Transaction's destructor will
5763  // cleanup the item. It "owns" it
5764  // now.
5765  bool bSuccess = false;
5766 
5767  if (!NYM_IS_ALLOWED(strUserID.Get(),
5769  OTLog::vOutput(0, "Notary::NotarizeExchangeBasket: User %s cannot do "
5770  "this transaction (All basket exchanges are "
5771  "disallowed in server.cfg)\n",
5772  strUserID.Get());
5773  }
5774  else if (nullptr == pItem) {
5775  OTLog::Output(0, "Notary::NotarizeExchangeBasket: No exchangeBasket "
5776  "item found on this transaction.\n");
5777  }
5778  else if (nullptr == pBalanceItem) {
5779  OTLog::Output(0, "Notary::NotarizeExchangeBasket: No Balance "
5780  "Agreement item found on this transaction.\n");
5781  }
5782  else if ((nullptr == pInbox)) {
5783  OTLog::Error("Error loading or verifying inbox.\n");
5784  }
5785  else if ((nullptr == pOutbox)) {
5786  OTLog::Error("Error loading or verifying outbox.\n");
5787  }
5788  else {
5789  pItem->SaveContractRaw(strInReferenceTo);
5790  pBalanceItem->SaveContractRaw(strBalanceItem);
5791 
5792  pResponseItem->SetReferenceString(strInReferenceTo); // the response
5793  // item carries a
5794  // copy of what
5795  // it's responding
5796  // to.
5797  pResponseItem->SetReferenceToNum(
5798  pItem->GetTransactionNum()); // This response item is IN RESPONSE to
5799  // pItem and its Owner Transaction.
5800 
5801  pResponseBalanceItem->SetReferenceString(
5802  strBalanceItem); // the response item carries a copy of what it's
5803  // responding to.
5804  pResponseBalanceItem->SetReferenceToNum(
5805  pBalanceItem->GetTransactionNum()); // This response item is IN
5806  // RESPONSE to tranIn's balance
5807  // agreement
5808  // Now after all that setup, we do the balance agreement!
5809  if (false ==
5810  pBalanceItem->VerifyBalanceStatement(
5811  0, // the one balance agreement that doesn't change any
5812  // balances.
5813  theNym, // Could have been a transaction agreement.
5814  *pInbox, // Still could be, in fact....
5815  *pOutbox, theAccount, tranIn)) {
5816  OTLog::vOutput(0, "Notary::NotarizeExchangeBasket: ERROR "
5817  "verifying balance statement.\n");
5818 
5819  }
5820  else // BALANCE AGREEMENT WAS SUCCESSFUL.......
5821  {
5822  pResponseBalanceItem->SetStatus(
5823  OTItem::acknowledgement); // the balance agreement was
5824  // successful.
5825 
5826  // Set up some account pointer lists for later...
5827  listOfAccounts listUserAccounts, listServerAccounts;
5828  std::list<OTLedger*> listInboxes;
5829 
5830  // Here's the request from the user.
5831  OTString strBasket;
5832  Basket theBasket, theRequestBasket;
5833 
5834  pItem->GetAttachment(strBasket);
5835 
5836  int64_t lTransferAmount = 0;
5837 
5838  // Now we have the Contract ID from the basket account,
5839  // we can get a pointer to its asset contract...
5840 
5841  OTIdentifier BASKET_ACCOUNT_ID;
5842 
5843  OTAccount* pBasketAcct = nullptr;
5844  std::unique_ptr<OTAccount> theBasketAcctGuardian;
5845 
5846  bool bLookup =
5847  server_->transactor_.lookupBasketAccountIDByContractID(
5848  BASKET_CONTRACT_ID, BASKET_ACCOUNT_ID);
5849  if (!bLookup) {
5850  OTLog::Error("Notary::NotarizeExchangeBasket: Asset type is "
5851  "not a basket currency.\n");
5852  }
5853  else if (!strBasket.Exists() ||
5854  !theRequestBasket.LoadContractFromString(strBasket) ||
5855  !theRequestBasket.VerifySignature(theNym)) {
5856  OTLog::Error("Notary::NotarizeExchangeBasket: Expected "
5857  "verifiable basket object to be attached to "
5858  "exchangeBasket item.\n");
5859  }
5860  else if (theRequestBasket.GetRequestAccountID() !=
5861  theAccount.GetPurportedAccountID()) {
5862  OTLog::Error("Notary::NotarizeExchangeBasket: User's main "
5863  "account ID according to request basket doesn't "
5864  "match theAccount.\n");
5865  }
5866  else if (false ==
5867  server_->transactor_.verifyTransactionNumber(
5868  theNym, theRequestBasket.GetClosingNum())) {
5869  OTLog::Error("Notary::NotarizeExchangeBasket: Closing number "
5870  "used for User's main account receipt was not "
5871  "available for use...\n");
5872  }
5873  else { // Load the basket account and make sure it exists.
5874  pBasketAcct = OTAccount::LoadExistingAccount(BASKET_ACCOUNT_ID,
5875  SERVER_ID);
5876 
5877  // If the pointer is nullptr, that works too. Otherwise it
5878  // cleans
5879  // up the object at the end of this function.
5880  theBasketAcctGuardian.reset(pBasketAcct);
5881 
5882  if (nullptr == pBasketAcct) {
5883  OTLog::Error("ERROR loading the basket account in "
5884  "Notary::NotarizeExchangeBasket\n");
5885  }
5886  // Does it verify?
5887  // I call VerifySignature here since VerifyContractID was
5888  // already called in LoadExistingAccount().
5889  else if (!pBasketAcct->VerifySignature(server_->m_nymServer)) {
5890  OTLog::Error("ERROR verifying signature on the basket "
5891  "account in "
5892  "Notary::NotarizeExchangeBasket\n");
5893  }
5894  else {
5895  // Now we get a pointer to its asset contract...
5896  OTAssetContract* pContract =
5897  server_->transactor_.getAssetContract(
5898  BASKET_CONTRACT_ID);
5899 
5900  // Now let's load up the actual basket, from the actual
5901  // asset contract.
5902  if (pContract &&
5903  theBasket.LoadContractFromString(
5904  pContract->GetBasketInfo()) &&
5905  theBasket.VerifySignature(server_->m_nymServer) &&
5906  theBasket.Count() == theRequestBasket.Count() &&
5907  theBasket.GetMinimumTransfer() ==
5908  theRequestBasket.GetMinimumTransfer()) {
5909  // Let's make sure that the same asset account doesn't
5910  // appear twice on the request.
5911  //
5912  std::set<OTIdentifier> setOfAccounts;
5913  setOfAccounts.insert(
5914  theRequestBasket.GetRequestAccountID());
5915 
5916  bool bFoundSameAcctTwice = false;
5917 
5918  for (int32_t i = 0; i < theRequestBasket.Count(); i++) {
5919  BasketItem* pItem = theRequestBasket.At(i);
5920  OT_ASSERT(nullptr != pItem);
5921  std::set<OTIdentifier>::iterator it_account =
5922  setOfAccounts.find(pItem->SUB_ACCOUNT_ID);
5923 
5924  if (setOfAccounts.end() !=
5925  it_account) // The account appears twice!!
5926  {
5927  const OTString strSubID(pItem->SUB_ACCOUNT_ID);
5928  OTLog::vError("%s: Failed: Sub-account ID "
5929  "found TWICE on same basket "
5930  "exchange request: %s\n",
5931  __FUNCTION__, strSubID.Get());
5932  bFoundSameAcctTwice = true;
5933  break;
5934  }
5935  setOfAccounts.insert(pItem->SUB_ACCOUNT_ID);
5936  }
5937  if (!bFoundSameAcctTwice) // Let's do it!
5938  {
5939  // Loop through the request AND the actual basket
5940  // TOGETHER...
5941  for (int32_t i = 0; i < theBasket.Count(); i++) {
5942  BasketItem* pBasketItem = theBasket.At(i);
5943  BasketItem* pRequestItem =
5944  theRequestBasket.At(i); // we already know
5945  // these are the
5946  // same length
5947 
5948  // if not equal
5949  if (!(pBasketItem->SUB_CONTRACT_ID ==
5950  pRequestItem->SUB_CONTRACT_ID)) {
5951  OTLog::Error("Error: expected asset type "
5952  "IDs to match in "
5953  "Notary::"
5954  "NotarizeExchangeBasket\n");
5955  bSuccess = false;
5956  break;
5957  }
5958  // if accounts are equal (should never happen --
5959  // why would the user be trying to use the
5960  // server's account as his own?)
5961  // Furthermore, loading both at the same time,
5962  // with same ID, then saving again, can screw up
5963  // the balance.
5964  //
5965  else if (pBasketItem->SUB_ACCOUNT_ID ==
5966  pRequestItem->SUB_ACCOUNT_ID) {
5967  OTLog::Error("Error: VERY strange to have "
5968  "these account ID's match. "
5969  "Notary::"
5970  "NotarizeExchangeBasket.\n");
5971  bSuccess = false;
5972  break;
5973  }
5974  else if (false ==
5975  server_->transactor_
5977  theNym,
5978  pRequestItem
5979  ->lClosingTransactionNo)) {
5980  OTLog::Error(
5981  "Error: Basket sub-currency closing "
5982  "number didn't verify . "
5983  "Notary::NotarizeExchangeBasket.\n");
5984  bSuccess = false;
5985  break;
5986  }
5987  else // if equal
5988  {
5989  bSuccess = true;
5990 
5991  // Load up the two accounts and perform the
5992  // exchange...
5993  OTAccount* pUserAcct =
5995  pRequestItem->SUB_ACCOUNT_ID,
5996  SERVER_ID);
5997 
5998  if (nullptr == pUserAcct) {
5999  OTLog::Error("ERROR loading a user's "
6000  "asset account in "
6001  "Notary::"
6002  "NotarizeExchangeBasket"
6003  "\n");
6004  bSuccess = false;
6005  break;
6006  }
6007  OTAccount* pServerAcct =
6009  pBasketItem->SUB_ACCOUNT_ID,
6010  SERVER_ID);
6011 
6012  if (nullptr == pServerAcct) {
6013  OTLog::Error("ERROR loading a basket "
6014  "sub-account in "
6015  "Notary::"
6016  "NotarizeExchangeBasket"
6017  "\n");
6018  bSuccess = false;
6019  break;
6020  }
6021  // Load up the inbox for the user's sub
6022  // account, so we can drop the receipt.
6023  //
6024  OTLedger* pSubInbox = pUserAcct->LoadInbox(
6025  server_->m_nymServer);
6026 
6027  if (nullptr == pSubInbox) {
6028  OTLog::Error("Error loading or "
6029  "verifying sub-inbox in "
6030  "Notary::"
6031  "NotarizeExchangeBasket."
6032  "\n");
6033  bSuccess = false;
6034  break;
6035  }
6036 
6037  // I'm preserving these points, to be
6038  // deleted at the end.
6039  // They won't be saved until after ALL
6040  // debits/credits were successful.
6041  // Once ALL exchanges are done, THEN it
6042  // loops through and saves / deletes
6043  // all the accounts.
6044  listUserAccounts.push_back(pUserAcct);
6045  listServerAccounts.push_back(pServerAcct);
6046  listInboxes.push_back(pSubInbox);
6047 
6048  // Do they verify?
6049  // I call VerifySignature here since
6050  // VerifyContractID was already called in
6051  // LoadExistingAccount().
6052  if (pUserAcct->GetAssetTypeID() !=
6053  pBasketItem->SUB_CONTRACT_ID) {
6054  OTLog::Error(
6055  "ERROR verifying asset type on a "
6056  "user's account in "
6057  "Notary::"
6058  "NotarizeExchangeBasket\n");
6059  bSuccess = false;
6060  break;
6061  }
6062  else if (!pUserAcct->VerifySignature(
6063  server_->m_nymServer)) {
6064  OTLog::Error(
6065  "ERROR verifying signature on a "
6066  "user's asset account in "
6067  "Notary::"
6068  "NotarizeExchangeBasket\n");
6069  bSuccess = false;
6070  break;
6071  }
6072  else if (!pServerAcct->VerifySignature(
6073  server_->m_nymServer)) {
6074  OTLog::Error(
6075  "ERROR verifying signature on a "
6076  "basket sub-account in "
6077  "Notary::"
6078  "NotarizeExchangeBasket\n");
6079  bSuccess = false;
6080  break;
6081  }
6082  else {
6083  // the amount being transferred between
6084  // these two accounts is the minimum
6085  // transfer amount
6086  // for the sub-account on the basket,
6087  // multiplied by
6088  lTransferAmount =
6089  (pBasketItem
6090  ->lMinimumTransferAmount *
6091  theRequestBasket
6092  .GetTransferMultiple());
6093 
6094  // user is performing exchange IN
6095  if (theRequestBasket
6096  .GetExchangingIn()) {
6097  if (pUserAcct->Debit(
6098  lTransferAmount)) {
6099  if (pServerAcct->Credit(
6100  lTransferAmount))
6101  bSuccess = true;
6102  else { // the server credit
6103  // failed.
6104  OTLog::Error(
6105  " Notary::"
6106  "NotarizeExchangeBasket"
6107  ": Failure crediting "
6108  "server acct.\n");
6109 
6110  // Since we debited the
6111  // user's acct already,
6112  // let's put that back.
6113  if (false ==
6114  pUserAcct->Credit(
6115  lTransferAmount))
6116  OTLog::Error(
6117  " Notary::"
6118  "NotarizeExchangeBa"
6119  "sket: Failure "
6120  "crediting back "
6121  "user "
6122  "account.\n");
6123  bSuccess = false;
6124  break;
6125  }
6126  }
6127  else {
6128  OTLog::Output(
6129  0, "Notary::"
6130  "NotarizeExchangeBasket:"
6131  " Unable to Debit user "
6132  "account.\n");
6133  bSuccess = false;
6134  break;
6135  }
6136  }
6137  else // user is peforming exchange OUT
6138  {
6139  if (pServerAcct->Debit(
6140  lTransferAmount)) {
6141  if (pUserAcct->Credit(
6142  lTransferAmount))
6143  bSuccess = true;
6144  else { // the user credit
6145  // failed.
6146  OTLog::Error(
6147  " Notary::"
6148  "NotarizeExchangeBasket"
6149  ": Failure crediting "
6150  "user acct.\n");
6151 
6152  // Since we debited the
6153  // server's acct already,
6154  // let's put that back.
6155  if (false ==
6156  pServerAcct->Credit(
6157  lTransferAmount))
6158  OTLog::Error(
6159  " Notary::"
6160  "NotarizeExchangeBa"
6161  "sket: Failure "
6162  "crediting back "
6163  "server "
6164  "account.\n");
6165  bSuccess = false;
6166  break;
6167  }
6168  }
6169  else {
6170  OTLog::Output(
6171  0, " Notary::"
6172  "NotarizeExchangeBasket:"
6173  " Unable to Debit "
6174  "server account.\n");
6175  bSuccess = false;
6176  break;
6177  }
6178  }
6179  // Drop the receipt -- accounts were
6180  // debited and credited properly.
6181  //
6182  if (bSuccess) { // need to be able to
6183  // "roll back" if
6184  // anything inside this
6185  // block fails.
6186  // update: actually does pretty good
6187  // roll-back as it is. The debits
6188  // and credits
6189  // don't save unless everything is a
6190  // success.
6191 
6192  // Generate new transaction number
6193  // (for putting the basketReceipt in
6194  // the exchanger's inbox.)
6195  // todo check this generation for
6196  // failure (can it fail?)
6197  int64_t lNewTransactionNumber = 0;
6198 
6199  server_->transactor_
6201  server_->m_nymServer,
6202  lNewTransactionNumber,
6203  false);
6204 
6205  OTTransaction* pInboxTransaction =
6208  *pSubInbox,
6209  OTTransaction::
6210  basketReceipt,
6211  lNewTransactionNumber);
6212 
6213  OTItem* pItemInbox = OTItem::
6215  *pInboxTransaction,
6217 
6218  // these may be unnecessary, I'll
6219  // have to check
6220  // CreateItemFromTransaction. I'll
6221  // leave em.
6222  OT_ASSERT(nullptr != pItemInbox);
6223 
6224  pItemInbox->SetStatus(
6226  pItemInbox->SetAmount(
6227  theRequestBasket
6228  .GetExchangingIn()
6229  ? lTransferAmount * (-1)
6230  : lTransferAmount);
6231 
6232  pItemInbox->SignContract(
6233  server_->m_nymServer);
6234  pItemInbox->SaveContract();
6235 
6236  pInboxTransaction->AddItem(
6237  *pItemInbox); // Add the inbox
6238  // item to the
6239  // inbox
6240  // transaction, so
6241  // we can add to
6242  // the inbox
6243  // ledger.
6244 
6245  pInboxTransaction
6246  ->SetNumberOfOrigin(*pItem);
6247 
6248  // The "exchangeBasket request"
6249  // OTItem is saved as the "In
6250  // Reference To" field
6251  // on the inbox basketReceipt
6252  // transaction.
6253  // todo put these two together in a
6254  // method.
6255  pInboxTransaction
6256  ->SetReferenceString(
6257  strInReferenceTo);
6258  pInboxTransaction
6259  ->SetReferenceToNum(
6260  pItem->GetTransactionNum());
6261  // Here is the number the user
6262  // wishes
6263  // to sign-off by accepting this
6264  // receipt.
6265  pInboxTransaction->SetClosingNum(
6266  pRequestItem
6267  ->lClosingTransactionNo);
6268 
6269  // Now we have created a new
6270  // transaction from the server to
6271  // the sender's inbox (for a
6272  // receipt).
6273  // Let's sign and save it...
6274  pInboxTransaction->SignContract(
6275  server_->m_nymServer);
6276  pInboxTransaction->SaveContract();
6277 
6278  // Here the transaction we just
6279  // created is actually added to the
6280  // exchanger's inbox.
6281  pSubInbox->AddTransaction(
6282  *pInboxTransaction);
6283  pInboxTransaction->SaveBoxReceipt(
6284  *pSubInbox);
6285  }
6286  } // User and Server sub-accounts are good.
6287  } // pBasketItem and pRequestItem are good.
6288  } // for (loop through basketitems)
6289  // Load up the two main accounts and perform the
6290  // exchange...
6291  // (Above we did the sub-accounts for server and
6292  // user. Now we do the main accounts for server and
6293  // user.)
6294  //
6295 
6296  // At this point, if we have successfully debited /
6297  // credited the sub-accounts.
6298  // then we need to debit and credit the user's main
6299  // basket account and the server's basket issuer
6300  // account.
6301  if ((true == bSuccess) &&
6302  (nullptr != pBasketAcct)) {
6303  lTransferAmount =
6304  (theRequestBasket.GetMinimumTransfer() *
6305  theRequestBasket.GetTransferMultiple());
6306 
6307  // Load up the two accounts and perform the
6308  // exchange...
6309  // user is performing exchange IN
6310  if (theRequestBasket.GetExchangingIn()) {
6311  if (pBasketAcct->Debit(lTransferAmount)) {
6312  if (theAccount.Credit(lTransferAmount))
6313  bSuccess = true;
6314  else {
6315  OTLog::Error("Notary::"
6316  "NotarizeExchangeBaske"
6317  "t: Failed crediting "
6318  "user basket "
6319  "account.\n");
6320 
6321  if (false ==
6322  pBasketAcct->Credit(
6323  lTransferAmount))
6324  OTLog::Error(
6325  "Notary::"
6326  "NotarizeExchangeBasket: "
6327  "Failed crediting back "
6328  "basket issuer account.\n");
6329 
6330  bSuccess = false;
6331  }
6332  }
6333  else {
6334  bSuccess = false;
6335  OTLog::Output(
6336  0, "Unable to Debit basket issuer "
6337  "account, in "
6338  "Notary::"
6339  "NotarizeExchangeBasket\n");
6340  }
6341  }
6342  else // user is peforming exchange OUT
6343  {
6344  if (theAccount.Debit(lTransferAmount)) {
6345  if (pBasketAcct->Credit(
6346  lTransferAmount))
6347  bSuccess = true;
6348  else {
6349  OTLog::Error("Notary::"
6350  "NotarizeExchangeBaske"
6351  "t: Failed crediting "
6352  "basket issuer "
6353  "account.\n");
6354 
6355  if (false ==
6356  theAccount.Credit(
6357  lTransferAmount))
6358  OTLog::Error(
6359  "Notary::"
6360  "NotarizeExchangeBasket: "
6361  "Failed crediting back "
6362  "user basket account.\n");
6363 
6364  bSuccess = false;
6365  }
6366  }
6367  else {
6368  bSuccess = false;
6369  OTLog::Output(0, "Unable to Debit user "
6370  "basket account in "
6371  "Notary::"
6372  "NotarizeExchangeBaske"
6373  "t\n");
6374  }
6375  }
6376 
6377  // Drop the receipt -- accounts were debited and
6378  // credited properly.
6379  //
6380  if (bSuccess) { // need to be able to "roll
6381  // back" if anything inside this
6382  // block fails.
6383  // update: actually does pretty good
6384  // roll-back as it is. The debits and
6385  // credits
6386  // don't save unless everything is a
6387  // success.
6388 
6389  // Generate new transaction number (for
6390  // putting the basketReceipt in the
6391  // exchanger's inbox.)
6392  // todo check this generation for failure
6393  // (can it fail?)
6394  int64_t lNewTransactionNumber = 0;
6395 
6396  server_->transactor_
6398  server_->m_nymServer,
6399  lNewTransactionNumber,
6400  false); // bStoreTheNumber = false
6401 
6402  OTTransaction* pInboxTransaction =
6404  *pInbox,
6406  lNewTransactionNumber);
6407 
6408  OTItem* pItemInbox =
6410  *pInboxTransaction,
6412 
6413  // these may be unnecessary, I'll have to
6414  // check CreateItemFromTransaction. I'll
6415  // leave em.
6416  OT_ASSERT(nullptr != pItemInbox);
6417 
6418  pItemInbox->SetStatus(
6419  OTItem::acknowledgement); // the
6420  // default.
6421  pItemInbox->SetAmount(
6422  theRequestBasket.GetExchangingIn()
6423  ? lTransferAmount
6424  : lTransferAmount * (-1));
6425 
6426  pItemInbox->SignContract(
6427  server_->m_nymServer);
6428  pItemInbox->SaveContract();
6429 
6430  pInboxTransaction->AddItem(
6431  *pItemInbox); // Add the inbox item to
6432  // the inbox transaction,
6433  // so we can add to the
6434  // inbox ledger.
6435 
6436  pInboxTransaction->SetNumberOfOrigin(
6437  *pItem);
6438 
6439  // The exchangeBasket request OTItem is
6440  // saved as a "in reference to" field,
6441  // on the inbox basketReceipt transaction.
6442  // todo put these two together in a method.
6443  pInboxTransaction->SetReferenceString(
6444  strInReferenceTo);
6445  pInboxTransaction->SetReferenceToNum(
6446  pItem->GetTransactionNum());
6447  pInboxTransaction->SetClosingNum(
6448  theRequestBasket
6449  .GetClosingNum()); // So the
6450  // exchanger can
6451  // sign-off on
6452  // this closing
6453  // num by
6454  // accepting the
6455  // basket receipt
6456  // on his main
6457  // basket
6458  // account.
6459 
6460  // Now we have created a new transaction
6461  // from the server to the sender's inbox
6462  // Let's sign and save it...
6463  pInboxTransaction->SignContract(
6464  server_->m_nymServer);
6465  pInboxTransaction->SaveContract();
6466 
6467  // Here the transaction we just created is
6468  // actually added to the source acct's
6469  // inbox.
6470  pInbox->AddTransaction(*pInboxTransaction);
6471  pInboxTransaction->SaveBoxReceipt(*pInbox);
6472  }
6473  }
6474  else {
6475  OTLog::Error("Error loading or verifying "
6476  "user's main basket account in "
6477  "Notary::"
6478  "NotarizeExchangeBasket\n");
6479  bSuccess = false;
6480  }
6481 
6482  // At this point, we have hopefully credited/debited
6483  // ALL the relevant accounts.
6484  // So now, let's Save them ALL to disk.. (and clean
6485  // them up.)
6486  OTAccount* pAccount = nullptr;
6487 
6488  // empty the list of USER accounts (and save to
6489  // disk, if everything was successful.)
6490  while (!listUserAccounts.empty()) {
6491  pAccount = listUserAccounts.front();
6492  if (nullptr == pAccount) OT_FAIL;
6493  listUserAccounts.pop_front();
6494 
6495  if (true == bSuccess) {
6496  pAccount->ReleaseSignatures();
6497  pAccount->SignContract(
6498  server_->m_nymServer);
6499  pAccount->SaveContract();
6500  pAccount->SaveAccount();
6501  }
6502 
6503  delete pAccount;
6504  pAccount = nullptr;
6505  }
6506  // empty the list of SERVER accounts (and save to
6507  // disk, if everything was successful.)
6508  while (!listServerAccounts.empty()) {
6509  pAccount = listServerAccounts.front();
6510  if (nullptr == pAccount) OT_FAIL;
6511 
6512  listServerAccounts.pop_front();
6513 
6514  if (true == bSuccess) {
6515  pAccount->ReleaseSignatures();
6516  pAccount->SignContract(
6517  server_->m_nymServer);
6518  pAccount->SaveContract();
6519  pAccount->SaveAccount();
6520  }
6521 
6522  delete pAccount;
6523  pAccount = nullptr;
6524  }
6525  // empty the list of inboxes (and save to disk, if
6526  // everything was successful.)
6527  while (!listInboxes.empty()) {
6528  OTLedger* pTempInbox = listInboxes.front();
6529  if (nullptr == pTempInbox) OT_FAIL;
6530  listInboxes.pop_front();
6531 
6532  if (true == bSuccess) {
6533  pTempInbox->ReleaseSignatures();
6534  pTempInbox->SignContract(
6535  server_->m_nymServer);
6536  pTempInbox->SaveContract();
6537  pTempInbox->SaveInbox();
6538  }
6539 
6540  delete pTempInbox;
6541  pTempInbox = nullptr;
6542  }
6543  if (true == bSuccess) {
6544  pInbox->ReleaseSignatures();
6545  pInbox->SignContract(server_->m_nymServer);
6546  pInbox->SaveContract();
6547  theAccount.SaveInbox(*pInbox);
6548 
6549  theAccount.ReleaseSignatures();
6550  theAccount.SignContract(server_->m_nymServer);
6551  theAccount.SaveContract();
6552  theAccount.SaveAccount();
6553 
6554  pBasketAcct->ReleaseSignatures();
6555  pBasketAcct->SignContract(server_->m_nymServer);
6556  pBasketAcct->SaveContract();
6557  pBasketAcct->SaveAccount();
6558 
6559  // Remove my ability to use the "closing"
6560  // numbers in the future.
6561  // (Since I'm using them to do this exchange...)
6562  //
6563  for (int32_t i = 0;
6564  i < theRequestBasket.Count(); i++) {
6565  BasketItem* pRequestItem =
6566  theRequestBasket.At(i);
6567 
6568  OT_ASSERT(nullptr != pRequestItem);
6569 
6570  // This just removes the number so I can't
6571  // USE it.
6572  // I'm still RESPONSIBLE for the number
6573  // until RemoveIssuedNumber() is called.
6574  //
6575  server_->transactor_
6577  theNym,
6578  pRequestItem->lClosingTransactionNo,
6579  false);
6580  }
6581  server_->transactor_.removeTransactionNumber(
6582  theNym, theRequestBasket.GetClosingNum(),
6583  true);
6584  pResponseItem->SetStatus(
6585  OTItem::acknowledgement); // the
6586  // exchangeBasket
6587  // was successful.
6588 
6589  bOutSuccess =
6590  true; // The exchangeBasket was successful.
6591  }
6592  } // Let's do it!
6593  }
6594  else {
6595  OTLog::Error(
6596  "Error finding asset contract for basket, or "
6597  "loading the basket from it, or verifying\n"
6598  "the signature on that basket, or the request "
6599  "basket didn't match actual basket.\n");
6600  }
6601  } // pBasket exists and signature verifies
6602  } // theRequestBasket loaded properly.
6603  } // else (balance agreement verified.)
6604  } // Balance Agreement item found.
6605 
6606  // I put this here so it's signed/saved whether the balance agreement itself
6607  // was successful OR NOT.
6608  pResponseItem->SignContract(server_->m_nymServer);
6609  pResponseItem->SaveContract();
6610 
6611  pResponseBalanceItem->SignContract(server_->m_nymServer);
6612  pResponseBalanceItem->SaveContract();
6613 }
static EXPORT void vError(const char *szError,...)
Definition: OTLog.cpp:800
static EXPORT OTTransaction * GenerateTransaction(const OTIdentifier &theUserID, const OTIdentifier &theAccountID, const OTIdentifier &theServerID, transactionType theType, int64_t lTransactionNum=0)
static EXPORT void Output(int32_t nVerbosity, const char *szOutput)
Definition: OTLog.cpp:710
std::list< OTAccount * > listOfAccounts
Definition: Notary.cpp:166
bool lookupBasketAccountIDByContractID(const OTIdentifier &basketContractId, OTIdentifier &basketAccountId)
Definition: Transactor.cpp:457
bool issueNextTransactionNumber(OTPseudonym &nym, int64_t &txNumber, bool storeNumber=true)
Definition: Transactor.cpp:211
#define NYM_IS_ALLOWED(SZ_NYM_ID, BOOL_VAR_NAME)
Definition: Macros.hpp:146
bool verifyTransactionNumber(OTPseudonym &nym, const int64_t &transactionNumber)
Definition: Transactor.cpp:278
bool removeTransactionNumber(OTPseudonym &nym, const int64_t &transactionNumber, bool save=false)
Definition: Transactor.cpp:320
static EXPORT OTItem * CreateItemFromTransaction(const OTTransaction &theOwner, OTItem::itemType theType, const OTIdentifier *pDestinationAcctID=nullptr)
Definition: OTItem.cpp:1451
static EXPORT void Error(const char *szError)
Definition: OTLog.cpp:831
#define OT_ASSERT(x)
Definition: Assert.hpp:150
#define OT_FAIL
Definition: Assert.hpp:139
OTAssetContract * getAssetContract(const OTIdentifier &id)
Definition: Transactor.cpp:394
static bool __transact_exchange_basket
static EXPORT void vOutput(int32_t nVerbosity, const char *szOutput,...)
Definition: OTLog.cpp:768
static EXPORT OTAccount * LoadExistingAccount(const OTIdentifier &accountId, const OTIdentifier &serverId)
Definition: OTAccount.cpp:480
void opentxs::Notary::NotarizeMarketOffer ( OTPseudonym nym,
OTAccount assetAccount,
OTTransaction tranIn,
OTTransaction tranOut,
bool &  outSuccess 
)

Definition at line 6618 of file Notary.cpp.

6622 {
6623  // The outgoing transaction is an "atMarketOffer", that is, "a reply to the
6624  // marketOffer request"
6625  tranOut.SetType(OTTransaction::atMarketOffer);
6626 
6627  OTItem* pItem = nullptr;
6628  OTItem* pBalanceItem = nullptr;
6629  OTItem* pResponseItem = nullptr;
6630  OTItem* pResponseBalanceItem = nullptr;
6631 
6632  // The incoming transaction may be sent to inboxes and outboxes, and it
6633  // will definitely be bundled in our reply to the user as well. Therefore,
6634  // let's grab it as a string.
6635  OTString strInReferenceTo;
6636  OTString strBalanceItem;
6637 
6638  // Grab the actual server ID from this object, and use it as the server ID
6639  // here.
6640  const OTIdentifier SERVER_ID(server_->m_strServerID), USER_ID(theNym);
6641  const OTString strUserID(USER_ID);
6642 
6643  pItem = tranIn.GetItem(OTItem::marketOffer);
6644  pBalanceItem = tranIn.GetItem(OTItem::transactionStatement);
6645  pResponseItem =
6647  pResponseItem->SetStatus(OTItem::rejection); // the default.
6648  tranOut.AddItem(*pResponseItem); // the Transaction's destructor will
6649  // cleanup the item. It "owns" it now.
6650 
6651  pResponseBalanceItem = OTItem::CreateItemFromTransaction(
6653  pResponseBalanceItem->SetStatus(OTItem::rejection); // the default.
6654  tranOut.AddItem(*pResponseBalanceItem); // the Transaction's destructor will
6655  // cleanup the item. It "owns" it
6656  // now.
6657  if (!NYM_IS_ALLOWED(strUserID.Get(),
6660  0,
6661  "Notary::NotarizeMarketOffer: User %s cannot do this transaction "
6662  "(All market offers are disallowed in server.cfg)\n",
6663  strUserID.Get());
6664  }
6665  else if (nullptr == pBalanceItem) {
6666  OTString strTemp(tranIn);
6667  OTLog::vOutput(0, "Notary::NotarizeMarketOffer: Expected transaction "
6668  "statement in trans # %ld: \n\n%s\n\n",
6669  tranIn.GetTransactionNum(),
6670  strTemp.Exists()
6671  ? strTemp.Get()
6672  : " (ERROR LOADING TRANSACTION INTO STRING) ");
6673  }
6674  else if (nullptr == pItem) {
6675  OTString strTemp(tranIn);
6676  OTLog::vOutput(0, "Notary::NotarizeMarketOffer: Expected "
6677  "OTItem::marketOffer in trans# %ld:\n\n%s\n\n",
6678  tranIn.GetTransactionNum(),
6679  strTemp.Exists()
6680  ? strTemp.Get()
6681  : " (ERROR LOADING TRANSACTION INTO STRING) ");
6682  }
6683  // For now, there should only be one of these marketOffer items inside the
6684  // transaction.
6685  // So we treat it that way... I either get it successfully or not.
6686  else {
6687  // The response item will contain a copy of the request item. So I save
6688  // it into a string
6689  // here so it can be saved into the "in reference to" field.
6690  pItem->SaveContractRaw(strInReferenceTo);
6691  pBalanceItem->SaveContractRaw(strBalanceItem);
6692 
6693  // ASSET_ACCT_ID is the ID on the "from" Account that was passed in.
6694  // The CURRENCY_ACCT_ID is the ID on the "To" Account. (When doing a
6695  // transfer, normally 2nd acct is the Payee.)
6696  const OTIdentifier ASSET_ACCT_ID(theAssetAccount),
6697  CURRENCY_ACCT_ID(pItem->GetDestinationAcctID());
6698 
6699  // Server response item being added to server response transaction
6700  // (tranOut)
6701  // They're getting SOME sort of response item.
6702 
6703  pResponseItem->SetReferenceString(strInReferenceTo); // the response
6704  // item carries a
6705  // copy of what
6706  // it's responding
6707  // to.
6708  pResponseItem->SetReferenceToNum(
6709  pItem->GetTransactionNum()); // This response item is IN RESPONSE to
6710  // pItem and its Owner Transaction.
6711 
6712  pResponseBalanceItem->SetReferenceString(
6713  strBalanceItem); // the response item carries a copy of what it's
6714  // responding to.
6715  pResponseBalanceItem->SetReferenceToNum(
6716  pItem->GetTransactionNum()); // This response item is IN RESPONSE to
6717  // pItem and its Owner Transaction.
6718 
6719  if (!(pBalanceItem->VerifyTransactionStatement(
6720  theNym, tranIn))) // bIsRealTransaction = true;
6721  {
6722  OTLog::vOutput(0, "ERROR verifying transaction statement in "
6723  "NotarizeMarketOffer.\n");
6724  }
6725  else {
6726  pResponseBalanceItem->SetStatus(
6727  OTItem::acknowledgement); // the transaction agreement was
6728  // successful.
6729 
6730  // Load up the currency account and validate it.
6731  std::unique_ptr<OTAccount> pCurrencyAcct(
6732  OTAccount::LoadExistingAccount(CURRENCY_ACCT_ID, SERVER_ID));
6733 
6734  // Also load up the Trade from inside the transaction item.
6735  OTString strOffer;
6736  OTOffer theOffer;
6737 
6738  OTString strTrade;
6739  pItem->GetAttachment(strTrade);
6740 
6741  OTTrade* pTrade = new OTTrade();
6742 
6743  OT_ASSERT(nullptr != pTrade);
6744 
6745  // First load the Trade up (from the string that was passed in on
6746  // the transaction item.)
6747  bool bLoadContractFromString =
6748  pTrade->LoadContractFromString(strTrade);
6749 
6750  // If failed to load the trade...
6751  if (!bLoadContractFromString) {
6752  OTLog::vError("ERROR loading trade from string in "
6753  "Notary::NotarizeMarketOffer:\n%s\n",
6754  strTrade.Get());
6755  }
6756  // I'm using the operator== because it exists. (Although now I
6757  // believe != exists also)
6758  // If the ID on the "from" account that was passed in,
6759  // does not match the "Acct From" ID on this transaction item
6760  else if (!(ASSET_ACCT_ID == pItem->GetPurportedAccountID())) {
6761  OTLog::Output(0, "Error: Asset account ID on the transaction "
6762  "does not match asset account ID on the "
6763  "transaction item.\n");
6764  }
6765  // ok so the IDs match. Does the currency account exist?
6766  else if (nullptr == pCurrencyAcct) {
6767  OTLog::Output(0, "ERROR verifying existence of the currency "
6768  "account in Notary::NotarizeMarketOffer\n");
6769  }
6770  else if (!pCurrencyAcct->VerifyContractID()) {
6771  OTLog::Output(0, "ERROR verifying Contract ID on the currency "
6772  "account in Notary::NotarizeMarketOffer\n");
6773  }
6774  else if (!pCurrencyAcct->VerifyOwner(theNym)) {
6775  OTLog::Output(0, "ERROR verifying ownership of the currency "
6776  "account in Notary::NotarizeMarketOffer\n");
6777  }
6778  // Are both of the accounts of the same Asset Type?
6779  else if (theAssetAccount.GetAssetTypeID() ==
6780  pCurrencyAcct->GetAssetTypeID()) {
6781  OTString strAssetTypeID(theAssetAccount.GetAssetTypeID()),
6782  strCurrencyTypeID(pCurrencyAcct->GetAssetTypeID());
6784  0, "ERROR - user attempted to trade between identical "
6785  "asset types in Notary::NotarizeMarketOffer:\n%s\n%s\n",
6786  strAssetTypeID.Get(), strCurrencyTypeID.Get());
6787  }
6788  // Does it verify?
6789  // I call VerifySignature here since VerifyContractID was already
6790  // called in LoadExistingAccount().
6791  else if (!pCurrencyAcct->VerifySignature(server_->m_nymServer)) {
6792  OTLog::Output(0, "ERROR verifying signature on the Currency "
6793  "account in Notary::NotarizeMarketOffer\n");
6794  }
6795  else if (!pTrade->VerifySignature(theNym)) {
6796  OTLog::Output(0, "ERROR verifying signature on the Trade in "
6797  "Notary::NotarizeMarketOffer\n");
6798  }
6799  else if (pTrade->GetTransactionNum() !=
6800  pItem->GetTransactionNum()) {
6801  OTLog::Output(0, "ERROR bad transaction number on trade in "
6802  "Notary::NotarizeMarketOffer\n");
6803  }
6804  // The transaction number opens the market offer, but there must
6805  // also be a closing number for closing it.
6806  else if ((pTrade->GetCountClosingNumbers() < 2) ||
6807  !server_->transactor_.verifyTransactionNumber(
6808  theNym,
6809  pTrade->GetAssetAcctClosingNum()) || // Verify that it
6810  // can still be
6811  // USED
6812  !server_->transactor_.verifyTransactionNumber(
6813  theNym, pTrade->GetCurrencyAcctClosingNum())) {
6814  OTLog::Output(0, "ERROR needed 2 valid closing transaction "
6815  "numbers in Notary::NotarizeMarketOffer\n");
6816  }
6817  else if (pTrade->GetServerID() != SERVER_ID) {
6818  const OTString strID1(pTrade->GetServerID()), strID2(SERVER_ID);
6819  OTLog::vOutput(0, "Notary::NotarizeMarketOffer: ERROR wrong "
6820  "Server ID (%s) on trade. Expected: %s\n",
6821  strID1.Get(), strID2.Get());
6822  }
6823  else if (pTrade->GetSenderUserID() != USER_ID) {
6824  const OTString strID1(pTrade->GetSenderUserID()),
6825  strID2(USER_ID);
6826  OTLog::vOutput(0, "Notary::NotarizeMarketOffer: ERROR wrong "
6827  "Nym ID (%s) on trade. Expected: %s\n",
6828  strID1.Get(), strID2.Get());
6829  }
6830  else if (pTrade->GetAssetID() !=
6831  theAssetAccount.GetAssetTypeID()) {
6832  const OTString strAssetID1(pTrade->GetAssetID()),
6833  strAssetID2(theAssetAccount.GetAssetTypeID());
6834  OTLog::vOutput(0, "Notary::NotarizeMarketOffer: ERROR wrong "
6835  "Asset Type ID (%s) on trade. Expected: %s\n",
6836  strAssetID1.Get(), strAssetID2.Get());
6837  }
6838  else if (pTrade->GetSenderAcctID() != ASSET_ACCT_ID) {
6839  const OTString strAcctID1(pTrade->GetSenderAcctID()),
6840  strAcctID2(ASSET_ACCT_ID);
6841  OTLog::vOutput(0, "Notary::NotarizeMarketOffer: ERROR wrong "
6842  "asset Acct ID (%s) on trade. Expected: %s\n",
6843  strAcctID1.Get(), strAcctID2.Get());
6844  }
6845  else if (pTrade->GetCurrencyID() !=
6846  pCurrencyAcct->GetAssetTypeID()) {
6847  const OTString strID1(pTrade->GetCurrencyID()),
6848  strID2(pCurrencyAcct->GetAssetTypeID());
6849  OTLog::vOutput(0, "Notary::NotarizeMarketOffer: ERROR wrong "
6850  "Currency Type ID (%s) on trade. Expected: "
6851  "%s\n",
6852  strID1.Get(), strID2.Get());
6853  }
6854  else if (pTrade->GetCurrencyAcctID() != CURRENCY_ACCT_ID) {
6855  const OTString strID1(pTrade->GetCurrencyAcctID()),
6856  strID2(CURRENCY_ACCT_ID);
6857  OTLog::vOutput(0, "Notary::NotarizeMarketOffer: ERROR wrong "
6858  "Currency Acct ID (%s) on trade. Expected: "
6859  "%s\n",
6860  strID1.Get(), strID2.Get());
6861  }
6862  // If the Trade successfully verified, but I couldn't get the offer
6863  // out of it, then it
6864  // actually DIDN'T successfully load still. :-(
6865  else if (!pTrade->GetOfferString(strOffer)) {
6866  OTLog::vError("ERROR getting offer string from trade in "
6867  "Notary::NotarizeMarketOffer:\n%s\n",
6868  strTrade.Get());
6869  }
6870  else if (!theOffer.LoadContractFromString(strOffer)) {
6871  OTLog::vError("ERROR loading offer from string in "
6872  "Notary::NotarizeMarketOffer:\n%s\n",
6873  strTrade.Get());
6874  }
6875  // ...And then we use that same Nym to verify the signature on the
6876  // offer.
6877  else if (!theOffer.VerifySignature(theNym)) {
6878  OTLog::Error("ERROR verifying offer signature in "
6879  "Notary::NotarizeMarketOffer.\n");
6880  }
6881  else if (!pTrade->VerifyOffer(theOffer)) {
6882  OTLog::Output(0, "FAILED verifying offer for Trade in "
6883  "Notary::NotarizeMarketOffer\n");
6884  }
6885  else if (theOffer.GetScale() <
6887  OTLog::vOutput(0, "Notary::NotarizeMarketOffer: FAILED "
6888  "verifying Offer, SCALE: %ld. (Minimum is "
6889  "%ld.) \n",
6890  theOffer.GetScale(),
6892  }
6893  else if (static_cast<int64_t>(
6894  (theNym.GetSetOpenCronItems().size() / 3)) >=
6896  // NOTE:
6897  // We divided by 3 since this set contains THREE numbers for
6898  // each active market offer.
6899  // It's kind of a hack, since it may NOT be three numbers for
6900  // other cron items such as
6901  // payment plans and smart contracts. But it's a good enough
6902  // approximation for now.
6903  //
6904  OTLog::Output(0, "Notary::NotarizeMarketOffer: FAILED adding "
6905  "offer to market: "
6906  "NYM HAS TOO MANY ACTIVE OFFERS ALREADY. See "
6907  "'max_items_per_nym' setting in the config "
6908  "file.\n");
6909  }
6910  // At this point I feel pretty confident that the Trade is a valid
6911  // request from the user.
6912  // The top half of this function is oriented around finding the
6913  // "marketOffer" item (in the "marketOffer"
6914  // transaction) and setting up the response item that will go into
6915  // the response transaction. It also
6916  // retrieves the Trade object and fully validates it.
6917  //
6918  // Next all we need to do is add it to the market...
6919  else {
6920  // We don't actually add the trade to a market here. Instead, we
6921  // add it to the server's Cron object.
6922  // That object will take care of processing the offer on and off
6923  // of any market.
6924  //
6925  // NOTE: FYI, inside AddCronItem, since this is a new CronItem,
6926  // a Cron Receipt will
6927  // be saved with the User's signature on it, containing the Cron
6928  // Item from the user's
6929  // original request. After that, the item is stored internally
6930  // to Cron itself, and
6931  // signed by the server--and changes over time as cron
6932  // processes. (The original receipt
6933  // can always be loaded when necessary.)
6934  //
6935  if (server_->m_Cron.AddCronItem(
6936  *pTrade, &theNym, true,
6937  OTTimeGetCurrentTime())) // bSaveReceipt=true
6938  {
6939  // todo need to be able to "roll back" if anything inside
6940  // this block fails.
6941 
6942  // Now we can set the response item as an acknowledgement
6943  // instead of the default (rejection)
6944  pResponseItem->SetStatus(OTItem::acknowledgement);
6945 
6946  bOutSuccess = true; // The offer was successfully placed on
6947  // the market.
6948 
6949  OTLog::Output(2,
6950  "Successfully added Trade to Cron object.\n");
6951 
6952  // Server side, the Nym stores a list of all open cron item
6953  // numbers.
6954  // (So we know if there is still stuff open on Cron for that
6955  // Nym, and we know what it is.)
6956  //
6957  std::set<int64_t>& theIDSet = theNym.GetSetOpenCronItems();
6958  theIDSet.insert(pTrade->GetTransactionNum());
6959  theIDSet.insert(pTrade->GetAssetAcctClosingNum());
6960  theIDSet.insert(pTrade->GetCurrencyAcctClosingNum());
6961  // This just removes the Closing number so he can't USE it
6962  // again. (Since he's using it as the closing
6963  // number for this cron item now.) He's still RESPONSIBLE
6964  // for the number until RemoveIssuedNumber()
6965  // is called. If we didn't call this here, then he could
6966  // come back later and USE THE NUMBER AGAIN!
6967  // (Bad!) You might ask, why not remove the Opening number
6968  // as well as the Closing numbers? The answer
6969  // is, we already did, before we got here. (Otherwise we
6970  // wouldn't have even gotten this far.)
6971  //
6972  server_->transactor_.removeTransactionNumber(
6973  theNym, pTrade->GetAssetAcctClosingNum(), false);
6974  server_->transactor_.removeTransactionNumber(
6975  theNym, pTrade->GetCurrencyAcctClosingNum(),
6976  false); // (Saved below.)
6977  // RemoveIssuedNum will be called for the original
6978  // transaction number when the finalReceipt is created.
6979  // RemoveIssuedNum will be called for the Closing number
6980  // when the finalReceipt is accepted.
6981 
6982  theNym.SaveSignedNymfile(
6983  server_->m_nymServer); // <===== SAVED HERE.
6984  }
6985  else {
6986  OTLog::Output(0, "Unable to add trade to Cron object "
6987  "Notary::NotarizeMarketOffer\n");
6988  }
6989  }
6990 
6991  // If the trade WAS successfully added to Cron, then we don't need
6992  // to
6993  // delete it here, since Cron owns it now, and will deal with
6994  // cleaning
6995  // it up at the right time.
6996  if ((nullptr != pTrade) &&
6997  pResponseItem->GetStatus() != OTItem::acknowledgement) {
6998  delete pTrade;
6999  pTrade = nullptr;
7000  }
7001  } // transaction statement verified.
7002  }
7003 
7004  // sign the response item before sending it back (it's already been added to
7005  // the transaction above)
7006  // Now, whether it was rejection or acknowledgement, it is set properly and
7007  // it is signed, and it
7008  // is owned by the transaction, who will take it from here.
7009  pResponseItem->SignContract(server_->m_nymServer);
7010  pResponseItem->SaveContract(); // the signing was of no effect because I
7011  // forgot to save. (fixed.)
7012 
7013  pResponseBalanceItem->SignContract(server_->m_nymServer);
7014  pResponseBalanceItem->SaveContract();
7015 }
static EXPORT void vError(const char *szError,...)
Definition: OTLog.cpp:800
static EXPORT void Output(int32_t nVerbosity, const char *szOutput)
Definition: OTLog.cpp:710
#define NYM_IS_ALLOWED(SZ_NYM_ID, BOOL_VAR_NAME)
Definition: Macros.hpp:146
bool verifyTransactionNumber(OTPseudonym &nym, const int64_t &transactionNumber)
Definition: Transactor.cpp:278
EXPORT bool AddCronItem(OTCronItem &theItem, OTPseudonym *pActivator, bool bSaveReceipt, time64_t tDateAdded)
Definition: OTCron.cpp:731
static bool __transact_market_offer
static int32_t GetCronMaxItemsPerNym()
Definition: OTCron.hpp:213
bool removeTransactionNumber(OTPseudonym &nym, const int64_t &transactionNumber, bool save=false)
Definition: Transactor.cpp:320
static EXPORT OTItem * CreateItemFromTransaction(const OTTransaction &theOwner, OTItem::itemType theType, const OTIdentifier *pDestinationAcctID=nullptr)
Definition: OTItem.cpp:1451
static EXPORT void Error(const char *szError)
Definition: OTLog.cpp:831
time64_t OTTimeGetCurrentTime()
Definition: Common.hpp:211
static int64_t GetMinMarketScale()
#define OT_ASSERT(x)
Definition: Assert.hpp:150
static EXPORT void vOutput(int32_t nVerbosity, const char *szOutput,...)
Definition: OTLog.cpp:768
static EXPORT OTAccount * LoadExistingAccount(const OTIdentifier &accountId, const OTIdentifier &serverId)
Definition: OTAccount.cpp:480
void opentxs::Notary::NotarizePayDividend ( OTPseudonym theNym,
OTAccount theSourceAccount,
OTTransaction tranIn,
OTTransaction tranOut,
bool &  bOutSuccess 
)

NotarizePayDividend

Phase 1: Only the signer on the currency contract (the issuer) can pay a dividend. He must pay the dividend in a currency of a DIFFERENT type. (Such as, a dollar dividend for shares of Pepsi.) So this transaction is a "dollar" transaction, using that example, and theAccount is a dollar account. But then how do we know those dollars are being paid to Pepsi shareholders? Because the asset type of the shares must be attached to the OTItem::payDividend within tranIn–and also so must the "dividend payout amount, per share" be included, for the same reason. This function gets the asset contract for the shares, and passes a functor to it, so that it can iterate through all the Pepsi asset accounts and form/send a payout voucher for each one (via the functor.) This function also verifies that theNym is both signer on the asset contract for Pepsi shares (the calling function has already verified that theNym is the signer on the dollar account.)

Phase 2: voting groups, hierarchical entities with agents, oversight, corporate asset accounts, etc.

Definition at line 1460 of file Notary.cpp.

1464 {
1465  const char* szFunc = "Notary::NotarizePayDividend";
1466 
1467  // The outgoing transaction is an "atPayDividend", that is, "a reply to the
1468  // 'pay dividend' request"
1469  tranOut.SetType(OTTransaction::atPayDividend);
1470 
1471  OTItem* pItem =
1472  nullptr; // This pointer and the following one, are 2 pointers,
1473  // as a vestige
1474  OTItem* pItemPayDividend =
1475  nullptr; // from the withdrawal code, which has two
1476  // forms: voucher and cash.
1477  OTItem* pBalanceItem = nullptr; // The balance agreement item, which must be
1478  // on any transaction.
1479  OTItem* pResponseItem = nullptr; // Server's response to pItem.
1480  OTItem* pResponseBalanceItem =
1481  nullptr; // Server's response to pBalanceItem.
1482 
1483  // The incoming transaction may be sent to inboxes and outboxes, and it
1484  // will probably be bundled in our reply to the user as well. Therefore,
1485  // let's grab it as a string.
1486  //
1487  OTString strInReferenceTo;
1488  OTString strBalanceItem;
1489 
1490  // Grab the actual server ID from this object, and use it as the server ID
1491  // here.
1492  //
1493  const OTIdentifier SERVER_ID(server_->m_strServerID), USER_ID(theNym),
1494  SOURCE_ACCT_ID(theSourceAccount), SERVER_USER_ID(server_->m_nymServer),
1495  PAYOUT_ASSET_ID(theSourceAccount.GetAssetTypeID()); // Ex: Pepsi shares,
1496  // Dollar dividend.
1497  // (PAYOUT_ASSET_ID
1498  // is Dollars.)
1499 
1500  const OTString strUserID(USER_ID), strAccountID(SOURCE_ACCT_ID),
1501  strAssetTypeID(PAYOUT_ASSET_ID);
1502  // Make sure the appropriate item is attached.
1503  //
1504  OTItem::itemType theReplyItemType = OTItem::error_state;
1505 
1506  pItemPayDividend = tranIn.GetItem(OTItem::payDividend);
1507 
1508  if (nullptr != pItemPayDividend) // found it.
1509  {
1510  pItem = pItemPayDividend;
1511  theReplyItemType = OTItem::atPayDividend;
1512  }
1513  // Server response item being added to server response transaction (tranOut)
1514  // (They're getting SOME sort of response item.)
1515  //
1516  pResponseItem =
1517  OTItem::CreateItemFromTransaction(tranOut, theReplyItemType);
1518  pResponseItem->SetStatus(OTItem::rejection); // the default.
1519  tranOut.AddItem(*pResponseItem); // the Transaction's destructor will
1520  // cleanup the item. It "owns" it now.
1521 
1522  pResponseBalanceItem =
1524  pResponseBalanceItem->SetStatus(OTItem::rejection); // the default.
1525  tranOut.AddItem(*pResponseBalanceItem); // the Transaction's destructor will
1526  // cleanup the item. It "owns" it
1527  // now.
1528  if (nullptr == pItem) {
1529  OTString strTemp(tranIn);
1531  0, "%s: Expected OTItem::payDividend in trans# %ld: \n\n%s\n\n",
1532  szFunc, tranIn.GetTransactionNum(),
1533  strTemp.Exists()
1534  ? strTemp.Get()
1535  : " (ERROR SERIALIZING TRANSACTION INTO A STRING) ");
1536  }
1537  // Below this point, we know that pItem is good, and that pItemPayDividend
1538  // is good,
1539  // and that pItem points to it. Therefore next, let's verify permissions:
1540  //
1541  // This permission has to do with ALL withdrawals from an account
1542  // (cash / voucher / dividends)
1543  else if (!NYM_IS_ALLOWED(strUserID.Get(),
1546  0, "%s: User %s cannot do this transaction (All withdrawals are "
1547  "disallowed in server.cfg, even for paying dividends with.)\n",
1548  szFunc, strUserID.Get());
1549  }
1550  // This permission has to do with paying dividends.
1551  //
1552  else if ((nullptr != pItemPayDividend) &&
1553  (false ==
1554  NYM_IS_ALLOWED(strUserID.Get(),
1556  OTLog::vOutput(0, "%s: User %s cannot do this transaction "
1557  "(payDividend is disallowed in server.cfg)\n",
1558  szFunc, strUserID.Get());
1559  }
1560  // Check for a balance agreement...
1561  //
1562  else if (nullptr ==
1563  (pBalanceItem = tranIn.GetItem(OTItem::balanceStatement))) {
1564  OTString strTemp(tranIn);
1565  OTLog::vOutput(0, "%s: Expected OTItem::balanceStatement, but not "
1566  "found in trans # %ld: \n\n%s\n\n",
1567  szFunc, tranIn.GetTransactionNum(),
1568  strTemp.Exists()
1569  ? strTemp.Get()
1570  : " (ERROR SERIALIZING TRANSACTION INTO A STRING) ");
1571  }
1572  else if (pItem->GetType() == OTItem::payDividend) // Superfluous by this
1573  // point. Artifact of
1574  // withdrawal code.
1575  {
1576  // The response item will contain a copy of the request item. So I save
1577  // it into a string
1578  // here so they can all grab a copy of it into their "in reference to"
1579  // fields.
1580  //
1581  pItem->SaveContractRaw(strInReferenceTo);
1582  pBalanceItem->SaveContractRaw(strBalanceItem);
1583 
1584  // Make sure the response items know which transaction # they're in
1585  // response to,
1586  // and have a copy of the original request-transaction.
1587  //
1588  pResponseItem->SetReferenceString(strInReferenceTo); // the response
1589  // item carries a
1590  // copy of what
1591  // it's responding
1592  // to.
1593  pResponseItem->SetReferenceToNum(
1594  pItem->GetTransactionNum()); // This response item is IN RESPONSE to
1595  // pItem and its Owner Transaction.
1596 
1597  pResponseBalanceItem->SetReferenceString(
1598  strBalanceItem); // the response item carries a copy of what it's
1599  // responding to.
1600  pResponseBalanceItem->SetReferenceToNum(
1601  pItem->GetTransactionNum()); // This response item is IN RESPONSE to
1602  // pItem and its Owner Transaction.
1603  const int64_t lTotalCostOfDividend = pItem->GetAmount();
1604  OTCheque theVoucherRequest;
1605  OTString strVoucherRequest,
1606  strItemNote; // When paying a dividend, you create a voucher request
1607  // (the same as in withdrawVoucher). It's just for
1608  // information
1609  pItem->GetAttachment(strVoucherRequest); // passing, since payDividend
1610  // needs a few bits of info,
1611  // and this is a convenient way
1612  // of passing it.
1613  pItem->GetNote(strItemNote);
1614  const bool bLoadContractFromString =
1615  theVoucherRequest.LoadContractFromString(strVoucherRequest);
1616 
1617  if (!bLoadContractFromString) {
1618  OTLog::vError("%s: ERROR loading dividend payout's voucher request "
1619  "from string:\n%s\n",
1620  szFunc, strVoucherRequest.Get());
1621  }
1622  else if (theVoucherRequest.GetAmount() <= 0) {
1623  OTLog::vError("%s: ERROR expected >0 'payout per share' as "
1624  "'amount' on request voucher:\n%s\n",
1625  szFunc, strVoucherRequest.Get());
1626  }
1627  else {
1628  // the request voucher (sent from client) contains the payout amount
1629  // per share.
1630  // Whereas pItem contains lTotalCostOfDividend, which is the total
1631  // cost (the
1632  // payout multiplied by number of shares.)
1633  //
1634  const int64_t lAmountPerShare =
1635  theVoucherRequest.GetAmount(); // already validated, just above.
1636  const OTIdentifier SHARES_ISSUER_ACCT_ID =
1637  theVoucherRequest.GetSenderAcctID();
1638 
1639  const OTString strSharesIssuerAcct(SHARES_ISSUER_ACCT_ID);
1640  // Get the asset contract for the shares type, stored in the voucher
1641  // request, inside pItem.
1642  // (Make sure it's NOT the same asset type as
1643  // theSourceAccount.)
1644  //
1645  const OTIdentifier SHARES_ASSET_ID = theVoucherRequest.GetAssetID();
1646  OTAssetContract* pSharesContract =
1647  server_->transactor_.getAssetContract(SHARES_ASSET_ID);
1648  OTAccount* pSharesIssuerAccount = nullptr;
1649  std::unique_ptr<OTAccount> theAcctAngel;
1650 
1651  if (nullptr != pSharesContract) {
1652  pSharesIssuerAccount = OTAccount::LoadExistingAccount(
1653  SHARES_ISSUER_ACCT_ID, SERVER_ID);
1654  theAcctAngel.reset(pSharesIssuerAccount);
1655  }
1656 
1657  if (nullptr == pSharesContract) {
1658  const OTString strSharesType(SHARES_ASSET_ID);
1659  OTLog::vError("%s: ERROR unable to find shares contract based "
1660  "on asset type ID: %s\n",
1661  szFunc, strSharesType.Get());
1662  }
1663  else if (!pSharesContract->IsShares()) {
1664  const OTString strSharesType(SHARES_ASSET_ID);
1665  OTLog::vError("%s: FAILURE: Asset contract is not "
1666  "shares-based. Asset type ID: %s\n",
1667  szFunc, strSharesType.Get());
1668  }
1669  else if (!pSharesContract->VerifySignature(theNym)) {
1670  const OTString strSharesType(SHARES_ASSET_ID);
1671  OTLog::vError("%s: ERROR unable to verify signature for Nym "
1672  "(%s) on shares contract "
1673  "with asset ID: %s\n",
1674  szFunc, strUserID.Get(), strSharesType.Get());
1675  }
1676  else if (nullptr == pSharesIssuerAccount) {
1677  OTLog::vError(
1678  "%s: ERROR unable to find issuer account for shares: %s\n",
1679  szFunc, strSharesIssuerAcct.Get());
1680  }
1681  else if (PAYOUT_ASSET_ID ==
1682  SHARES_ASSET_ID) // these can't be the same
1683  {
1684  const OTString strSharesType(PAYOUT_ASSET_ID);
1685  OTLog::vError("%s: ERROR dividend payout attempted, using "
1686  "shares asset type as payout type also. "
1687  "(It's logically impossible for it to payout to "
1688  "itself, using "
1689  "ITSELF as the asset type for the payout): %s\n",
1690  szFunc, strSharesType.Get());
1691  }
1692  else if (false ==
1693  pSharesIssuerAccount->VerifyAccount(
1694  server_->m_nymServer)) {
1695  const OTString strIssuerAcctID(SHARES_ISSUER_ACCT_ID);
1696  OTLog::vError(
1697  "%s: ERROR failed trying to verify issuer account: %s\n",
1698  szFunc, strIssuerAcctID.Get());
1699  }
1700  else if (!pSharesIssuerAccount->VerifyOwner(theNym)) {
1701  const OTString strIssuerAcctID(SHARES_ISSUER_ACCT_ID);
1703  0, "%s: ERROR verifying signer's ownership of shares "
1704  "issuer account (%s), "
1705  "while trying to pay dividend from source account: %s\n",
1706  szFunc, strIssuerAcctID.Get(), strAccountID.Get());
1707  }
1708  // Make sure the share issuer's account balance (number of shares
1709  // issued * (-1)),
1710  // when multiplied by the dividend "amount payout per share", equals
1711  // the "total cost of dividend"
1712  // as expected based on the value from pItem->GetAmount.
1713  //
1714  //
1715  else if ((pSharesIssuerAccount->GetBalance() * (-1) *
1716  lAmountPerShare) != lTotalCostOfDividend) {
1717  const OTString strIssuerAcctID(SHARES_ISSUER_ACCT_ID);
1718  OTLog::vOutput(0, "%s: ERROR: total payout of dividend as "
1719  "calculated (%ld) doesn't match client's "
1720  "request (%ld) for source acct: %s\n",
1721  szFunc, (pSharesIssuerAccount->GetBalance() *
1722  (-1) * lAmountPerShare),
1723  lTotalCostOfDividend, strAccountID.Get());
1724  }
1725  else if (theSourceAccount.GetBalance() < lTotalCostOfDividend) {
1726  const OTString strIssuerAcctID(SHARES_ISSUER_ACCT_ID);
1727  OTLog::vOutput(0, "%s: FAILURE: not enough funds (%ld) to "
1728  "cover total dividend payout (%ld) for "
1729  "source acct: %s\n",
1730  szFunc, theSourceAccount.GetBalance(),
1731  lTotalCostOfDividend, strAccountID.Get());
1732  }
1733  else {
1734  // Remove all the funds at once (so the balance agreement
1735  // matches up.)
1736  // Then, iterate through the asset accounts and use a functor to
1737  // send a voucher to each one.
1738  // (Or back to the issuer, for any that fail.)
1739 
1740  // UPDATE: unfortunately the balance agreement will be a lie
1741  // unless the complete amount is removed.
1742  // Therefore, failures must be sent back to the issuer as
1743  // individual receipts, containing the vouchers
1744  // for any failures, so he can have a record of them, and so he
1745  // can recover the funds.
1746  std::unique_ptr<OTLedger> pInbox(
1747  theSourceAccount.LoadInbox(server_->m_nymServer));
1748  std::unique_ptr<OTLedger> pOutbox(
1749  theSourceAccount.LoadOutbox(server_->m_nymServer));
1750  // contains the server's funds to back vouchers of a specific
1751  // asset type.
1752  std::shared_ptr<OTAccount> pVoucherReserveAcct;
1753  // OTAccount * pVoucherReserveAcct =
1754  // nullptr;
1755  //
1756  // If the ID on the "from" account that was passed in, does
1757  // not match the "Acct From" ID on this transaction item...
1758  //
1759  if (SOURCE_ACCT_ID !=
1760  pItem->GetPurportedAccountID()) { // TODO see if this is
1761  // already verified by the
1762  // caller function and if
1763  // so, remove.
1764  // (I believe the item would have entirely failed to load,
1765  // if the account ID, and
1766  // other IDs, hadn't matched up with the transaction when we
1767  // loaded it.)
1768  //
1769  OTLog::vOutput(0, "%s: Error: Account ID does not match "
1770  "account ID on the 'pay dividend' "
1771  "item.\n",
1772  szFunc);
1773  }
1774  else if (nullptr == pInbox) {
1775  OTLog::vError("%s: Error loading or verifying inbox.\n",
1776  szFunc);
1777  }
1778  else if (nullptr == pOutbox) {
1779  OTLog::vError("%s: Error loading or verifying outbox.\n",
1780  szFunc);
1781  }
1782  // The server will already have a special account for issuing
1783  // vouchers. Actually, a list of them --
1784  // one for each asset type. Since this is the normal way of
1785  // doing business, transactor_.getVoucherAccount() will
1786  // just create it if it doesn't already exist, and then return
1787  // the pointer. Therefore, a failure here
1788  // is a catastrophic failure! Should never fail.
1789  //
1790  else if ((pVoucherReserveAcct =
1791  server_->transactor_.getVoucherAccount(
1792  PAYOUT_ASSET_ID)) && // If
1793  // transactor_.getVoucherAccount
1794  // returns a good pointer...
1795  pVoucherReserveAcct->VerifyAccount(
1796  server_->m_nymServer)) // ...and if it points to an
1797  // acct
1798  // that verifies with the server's
1799  // nym...
1800  {
1801  OTAccount& theVoucherReserveAcct = (*pVoucherReserveAcct);
1802  const OTIdentifier VOUCHER_ACCOUNT_ID(
1803  theVoucherReserveAcct);
1804 
1805  // This amount must be the total amount based on the amount
1806  // issued.
1807  // For example if 1000 shares of Pepsi were issued, and the
1808  // dividend is $2 per share,
1809  // then loading the issuer's account will show a balance of
1810  // -1000, and I must have
1811  // $2000 in my source account if I am going to pay this
1812  // dividend.
1813  //
1814  // This $2000 is entirely removed from my account at once,
1815  // and the below balance agreement
1816  // must be for $2000. The vouchers are sent to the owners of
1817  // each account, in amounts
1818  // proportionate to the number of shares in the account. For
1819  // any voucher that fails to be
1820  // sent (for whatever reason) it is sent back to theNym
1821  // instead.
1822  //
1823  if (!(pBalanceItem->VerifyBalanceStatement(
1824  lTotalCostOfDividend * (-1), // My account's
1825  // balance will go
1826  // down by this much.
1827  theNym, *pInbox, *pOutbox, theSourceAccount,
1828  tranIn))) {
1829  OTLog::vOutput(0, "%s: ERROR verifying balance "
1830  "statement while trying to pay "
1831  "dividend. Source Acct ID: %s\n",
1832  szFunc, strAccountID.Get());
1833  }
1834  else // successfully verified the balance agreement.
1835  {
1836  pResponseBalanceItem->SetStatus(
1837  OTItem::acknowledgement); // the transaction
1838  // agreement was
1839  // successful.
1840  // IF we successfully created the voucher, AND the
1841  // voucher amount is greater than 0,
1842  // AND debited the user's account,
1843  // AND credited the server's voucher account,
1844  //
1845  // THEN save the accounts and pay the dividend out to
1846  // the shareholders.
1847  //
1848  if ((lTotalCostOfDividend > 0) &&
1849  theSourceAccount.Debit(
1850  lTotalCostOfDividend) // todo: failsafe: update
1851  // this code in case of
1852  // problems in this
1853  // sensitive area. need
1854  // better funds transfer
1855  // code.
1856  ) {
1857  const OTString strVoucherAcctID(VOUCHER_ACCOUNT_ID);
1858 
1859  if (false ==
1860  pVoucherReserveAcct->Credit(
1861  lTotalCostOfDividend)) // theVoucherRequest.GetAmount()))
1862  {
1863  OTLog::vError("%s: Failed crediting %ld units "
1864  "to voucher reserve account: "
1865  "%s\n",
1866  szFunc, lTotalCostOfDividend,
1867  strVoucherAcctID.Get());
1868 
1869  // Since pVoucherReserveAcct->Credit failed, we
1870  // have to return
1871  // the funds from theSourceAccount.Debit (Credit
1872  // them back.)
1873  //
1874  if (false ==
1875  theSourceAccount.Credit(
1876  lTotalCostOfDividend))
1877  OTLog::vError(
1878  "%s: Failed crediting back the user "
1879  "account, after taking his funds "
1880  "and failing to credit them to the "
1881  "voucher reserve account.\n",
1882  szFunc);
1883  }
1884  else // By this point, we have taken the full
1885  // funds
1886  // and moved them to the voucher
1887  { // reserve account. So now, let's iterate all the
1888  // accounts for that share type,
1889  // and send a voucher to the owner of each one,
1890  // to payout his dividend.
1891 
1892  // todo: determine whether I need to attach
1893  // anything here at all...
1894  pResponseItem->SetStatus(
1896 
1897  bOutSuccess = true; // The paying of the
1898  // dividends was successful.
1899  //
1900  //
1901  // SAVE THE ACCOUNTS WITH THE NEW BALANCES
1902  // (FUNDS ARE MOVED)
1903  //
1904  // At this point, we save the accounts, so that
1905  // the funds transfer is solid before
1906  // we start mailing vouchers out to people.
1907 
1908  // Release any signatures that were there before
1909  // (They won't
1910  // verify anymore anyway, since the content has
1911  // changed.)
1912  theSourceAccount.ReleaseSignatures();
1913  theSourceAccount.SignContract(
1914  server_->m_nymServer); // Sign
1915  theSourceAccount.SaveContract(); // Save
1916  theSourceAccount.SaveAccount(); // Save to file
1917 
1918  // We also need to save the Voucher cash reserve
1919  // account.
1920  // (Any issued voucher cheque is automatically
1921  // backed by this reserve account.
1922  // If a cheque is deposited, the funds come back
1923  // out of this account. If the
1924  // cheque expires, then after the expiry period,
1925  // if it remains in the account,
1926  // it is now the property of the transaction
1927  // server.)
1928  pVoucherReserveAcct->ReleaseSignatures();
1929  pVoucherReserveAcct->SignContract(
1930  server_->m_nymServer);
1931  pVoucherReserveAcct->SaveContract();
1932  pVoucherReserveAcct->SaveAccount();
1933 
1934  //
1935  // PAY THE SHAREHOLDERS
1936  //
1937  // Here's where we actually loop through the
1938  // asset accounts for the share type,
1939  // and send a voucher to the owner of each one.
1940  //
1941  // This way, the actionPayDividend won't
1942  // possibly load these accounts twice.
1943  // We make them available here this way.
1944  //
1945  mapOfAccounts theAccounts;
1946  theAccounts.insert(
1947  std::pair<std::string, OTAccount*>(
1948  strAccountID.Get(), &theSourceAccount));
1949  theAccounts.insert(
1950  std::pair<std::string, OTAccount*>(
1951  strSharesIssuerAcct.Get(),
1952  pSharesIssuerAccount));
1953  theAccounts.insert(
1954  std::pair<std::string, OTAccount*>(
1955  strVoucherAcctID.Get(),
1956  &theVoucherReserveAcct));
1957 
1958  PayDividendVisitor actionPayDividend(
1959  SERVER_ID, USER_ID, PAYOUT_ASSET_ID,
1960  VOUCHER_ACCOUNT_ID,
1961  strInReferenceTo, // Memo for each voucher
1962  // (containing original
1963  // payout request pItem)
1964  *server_, lAmountPerShare, &theAccounts);
1965 
1966  // Loops through all the accounts for a given
1967  // asset type (PAYOUT_ASSET_ID), and triggers
1968  // actionPayDividend for each one. This sends
1969  // the owner nym for each, a voucher drawn on
1970  // VOUCHER_ACCOUNT_ID. (In the amount of
1971  // lAmountPerShare * number of shares in
1972  // account.)
1973  //
1974  const bool bForEachAcct =
1975  pSharesContract->VisitAccountRecords(
1976  actionPayDividend); // <================
1977  // pay all the
1978  // dividends here.
1979 
1980  // TODO: Since the above line of code loops
1981  // through all the accounts and loads them
1982  // up, transforms them, and saves them again, we
1983  // cannot use our own loaded accounts below
1984  // this point. (They could overwrite
1985  // themselves.) theSourceAccount especially, was
1986  // passed in
1987  // from above -- so how can we possible warn the
1988  // caller than he cannot save this account
1989  // without
1990  // overwriting work we have done in this
1991  // function?
1992  //
1993  // Aside from any more elegant solution, the
1994  // only way to make it work in this case would
1995  // be to
1996  // make a map or list of all the accounts that
1997  // are already loaded in memory (such as
1998  // theSourceAccount)
1999  // and PASS THEM IN to the above
2000  // VisitAccountRecords call. This way it would
2001  // have the option to use
2002  // the "already loaded" versions, where
2003  // appropriate, instead of loading them twice.
2004  // (As it is,
2005  // theSourceAccount is not used below this
2006  // point, though we couldn't preven the caller
2007  // from using it.)
2008  //
2009  // Therefore we need to have some central system
2010  // where accounts can be loaded, locked, saved,
2011  // etc.
2012  // So we cannot ever overwrite ourselves BY
2013  // DESIGN. (And the same for other data types as
2014  // well, like Nyms.)
2015  // Todo.
2016  //
2017  if (!bForEachAcct) // todo failsafe. Handle this
2018  // better.
2019  {
2020  OTLog::vError(
2021  "%s: ERROR: After moving funds for "
2022  "dividend payment, there was some "
2023  "error when sending out the vouchers "
2024  "to the payout recipients.\n",
2025  szFunc);
2026  }
2027  //
2028  // REFUND ANY LEFTOVERS
2029  //
2030  const int64_t lLeftovers =
2031  lTotalCostOfDividend -
2032  (actionPayDividend.GetAmountPaidOut() +
2033  actionPayDividend.GetAmountReturned());
2034  if (lLeftovers > 0) {
2035  // Of the total amount removed from the
2036  // sender's account, and after paying all
2037  // dividends,
2038  // there was a leftover amount that wasn't
2039  // paid to anybody. Therefore, we should pay
2040  // it back
2041  // to the sender himself, now.
2042  //
2044  0, "%s: After dividend payout, with "
2045  "%ld units removed initially, "
2046  "there were %ld units remaining. "
2047  "(Returning them to sender...)\n",
2048  szFunc, lTotalCostOfDividend,
2049  lLeftovers);
2050  OTCheque theVoucher(SERVER_ID,
2051  PAYOUT_ASSET_ID);
2052 
2053  // 10 minutes == 600 Seconds
2054  // 1 hour == 3600 Seconds
2055  // 1 day == 86400 Seconds
2056  // 30 days == 2592000 Seconds
2057  // 3 months == 7776000 Seconds
2058  // 6 months == 15552000 Seconds
2059 
2060  const time64_t VALID_FROM =
2061  OTTimeGetCurrentTime(); // This time is
2062  // set to TODAY
2063  // NOW
2064  const time64_t VALID_TO =
2066  VALID_FROM,
2068  OT_TIME_SIX_MONTHS_IN_SECONDS)); // This time occurs in 180 days (6 months). Todo hardcoding.
2069 
2070  int64_t lNewTransactionNumber = 0;
2071  const bool bGotNextTransNum =
2072  server_->transactor_
2074  server_->m_nymServer,
2075  lNewTransactionNumber); // bStoreTheNumber
2076  // defaults to
2077  // true. We save
2078  // the
2079  // transaction
2080  // number on the server Nym (normally we'd
2081  // discard it) because
2082  // when the cheque is deposited, the server
2083  // nym, as the owner of
2084  // the voucher account, needs to verify the
2085  // transaction # on the
2086  // cheque (to prevent double-spending of
2087  // cheques.)
2088  if (bGotNextTransNum) {
2089  const OTIdentifier SERVER_NYM_ID(
2090  server_->m_nymServer);
2091  const bool bIssueVoucher =
2092  theVoucher.IssueCheque(
2093  lLeftovers, // The amount of the
2094  // cheque.
2095  lNewTransactionNumber, // Requiring
2096  // a
2097  // transaction
2098  // number
2099  // prevents
2100  // double-spending
2101  // of
2102  // cheques.
2103  VALID_FROM, // The expiration
2104  // date
2105  // (valid from/to dates)
2106  // of the cheque
2107  VALID_TO, // Vouchers are
2108  // automatically starting
2109  // today and lasting 6
2110  // months.
2111  VOUCHER_ACCOUNT_ID, // The asset
2112  // account the
2113  // cheque is
2114  // drawn on.
2115  SERVER_NYM_ID, // User ID of the
2116  // sender (in this
2117  // case the server
2118  // nym.)
2119  strInReferenceTo, // Optional
2120  // memo
2121  // field. Includes
2122  // item note and
2123  // request memo.
2124  &USER_ID);
2125 
2126  // All account crediting / debiting
2127  // happens in the caller, in OTServer.
2128  // (AND it happens only ONCE, to
2129  // cover ALL vouchers.)
2130  // Then in here, the voucher either gets
2131  // send to the recipient, or if error,
2132  // sent back home to
2133  // the issuer Nym. (ALL the funds are
2134  // removed, then the vouchers are sent
2135  // one way or the other.)
2136  // Any returned vouchers, obviously
2137  // serve to notify the dividend payer of
2138  // where the errors were
2139  // (as well as give him the opportunity
2140  // to get his money back.)
2141  //
2142  bool bSent = false;
2143  if (bIssueVoucher) {
2144  theVoucher.SetAsVoucher(
2145  SERVER_NYM_ID,
2146  VOUCHER_ACCOUNT_ID); // All this
2147  // does is
2148  // set the
2149  // voucher's
2150  // internal
2151  // contract
2152  // string
2153  theVoucher.SignContract(
2154  server_->m_nymServer); // to
2155  // "VOUCHER"
2156  // instead of
2157  // "CHEQUE".
2158  theVoucher.SaveContract();
2159 
2160  // Send the voucher to the payments
2161  // inbox of the recipient.
2162  //
2163  const OTString strVoucher(
2164  theVoucher);
2165  OTPayment thePayment(strVoucher);
2166 
2167  // calls DropMessageToNymbox
2168  bSent =
2169  server_->SendInstrumentToNym(
2170  SERVER_ID,
2171  SERVER_NYM_ID, // sender nym
2172  USER_ID, // recipient nym
2173  // (returning to
2174  // original sender.)
2175  nullptr, &thePayment,
2176  "payDividend"); // todo:
2177  // hardcoding.
2178  }
2179  // If we didn't send it, then we need to
2180  // return the funds to where they came
2181  // from.
2182  //
2183  if (!bSent) {
2184  const OTString strPayoutAssetID(
2185  PAYOUT_ASSET_ID),
2186  strSenderUserID(USER_ID);
2187  OTLog::vError(
2188  "%s: ERROR failed issuing "
2189  "voucher (to return leftovers "
2190  "back to "
2191  "the dividend payout "
2192  "initiator.) WAS TRYING TO PAY "
2193  "%ld of asset type %s to Nym "
2194  "%s.\n",
2195  szFunc, lLeftovers,
2196  strPayoutAssetID.Get(),
2197  strSenderUserID.Get());
2198  } // if !bSent
2199  }
2200  else // !bGotNextTransNum
2201  {
2202  const OTString strPayoutAssetID(
2203  PAYOUT_ASSET_ID),
2204  strRecipientUserID(USER_ID);
2205  OTLog::vError(
2206  "%s: ERROR!! Failed issuing next "
2207  "transaction "
2208  "number while trying to send a "
2209  "voucher (while returning leftover "
2210  "funds, after paying dividends.) "
2211  "WAS TRYING TO PAY %ld of asset "
2212  "type %s to Nym %s.\n",
2213  szFunc, lLeftovers,
2214  strPayoutAssetID.Get(),
2215  strRecipientUserID.Get());
2216  }
2217  }
2218  } // else
2219  }
2220  // else{} // TODO log that there was a problem with the
2221  // amount
2222 
2223  } // voucher request loaded successfully from string
2224  } // server_->transactor_.getVoucherAccount()
2225  else {
2226  OTLog::vError(
2227  "%s: server_->transactor_.getVoucherAccount() failed. "
2228  "Asset Type:\n%s\n",
2229  szFunc, strAssetTypeID.Get());
2230  }
2231  }
2232  }
2233  }
2234  else {
2235  OTString strTemp(tranIn);
2237  0, "%s: Expected OTItem::payDividend in trans# %ld: \n\n%s\n\n",
2238  szFunc, tranIn.GetTransactionNum(),
2239  strTemp.Exists() ? strTemp.Get()
2240  : " (ERROR LOADING TRANSACTION INTO STRING) ");
2241  }
2242  // sign the response item before sending it back (it's already been added to
2243  // the transaction above)
2244  // Now, whether it was rejection or acknowledgement, it is set properly and
2245  // it is signed, and it
2246  // is owned by the transaction, who will take it from here.
2247  pResponseItem->SignContract(server_->m_nymServer);
2248  pResponseItem->SaveContract(); // the signing was of no effect because I
2249  // forgot to save.
2250 
2251  pResponseBalanceItem->SignContract(server_->m_nymServer);
2252  pResponseBalanceItem->SaveContract();
2253 }
static EXPORT void vError(const char *szError,...)
Definition: OTLog.cpp:800
bool issueNextTransactionNumber(OTPseudonym &nym, int64_t &txNumber, bool storeNumber=true)
Definition: Transactor.cpp:211
time64_t OTTimeAddTimeInterval(time64_t lhs, int64_t rhs)
Definition: Common.hpp:238
#define NYM_IS_ALLOWED(SZ_NYM_ID, BOOL_VAR_NAME)
Definition: Macros.hpp:146
int64_t time64_t
Definition: Common.hpp:209
std::shared_ptr< OTAccount > getVoucherAccount(const OTIdentifier &assetTypeId)
Definition: Transactor.cpp:536
#define OT_TIME_SIX_MONTHS_IN_SECONDS
Definition: Common.hpp:170
static EXPORT OTItem * CreateItemFromTransaction(const OTTransaction &theOwner, OTItem::itemType theType, const OTIdentifier *pDestinationAcctID=nullptr)
Definition: OTItem.cpp:1451
time64_t OTTimeGetCurrentTime()
Definition: Common.hpp:211
std::map< std::string, OTAccount * > mapOfAccounts
Definition: OTWallet.hpp:157
OTAssetContract * getAssetContract(const OTIdentifier &id)
Definition: Transactor.cpp:394
int64_t OTTimeGetSecondsFromTime(time64_t time)
Definition: Common.hpp:230
static bool __transact_pay_dividend
static EXPORT void vOutput(int32_t nVerbosity, const char *szOutput,...)
Definition: OTLog.cpp:768
static EXPORT OTAccount * LoadExistingAccount(const OTIdentifier &accountId, const OTIdentifier &serverId)
Definition: OTAccount.cpp:480
void opentxs::Notary::NotarizePaymentPlan ( OTPseudonym theNym,
OTAccount theDepositorAccount,
OTTransaction tranIn,
OTTransaction tranOut,
bool &  bOutSuccess 
)

1) The Merchant generates the payment plan, adds transaction numbers, and signs. (All done via ProposePaymentPlan) 2) Then the Customer uses ConfirmPaymentPlan to add his own numbers and sign. 3) Then the Customer must activate the payment plan. (Using a transaction with the same number as the plan.)

Definition at line 4065 of file Notary.cpp.

4069 {
4070  // The outgoing transaction is an "atPaymentPlan", that is, "a reply to the
4071  // paymentPlan request"
4072  tranOut.SetType(OTTransaction::atPaymentPlan);
4073 
4074  OTItem* pItem = nullptr;
4075  OTItem* pBalanceItem = nullptr;
4076  OTItem* pResponseItem = nullptr;
4077  OTItem* pResponseBalanceItem = nullptr;
4078 
4079  // The incoming transaction may be sent to inboxes and outboxes, and it
4080  // will definitely be bundled in our reply to the user as well. Therefore,
4081  // let's grab it as a string.
4082  OTString strInReferenceTo;
4083  OTString strBalanceItem;
4084 
4085  // Grab the actual server ID from this object, and use it as the server ID
4086  // here.
4087  const OTIdentifier SERVER_ID(server_->m_strServerID),
4088  DEPOSITOR_USER_ID(theNym), SERVER_USER_ID(server_->m_nymServer),
4089  DEPOSITOR_ACCT_ID(theDepositorAccount), USER_ID(theNym);
4090 
4091  const OTString strUserID(USER_ID);
4092  pItem = tranIn.GetItem(OTItem::paymentPlan);
4093  pBalanceItem = tranIn.GetItem(OTItem::transactionStatement);
4094  pResponseItem =
4096  pResponseItem->SetStatus(OTItem::rejection); // the default.
4097  tranOut.AddItem(*pResponseItem); // the Transaction's destructor will
4098  // cleanup the item. It "owns" it now.
4099  pResponseBalanceItem = OTItem::CreateItemFromTransaction(
4101  pResponseBalanceItem->SetStatus(OTItem::rejection); // the default.
4102  tranOut.AddItem(*pResponseBalanceItem); // the Transaction's destructor will
4103  // cleanup the item. It "owns" it
4104  // now.
4105  if ((nullptr != pItem) &&
4106  (false == NYM_IS_ALLOWED(strUserID.Get(),
4108  OTLog::vOutput(0, "%s: User %s cannot do this transaction (All payment "
4109  "plans are disallowed in server.cfg)\n",
4110  __FUNCTION__, strUserID.Get());
4111  }
4112  // For now, there should only be one of these paymentPlan items inside the
4113  // transaction.
4114  // So we treat it that way... I either get it successfully or not.
4115  else if ((nullptr == pItem) || (nullptr == pBalanceItem)) {
4116  OTLog::vError("%s: Error, expected OTItem::paymentPlan and "
4117  "OTItem::transactionStatement.\n",
4118  __FUNCTION__);
4119  }
4120  else {
4121  if (DEPOSITOR_ACCT_ID != pItem->GetPurportedAccountID()) {
4122  OTLog::vOutput(0, "%s: Error: Source account ID on the transaction "
4123  "does not match sender's account ID on the "
4124  "transaction item.\n",
4125  __FUNCTION__);
4126  }
4127  else if (false ==
4128  pBalanceItem->VerifyTransactionStatement(
4129  theNym, tranIn)) // bIsRealTransaction=true
4130  {
4131  OTLog::vOutput(0, "%s: Failed verifying transaction statement.\n",
4132  __FUNCTION__);
4133  }
4134  else {
4135  pResponseBalanceItem->SetStatus(
4136  OTItem::acknowledgement); // the transaction agreement was
4137  // successful.
4138 
4139  // The response item will contain a copy of the request item. So I
4140  // save it into a string
4141  // here so it can be saved into the "in reference to" field.
4142  pItem->SaveContractRaw(strInReferenceTo);
4143  pBalanceItem->SaveContractRaw(strBalanceItem);
4144 
4145  // Server response item being added to server response transaction
4146  // (tranOut)
4147  // They're getting SOME sort of response item.
4148 
4149  pResponseItem->SetReferenceString(
4150  strInReferenceTo); // the response item carries a copy of what
4151  // it's responding to.
4152  pResponseItem->SetReferenceToNum(
4153  pItem->GetTransactionNum()); // This response item is IN
4154  // RESPONSE to pItem and its Owner
4155  // Transaction.
4156 
4157  pResponseBalanceItem->SetReferenceString(
4158  strBalanceItem); // the response item carries a copy of what
4159  // it's responding to.
4160  pResponseBalanceItem->SetReferenceToNum(
4161  pItem->GetTransactionNum()); // This response item is IN
4162  // RESPONSE to pItem and its Owner
4163  // Transaction.
4164 
4165  // Also load up the Payment Plan from inside the transaction item.
4166  OTString strPaymentPlan;
4167  pItem->GetAttachment(strPaymentPlan);
4168  OTPaymentPlan* pPlan = new OTPaymentPlan();
4169  OT_ASSERT(nullptr != pPlan);
4170 
4171  // If we failed to load the plan...
4172  if ((false == pPlan->LoadContractFromString(strPaymentPlan))) {
4173  OTLog::vError(
4174  "%s: ERROR loading payment plan from string:\n%s\n",
4175  __FUNCTION__, strPaymentPlan.Get());
4176  }
4177  else if (pPlan->GetServerID() != SERVER_ID) {
4178  OTLog::vOutput(0, "%s: ERROR bad server ID on payment plan.\n",
4179  __FUNCTION__);
4180  }
4181  else if (pPlan->GetAssetID() !=
4182  theDepositorAccount.GetAssetTypeID()) {
4183  const OTString strAssetID1(pPlan->GetAssetID()),
4184  strAssetID2(theDepositorAccount.GetAssetTypeID());
4185  OTLog::vOutput(0, "%s: ERROR wrong Asset Type ID (%s) on "
4186  "payment plan. Expected: %s\n",
4187  __FUNCTION__, strAssetID1.Get(),
4188  strAssetID2.Get());
4189  }
4190  else {
4191  // CANCELLING? OR ACTIVATING?
4192  // If he is cancelling the payment plan (from his outpayments
4193  // box, before it's even had a chance
4194  // to be activated by the sender) then the recipient (merchant)
4195  // will be the depositor. Otherwise,
4196  // if he is activating the payment plan (from his payments
4197  // inbox) then the sender (customer) will
4198  // be the depositor.
4199 
4200  OTIdentifier theCancelerNymID;
4201  const bool bCancelling =
4202  (pPlan->IsCanceled() &&
4203  pPlan->GetCancelerID(theCancelerNymID));
4204  const int64_t lExpectedNum =
4205  bCancelling ? 0 : pItem->GetTransactionNum();
4206  const int64_t lFoundNum = pPlan->GetTransactionNum();
4207  const OTIdentifier& FOUND_USER_ID =
4208  bCancelling ? pPlan->GetRecipientUserID()
4209  : pPlan->GetSenderUserID();
4210  const OTIdentifier& FOUND_ACCT_ID =
4211  bCancelling ? pPlan->GetRecipientAcctID()
4212  : pPlan->GetSenderAcctID();
4213  const int64_t lFoundOpeningNum =
4214  pPlan->GetOpeningNumber(FOUND_USER_ID);
4215  const int64_t lFoundClosingNum =
4216  pPlan->GetClosingNumber(FOUND_ACCT_ID);
4217  if (lFoundNum != lExpectedNum) {
4218  OTLog::vOutput(0, "%s: ERROR bad main transaction number "
4219  "while %s payment plan (%ld). Expected "
4220  "based on transaction: %ld\n",
4221  __FUNCTION__,
4222  bCancelling ? "cancelling" : "activating",
4223  lFoundNum, lExpectedNum);
4224  }
4225  if (lFoundOpeningNum != pItem->GetTransactionNum()) {
4227  0, "%s: ERROR bad transaction number while %s payment "
4228  "plan (%ld). Expected based on transaction: %ld\n",
4229  __FUNCTION__, bCancelling ? "cancelling" : "activating",
4230  lFoundOpeningNum, pItem->GetTransactionNum());
4231  }
4232  else if (FOUND_USER_ID != DEPOSITOR_USER_ID) {
4233  const OTString strIDExpected(FOUND_USER_ID),
4234  strIDDepositor(DEPOSITOR_USER_ID);
4236  0, "%s: ERROR wrong user ID while %s payment plan. "
4237  "Depositor: %s Found on plan: %s\n",
4238  __FUNCTION__, bCancelling ? "cancelling" : "activating",
4239  strIDDepositor.Get(), strIDExpected.Get());
4240  }
4241  else if (bCancelling &&
4242  (DEPOSITOR_USER_ID != theCancelerNymID)) {
4243  const OTString strIDExpected(DEPOSITOR_USER_ID),
4244  strIDDepositor(theCancelerNymID);
4245  OTLog::vOutput(0, "%s: ERROR wrong canceler Nym ID while "
4246  "canceling payment plan. Depositor: %s "
4247  "Canceler: %s\n",
4248  __FUNCTION__, strIDExpected.Get(),
4249  strIDDepositor.Get());
4250  }
4251  else if (FOUND_ACCT_ID != DEPOSITOR_ACCT_ID) {
4252  const OTString strAcctID1(FOUND_ACCT_ID),
4253  strAcctID2(DEPOSITOR_ACCT_ID);
4254  OTLog::vOutput(0, "%s: ERROR wrong Acct ID (%s) while %s "
4255  "payment plan. Expected: %s\n",
4256  __FUNCTION__, strAcctID1.Get(),
4257  bCancelling ? "cancelling" : "activating",
4258  strAcctID2.Get());
4259  }
4260  // If we're activating the plan (versus cancelling) then the
4261  // transaction number opens
4262  // the payment plan, but there must also be a closing number for
4263  // closing it.
4264  else if (!bCancelling && // If activating and:
4265  ((pPlan->GetCountClosingNumbers() <
4266  1) || // ...if there aren't enough closing numbers...
4267  !server_->transactor_.verifyTransactionNumber(
4268  theNym, lFoundClosingNum))) // ...or the official
4269  // closing # isn't
4270  // available for use
4271  // on theNym.
4272  { // We don't check opening number here, since
4273  // NotarizeTransaction already did.
4274  OTLog::vOutput(0, "%s: ERROR: the Closing number %ld "
4275  "wasn't available for use while "
4276  "activating a payment plan.\n",
4277  __FUNCTION__, lFoundClosingNum);
4278  }
4279  else if (bCancelling && // If cancelling and:
4280  ((pPlan->GetRecipientCountClosingNumbers() < 2) ||
4281  !server_->transactor_.verifyTransactionNumber(
4282  theNym, lFoundClosingNum))) {
4283  OTLog::vOutput(0, "%s: ERROR: the Closing number wasn't "
4284  "available for use while cancelling a "
4285  "payment plan.\n",
4286  __FUNCTION__);
4287  }
4288  else // The plan is good (so far.)
4289  {
4290  // The RECIPIENT_ACCT_ID is the ID on the "To" Account.
4291  // (When doing a transfer, normally 2nd acct is the Payee.)
4292  const OTIdentifier RECIPIENT_ACCT_ID(
4293  pPlan->GetRecipientAcctID()),
4294  RECIPIENT_USER_ID(pPlan->GetRecipientUserID());
4295 
4296  bool bRecipientNymIsServerNym =
4297  ((RECIPIENT_USER_ID == SERVER_USER_ID) ? true : false);
4298  bool bUsersAreSameNym =
4299  ((DEPOSITOR_USER_ID == RECIPIENT_USER_ID) ? true
4300  : false);
4301 
4302  OTPseudonym theRecipientNym; // We'll probably use this, but
4303  // maybe not. So I use a
4304  // pointer that will maybe
4305  // point here.
4306  OTPseudonym* pRecipientNym = nullptr; // Here's the pointer.
4307  // (Logic explained
4308  // directly below.)
4309  // Set pRecipientNym to point to the right one so we can use
4310  // it below. (Do NOT use theRecipientNym,
4311  // since it won't always point to that one.)
4312 
4313  bool bFoundRecipientNym = false;
4314 
4315  // Find out if Recipient Nym is also the Server Nym...
4316  if (bRecipientNymIsServerNym) {
4317  // If the Recipient Nym is the server, then just point
4318  // to that.
4319  pRecipientNym = &server_->m_nymServer;
4320  bFoundRecipientNym = true;
4321 
4322  // (No need to verify Nym here since already done in
4323  // this case.)
4324  }
4325  else if (bUsersAreSameNym) // Else if the participants are
4326  // the same Nym, point to the
4327  // one we already loaded.
4328  {
4329  pRecipientNym = &theNym;
4330  bFoundRecipientNym = true;
4331 
4332  // (No need to verify Nym here since already done in
4333  // this case, before we even got here.)
4334  }
4335  else // Otherwise load the Recipient Nym from Disk and
4336  // point to that.
4337  {
4338  theRecipientNym.SetIdentifier(RECIPIENT_USER_ID);
4339 
4340  bool bLoadedNym =
4341  theRecipientNym.LoadPublicKey(); // Old style
4342  // (deprecated.)
4343  // NOTE:
4344  // LoadCredentials
4345  // is already
4346  // called inside
4347  // LoadPublicKey,
4348  // at the top, but
4349  // eventually we'll
4350  // be calling it
4351  // here directly,
4352  // once
4353  // LoadPublicKey is
4354  // removed.
4355 
4356  if (!bLoadedNym) {
4357  OTString strNymID(RECIPIENT_USER_ID);
4358  OTLog::vError("%s: Failure loading Recipient Nym "
4359  "public key: %s\n",
4360  __FUNCTION__, strNymID.Get());
4361  bFoundRecipientNym = false;
4362  }
4363  else if (!theRecipientNym.VerifyPseudonym() ||
4364  !theRecipientNym.LoadSignedNymfile(
4365  server_->m_nymServer)) {
4366  OTString strNymID(RECIPIENT_USER_ID);
4367  OTLog::vError("%s: Failure loading or verifying "
4368  "Recipient Nym public key: %s\n",
4369  __FUNCTION__, strNymID.Get());
4370  bFoundRecipientNym = false;
4371  }
4372  else {
4373  pRecipientNym = &theRecipientNym; // <=====
4374  bFoundRecipientNym = true;
4375  }
4376  }
4377  // Below this point, ALWAYS use pRecipientNym, NOT
4378  // theRecipientNym.
4379  // pRecipientNym is always guaranteed below here to point to
4380  // the right one.
4381  if (!bFoundRecipientNym || (nullptr == pRecipientNym)) {
4382  // (No need to log here; already logged right above.)
4383  // OTLog::vOutput("Unable to load or verify Recipient
4384  // Nym.()", __FUNCTION__);
4385  }
4386 
4387  // Below this point, we know for sure that the Recipient Nym
4388  // is loaded and verified, and we know
4389  // that if the Server or Sender is actually the Recipient,
4390  // that the pRecipientNym pointer will
4391  // always point to the right one, and no files can be
4392  // overwritten. *phew*
4393 
4394  // You CAN have both accounts owned by the same Nym, but you
4395  // CANNOT have them both actually be the SAME ACCT.
4396  else if (!bCancelling && (DEPOSITOR_ACCT_ID ==
4397  RECIPIENT_ACCT_ID)) // ACTIVATING
4398  {
4400  0, "%s: Error: Source account ID matches Recipient "
4401  "account ID "
4402  "on attempted Payment Plan notarization.\n",
4403  __FUNCTION__);
4404  }
4405  // Unless you are cancelling...
4406  else if (bCancelling && (DEPOSITOR_ACCT_ID !=
4407  RECIPIENT_ACCT_ID)) // CANCELLING
4408  {
4410  0, "%s: Error: Source account ID doesn't match "
4411  "Recipient account ID "
4412  "on attempted Payment Plan cancellation.\n",
4413  __FUNCTION__);
4414  }
4415  else if (!bCancelling &&
4416  !pPlan->VerifyAgreement(*pRecipientNym,
4417  theNym)) // ACTIVATING
4418  {
4420  0, "%s: ERROR verifying Sender and Recipient on "
4421  "Payment Plan "
4422  "(against merchant and customer copies.)\n",
4423  __FUNCTION__);
4424  }
4425  // This is now done above, in VerifyAgreement().
4426  // We only have it here now in cases of cancellation (where
4427  // VerifyAgreement isn't called.)
4428  // //
4429  // CANCELING
4430  else if (bCancelling &&
4431  !pPlan->VerifySignature(*pRecipientNym)) {
4432  OTLog::Output(0, "ERROR verifying Recipient's "
4433  "signature on Payment Plan.\n");
4434  }
4435  else {
4436  // Verify that BOTH of the Recipient's transaction
4437  // numbers
4438  // (opening and closing) are available for use.
4439  //
4440  // These three blocks are only checked if we are
4441  // activating, not cancelling.
4442  // Why? Because if we're canceling, then we ALREADY
4443  // checked these things above.
4444  // But if we're activating, that means we checked the
4445  // sender above only, and
4446  // thus we still need to check the recipient.
4447  //
4448  if (!bCancelling &&
4449  pPlan->GetRecipientCountClosingNumbers() < 2) {
4450  OTLog::vOutput(0, "%s: ERROR verifying Recipient's "
4451  "Opening and Closing number on a "
4452  "Payment Plan "
4453  "(he should have two numbers, "
4454  "but he doesn't.)\n",
4455  __FUNCTION__);
4456  }
4457  else if (!bCancelling &&
4458  !server_->transactor_
4460  *pRecipientNym,
4461  pPlan->GetRecipientOpeningNum())) {
4462  OTLog::vOutput(0, "%s: ERROR verifying Recipient's "
4463  "opening transaction number on a "
4464  "payment plan.\n",
4465  __FUNCTION__);
4466  }
4467  else if (!bCancelling &&
4468  !server_->transactor_
4470  *pRecipientNym,
4471  pPlan->GetRecipientClosingNum())) {
4472  OTLog::vOutput(0, "%s: ERROR verifying Recipient's "
4473  "Closing transaction number on a "
4474  "Payment Plan.\n",
4475  __FUNCTION__);
4476  }
4477  else {
4478  // Load up the recipient ACCOUNT and validate it.
4479  //
4480  OTAccount* pRecipientAcct = nullptr;
4481  std::unique_ptr<OTAccount> theRecipientAcctGuardian;
4482  if (!bCancelling) // ACTIVATING
4483  {
4484  pRecipientAcct = OTAccount::LoadExistingAccount(
4485  RECIPIENT_ACCT_ID, SERVER_ID);
4486  theRecipientAcctGuardian.reset(pRecipientAcct);
4487  }
4488  else // CANCELLING
4489  {
4490  pRecipientAcct = &theDepositorAccount;
4491  }
4492  //
4493  if (nullptr == pRecipientAcct) {
4495  0, "%s: ERROR loading Recipient account.\n",
4496  __FUNCTION__);
4497  }
4498  else if (!pRecipientAcct->VerifyOwner(
4499  *pRecipientNym)) {
4500  OTLog::vOutput(0, "%s: ERROR verifying "
4501  "ownership of the recipient "
4502  "account.\n",
4503  __FUNCTION__);
4504  }
4505  else if (pRecipientAcct->IsInternalServerAcct()) {
4507  0,
4508  "%s: Failed: recipient account is an "
4509  "internal "
4510  "server account (currently prohibited.)\n",
4511  __FUNCTION__);
4512  }
4513  // Are both of the accounts of the same Asset Type?
4514  // VERY IMPORTANT!!
4515  else if (pRecipientAcct->GetAssetTypeID() !=
4516  theDepositorAccount.GetAssetTypeID()) {
4517  OTString strSourceAssetID(
4518  theDepositorAccount.GetAssetTypeID()),
4519  strRecipAssetID(
4520  pRecipientAcct->GetAssetTypeID());
4522  0, "%s: ERROR - user attempted to %s a "
4523  "payment plan between dissimilar "
4524  "asset types:\n%s\n%s\n",
4525  __FUNCTION__,
4526  bCancelling ? "cancel" : "activate",
4527  strSourceAssetID.Get(),
4528  strRecipAssetID.Get());
4529  }
4530  // Does it verify?
4531  // I call VerifySignature here since
4532  // VerifyContractID was already called in
4533  // LoadExistingAccount().
4534  else if (!pRecipientAcct->VerifySignature(
4535  server_->m_nymServer)) {
4536  OTLog::vOutput(0, "%s: ERROR verifying "
4537  "signature on the Recipient "
4538  "account.\n",
4539  __FUNCTION__);
4540  }
4541  // This one is superfluous, but I'm leaving it.
4542  // (pPlan and pRecip are both already
4543  // matches to a 3rd value: source acct asset type
4544  // ID.)
4545  else if (pRecipientAcct->GetAssetTypeID() !=
4546  pPlan->GetAssetID()) {
4547  const OTString strAssetID1(pPlan->GetAssetID()),
4548  strAssetID2(
4549  pRecipientAcct->GetAssetTypeID());
4550  OTLog::vOutput(0, "%s: ERROR wrong Asset Type "
4551  "ID (%s) on Recipient Acct. "
4552  "Expected per Plan: %s\n",
4553  __FUNCTION__, strAssetID2.Get(),
4554  strAssetID1.Get());
4555  }
4556  // At this point I feel pretty confident that the
4557  // Payment Plan is a valid request from both
4558  // parties.
4559  // I have both users AND both accounts and validated
4560  // against the Payment Plan, signatures and all.
4561  // The only other possibility is that the merchant
4562  // is canceling the payment plan before the customer
4563  // had a chance to confirm/activate it.
4564  else {
4565  // If activating, add it to Cron...
4566  //
4567  // We add the payment plan to the server's Cron
4568  // object, which does regular processing.
4569  // That object will take care of processing the
4570  // payment plan according to its terms.
4571  //
4572  // NOTE: FYI, inside AddCronItem, since this is
4573  // a new CronItem, a Cron Receipt will
4574  // be saved with the User's signature on it,
4575  // containing the Cron Item from the user's
4576  // original request. After that, the item is
4577  // stored internally to Cron itself, and
4578  // signed by the server--and changes over time
4579  // as cron processes. (The original receipt
4580  // can always be loaded when necessary.)
4581  //
4582  if (!bCancelling &&
4583  server_->m_Cron.AddCronItem(
4584  *pPlan, &theNym, true,
4585  OTTimeGetCurrentTime())) // bSaveReceipt=true
4586  {
4587  // todo need to be able to "roll back" if
4588  // anything inside this block fails.
4589 
4590  // Now we can set the response item as an
4591  // acknowledgement instead of the default
4592  // (rejection)
4593  pResponseItem->SetStatus(
4595 
4596  bOutSuccess = true; // The payment plan
4597  // activation was
4598  // successful.
4599 
4600  OTLog::vOutput(2, "%s: Successfully added "
4601  "payment plan to Cron "
4602  "object.\n",
4603  __FUNCTION__);
4604 
4605  // Server side, the Nym stores a list of all
4606  // open cron item numbers.
4607  // (So we know if there is still stuff open
4608  // on Cron for that Nym, and we know what it
4609  // is.)
4610  //
4611  std::set<int64_t>& theIDSet =
4612  theNym.GetSetOpenCronItems();
4613  theIDSet.insert(pPlan->GetTransactionNum());
4614  theIDSet.insert(pPlan->GetClosingNum());
4615  // // saved below
4616 
4617  // This just marks the Closing number so I
4618  // can't USE it again. (Since I'm using it
4619  // as the closing
4620  // number for this cron item now.) I'm still
4621  // RESPONSIBLE for the number until
4622  // RemoveIssuedNumber()
4623  // is called. If we didn't call this here,
4624  // then I could come back later and USE THE
4625  // NUMBER AGAIN!
4626  // (Bad!)
4627  // server_->transactor_.removeTransactionNumber
4628  // was
4629  // already
4630  // called for tranIn->GetTransactionNum()
4631  // (That's the opening number.)
4632  //
4633  // Here's the closing number:
4634  server_->transactor_
4636  theNym, pPlan->GetClosingNum(),
4637  true); // bSave=true
4638  // RemoveIssuedNum will be called for that
4639  // original transaction number when the
4640  // finalReceipt is created.
4641  // RemoveIssuedNum will be called for the
4642  // Closing number when the finalReceipt is
4643  // accepted.
4644 
4645  std::set<int64_t>& theIDSet2 =
4646  pRecipientNym->GetSetOpenCronItems();
4647  theIDSet2.insert(
4648  pPlan->GetRecipientOpeningNum());
4649  theIDSet2.insert(
4650  pPlan->GetRecipientClosingNum());
4651  // // saved below
4652 
4653  // For recipient, I also remove the opening
4654  // and closing numbers as AVAILABLE FOR USE.
4655  // But they aren't removed as ISSUED until
4656  // later...
4657  // RemoveIssuedNum is called for the
4658  // Recipient's opening number
4659  // onFinalReceipt,
4660  // and it's called for the Recipient's
4661  // closing number when that final receipt is
4662  // closed out.
4663  server_->transactor_
4665  *pRecipientNym,
4666  pPlan->GetRecipientOpeningNum(),
4667  false); // bSave=true
4668  server_->transactor_
4670  *pRecipientNym,
4671  pPlan->GetRecipientClosingNum(),
4672  true); // bSave=true
4673 
4674  // Send success notice to other parties.
4675  // (So they can deal with their payments
4676  // inbox and outpayments box,
4677  // where pending copies of the instrument
4678  // may still be waiting.)
4679  //
4680  int64_t lOtherNewTransNumber = 0;
4681  server_->transactor_
4683  server_->m_nymServer,
4684  lOtherNewTransNumber,
4685  false); // bStoreTheNumber = false
4686 
4687  if (false ==
4688  pPlan->SendNoticeToAllParties(
4689  true, // bSuccessMsg=true
4690  server_->m_nymServer, SERVER_ID,
4691  lOtherNewTransNumber,
4692  // // Each party has its own opening
4693  // number. Handled internally.
4694  strPaymentPlan, nullptr, nullptr,
4695  &theNym)) {
4697  0, "%s: Failed notifying parties "
4698  "while trying to activate "
4699  "payment plan: %ld.\n",
4700  __FUNCTION__,
4701  pPlan->GetOpeningNum());
4702  }
4703  }
4704  else {
4705  if (bCancelling) {
4706  tranOut.SetAsCancelled();
4707 
4709  0, "%s: Canceling a payment plan "
4710  "before it was ever activated. "
4711  "(At user's request.)\n",
4712  __FUNCTION__);
4713  }
4714  else
4716  0, "%s: Unable to add payment plan "
4717  "to Cron. (Failed activating "
4718  "payment plan.)\n",
4719  __FUNCTION__);
4720 
4721  // Send a failure notice to the other
4722  // parties.
4723  //
4724  // DROP REJECTION NOTICE HERE TO ALL
4725  // PARTIES....
4726  // SO THEY CAN CLAW BACK THEIR TRANSACTION
4727  // #s....
4728  //
4729  int64_t lOtherNewTransNumber = 0;
4730  server_->transactor_
4732  server_->m_nymServer,
4733  lOtherNewTransNumber,
4734  false); // bStoreTheNumber = false
4735 
4736  if (false ==
4737  pPlan->SendNoticeToAllParties(
4738  false, server_->m_nymServer,
4739  SERVER_ID, lOtherNewTransNumber,
4740  // // Each party has its own opening
4741  // number. Handled internally.
4742  strPaymentPlan, nullptr, nullptr,
4743  &theNym)) {
4744  // NOTE: A party may deliberately try to
4745  // activate a payment plan without
4746  // signing it.
4747  // (As a way of rejecting it.) This will
4748  // cause rejection notices to go to all
4749  // the other
4750  // parties, allowing them to harvest
4751  // back their closing numbers.
4752  // Since that is expected to happen,
4753  // that means if you have 2 parties, and
4754  // the 2nd one
4755  // "activates" it (without signing),
4756  // then this piece of code here will
4757  // DEFINITELY fail to
4758  // send the rejection notice to the
4759  // first party (since the 2nd one hadn't
4760  // even signed the
4761  // thing yet.)
4762  //
4763  // (Since we expect that to normally
4764  // happen, we don't log an error here.)
4765 
4766  // OTLog::vOutput(0,
4767  // "%s: Failed notifying all parties
4768  // about failed activation of payment
4769  // plan: %ld.\n",
4770  // __FUNCTION__,
4771  // pPlan->GetTransactionNum());
4772  }
4773  } // Failure adding Cron Item.
4774  }
4775  }
4776  } // If recipient Nym successfully loaded from storage.
4777  } // If Payment Plan successfully loaded from Transaction Item.
4778  } // else
4779 
4780  // If the payment plan WAS successfully added to Cron, then we don't
4781  // need to
4782  // delete it here, since Cron owns it now, and will deal with
4783  // cleaning it up at the right time.
4784  if ((nullptr != pPlan) &&
4785  (pResponseItem->GetStatus() != OTItem::acknowledgement)) {
4786  delete pPlan;
4787  pPlan = nullptr;
4788  }
4789  }
4790  }
4791 
4792  // sign the response item before sending it back (it's already been added to
4793  // the transaction above)
4794  // Now, whether it was rejection or acknowledgement, it is set properly and
4795  // it is signed, and it
4796  // is owned by the transaction, who will take it from here.
4797  pResponseItem->SignContract(server_->m_nymServer);
4798  pResponseItem->SaveContract(); // the signing was of no effect because I
4799  // forgot to save.
4800 
4801  pResponseBalanceItem->SignContract(server_->m_nymServer);
4802  pResponseBalanceItem->SaveContract();
4803 }
static EXPORT void vError(const char *szError,...)
Definition: OTLog.cpp:800
static EXPORT void Output(int32_t nVerbosity, const char *szOutput)
Definition: OTLog.cpp:710
bool issueNextTransactionNumber(OTPseudonym &nym, int64_t &txNumber, bool storeNumber=true)
Definition: Transactor.cpp:211
#define NYM_IS_ALLOWED(SZ_NYM_ID, BOOL_VAR_NAME)
Definition: Macros.hpp:146
bool verifyTransactionNumber(OTPseudonym &nym, const int64_t &transactionNumber)
Definition: Transactor.cpp:278
EXPORT bool AddCronItem(OTCronItem &theItem, OTPseudonym *pActivator, bool bSaveReceipt, time64_t tDateAdded)
Definition: OTCron.cpp:731
bool removeTransactionNumber(OTPseudonym &nym, const int64_t &transactionNumber, bool save=false)
Definition: Transactor.cpp:320
static EXPORT OTItem * CreateItemFromTransaction(const OTTransaction &theOwner, OTItem::itemType theType, const OTIdentifier *pDestinationAcctID=nullptr)
Definition: OTItem.cpp:1451
EXPORT void SetIdentifier(const OTIdentifier &theIdentifier)
time64_t OTTimeGetCurrentTime()
Definition: Common.hpp:211
#define OT_ASSERT(x)
Definition: Assert.hpp:150
static bool __transact_payment_plan
static EXPORT void vOutput(int32_t nVerbosity, const char *szOutput,...)
Definition: OTLog.cpp:768
static EXPORT OTAccount * LoadExistingAccount(const OTIdentifier &accountId, const OTIdentifier &serverId)
Definition: OTAccount.cpp:480
void opentxs::Notary::NotarizeProcessInbox ( OTPseudonym theNym,
OTAccount theAccount,
OTTransaction tranIn,
OTTransaction tranOut,
bool &  bOutSuccess 
)

The client may send multiple transactions in the ledger when he calls processInbox. This function will be called for each of those. Each may contain multiple items accepting or rejecting certain transactions. The server acknowledges and notarizes those transactions accordingly. (And each of those transactions must be accepted or rejected in whole.)

Definition at line 8088 of file Notary.cpp.

8091 {
8092  // The outgoing transaction is an "atProcessInbox", that is, "a reply to the
8093  // process inbox request"
8094  tranOut.SetType(OTTransaction::atProcessInbox);
8095 
8096  OTItem* pItem = nullptr;
8097  OTItem* pBalanceItem = tranIn.GetItem(OTItem::balanceStatement);
8098  OTItem* pResponseItem = nullptr;
8099  OTItem* pResponseBalanceItem = nullptr;
8100 
8101  // The incoming transaction may be sent to inboxes and outboxes, and it
8102  // will probably be bundled in our reply to the user as well. Therefore,
8103  // let's grab it as a string.
8104  OTString strInReferenceTo;
8105  OTString strBalanceItem;
8106 
8107  // Grab the actual server ID from this object, and use it as the server ID
8108  // here.
8109  const OTIdentifier SERVER_ID(server_->m_strServerID),
8110  ACCOUNT_ID(theAccount), USER_ID(theNym);
8111 
8112  const OTString strUserID(USER_ID);
8113 
8114  OTPseudonym theTempNym, theTempClosingNumNym;
8115  std::unique_ptr<OTLedger> pInbox(
8116  theAccount.LoadInbox(server_->m_nymServer));
8117  std::unique_ptr<OTLedger> pOutbox(
8118  theAccount.LoadOutbox(server_->m_nymServer));
8119 
8120  pResponseBalanceItem =
8122  pResponseBalanceItem->SetStatus(OTItem::rejection); // the default.
8123  tranOut.AddItem(*pResponseBalanceItem); // the Transaction's destructor will
8124  // cleanup the item. It "owns" it
8125  // now.
8126  if (!NYM_IS_ALLOWED(strUserID.Get(),
8129  0, "%s: User %s cannot do this transaction (All \"process inbox\" "
8130  "transactions are disallowed in server.cfg)\n",
8131  __FUNCTION__, strUserID.Get());
8132  }
8133  else if (nullptr == pBalanceItem) {
8135  0, "%s: No Balance Agreement item found on this transaction.\n",
8136  __FUNCTION__);
8137  }
8138  else if (nullptr == pInbox) {
8139  OTLog::vError("%s: Error loading or verifying inbox.\n", __FUNCTION__);
8140  }
8141  else if (nullptr == pOutbox) {
8142  OTLog::vError("%s: Error loading or verifying outbox.\n", __FUNCTION__);
8143  }
8144  else {
8145  pBalanceItem->SaveContractRaw(strBalanceItem);
8146 
8147  pResponseBalanceItem->SetReferenceString(
8148  strBalanceItem); // the response item carries a copy of what it's
8149  // responding to.
8150  pResponseBalanceItem->SetReferenceToNum(
8151  pBalanceItem->GetTransactionNum()); // This response item is IN
8152  // RESPONSE to tranIn's balance
8153  // agreement
8154  pResponseBalanceItem->SetNumberOfOrigin(*pBalanceItem);
8155 
8156  // This transaction accepts various incoming pending transfers.
8157  // So when it's all done, my balance will be higher.
8158  // AND pending inbox items will be removed from my inbox.
8159  //
8160  // I would like to not even process the whole giant loop below,
8161  // if I can verify here now that the balance agreement is wrong.
8162  //
8163  // Thus I will actually loop through the acceptPending items in tranIn,
8164  // and then for each one, I'll
8165  // lookup the ACTUAL transaction in the inbox, and get its ACTUAL value.
8166  // (And total them all up.)
8167  //
8168  // The total of those, (WITHOUT the user having to tell me what it will
8169  // be, since I'm looking them all up),
8170  // should equal the difference in the account balance! Meaning the
8171  // current balance plus that total will be
8172  // the expected NEW balance, according to this balance agreement -- if
8173  // it wants to be approved, that is.
8174  //
8175  //
8176 
8177  std::list<int64_t> theListOfInboxReceiptsBeingRemoved;
8178  // To make sure each
8179  // inbox item refers to a different number. (If two of them refer to the
8180  // same number, that's bad and is not allowed. You can't process the
8181  // same inbox item twice simultaneously! Or even at all.)
8182 
8183  bool bSuccessFindingAllTransactions = true;
8184  int64_t lTotalBeingAccepted = 0;
8185 
8186  for (auto& it_bigloop : tranIn.GetItemList()) {
8187  pItem = it_bigloop;
8188  OT_ASSERT_MSG(nullptr != pItem,
8189  "Pointer should not have been nullptr.");
8190  OTTransaction* pServerTransaction = nullptr;
8191 
8192  switch (pItem->GetType()) {
8194  pServerTransaction = nullptr;
8195  continue;
8196 
8203  pServerTransaction =
8204  pInbox->GetTransaction(pItem->GetReferenceToNum());
8205  break;
8206 
8207  case OTItem::acceptPending: // Accept an incoming (pending)
8208  // transfer.
8209  case OTItem::acceptItemReceipt: // Accept a chequeReceipt,
8210  // voucherReceipt, or
8211  // transferReceipt.
8212  case OTItem::rejectPending:
8214  pServerTransaction =
8215  pInbox->GetTransaction(pItem->GetReferenceToNum());
8216  break;
8217 
8218  default: {
8219  OTString strItemType;
8220  pItem->GetTypeString(strItemType);
8221  int32_t nItemType = pItem->GetType();
8222 
8223  pServerTransaction = nullptr;
8224  bSuccessFindingAllTransactions = false;
8225 
8226  OTLog::vError("%s: Wrong item type: %s (%d).\n", __FUNCTION__,
8227  strItemType.Exists() ? strItemType.Get() : "",
8228  nItemType);
8229  break;
8230  }
8231  }
8232  if (nullptr == pServerTransaction) {
8233  const OTString strAccountID(ACCOUNT_ID);
8234  OTLog::vError("%s: Unable to find or process inbox transaction "
8235  "being accepted by user: %s for account: %s\n",
8236  __FUNCTION__, strUserID.Get(),
8237  strAccountID.Get());
8238  bSuccessFindingAllTransactions = false;
8239  break;
8240  }
8241  else if (pServerTransaction->GetReceiptAmount() !=
8242  pItem->GetAmount()) {
8243  OTLog::vError(
8244  "%s: Receipt amounts don't match: %ld and %ld. Nym: %s\n",
8245  __FUNCTION__, pServerTransaction->GetReceiptAmount(),
8246  pItem->GetAmount(), strUserID.Get());
8247  bSuccessFindingAllTransactions = false;
8248  break;
8249  }
8250 
8251  // BELOW THIS POINT, WE KNOW THAT pServerTransaction was FOUND (and
8252  // validated.)
8253 
8254  switch (pItem->GetType()) {
8256  bSuccessFindingAllTransactions = true;
8257  break;
8259  bSuccessFindingAllTransactions = true;
8260 
8261  // Need to ERROR OUT here, if the number of cron receipts
8262  // (related to
8263  // this finalReceipt) in the inbox isn't equal to the number
8264  // being accepted
8265  // in this processInbox transaction. (You can't close the final
8266  // receipt unless
8267  // you close all the others as well.)
8268  //
8269 
8270  // IN THIS CASE: If user is accepting a finalReceipt, that means
8271  // all the OTHER receipts related to it
8272  // (sharing the same "in reference to") must ALSO be cleared
8273  // from the inbox along with it! That's the
8274  // whole point of the finalReceipt -- to make sure all related
8275  // receipts are cleared, when IT is.
8276  //
8277  // So let's see if the number of related receipts on this
8278  // process inbox (tranIn) matches
8279  // the number of related receipts in the actual inbox (pInbox),
8280  // as found by the finalReceipt's
8281  // (pServerTransaction) "in reference to" value, which should be
8282  // the same as on the related receipts.
8283 
8284  // (Below) tranIn is the processInbox transaction. Each item on
8285  // it is "in ref to" a DIFFERENT receipt,
8286  // even though, if they are marketReceipts, all of THOSE
8287  // receipts are "in ref to" the original transaction#.
8288  // I need to loop through all items on tranIn (processInbox
8289  // request)
8290  // For each, look it up on the inbox. (Each item will be "in
8291  // reference to" the original transaction.)
8292  // ONCE THE INBOX RECEIPT IS FOUND, if *IT* is "in reference to"
8293  // pServerTransaction->GetReferenceToNum(),
8294  // Then increment the count for the transaction. COMPARE *THAT*
8295  // to theInbox.GetCount and we're golden!!
8296  {
8297  std::set<int64_t> setOfRefNumbers; // we'll store them here,
8298  // and disallow
8299  // duplicates, to make
8300  // sure they are all
8301  // unique IDs (no
8302  // repeats.)
8303 
8304  for (auto& it : tranIn.GetItemList()) {
8305  OTItem* pItemPointer = it;
8306  OT_ASSERT_MSG(nullptr != pItemPointer,
8307  "Pointer should not have been nullptr.");
8308 
8309  OTTransaction* pTransPointer = pInbox->GetTransaction(
8310  pItemPointer->GetReferenceToNum());
8311 
8312  if ((nullptr != pTransPointer) &&
8313  (pTransPointer->GetReferenceToNum() ==
8314  pServerTransaction->GetReferenceToNum())) {
8315  setOfRefNumbers.insert(
8316  pItemPointer->GetReferenceToNum());
8317  }
8318  }
8319 
8320  if (pInbox->GetTransactionCountInRefTo(
8321  pServerTransaction->GetReferenceToNum()) !=
8322  static_cast<int32_t>(setOfRefNumbers.size())) {
8324  0, "%s: User tried to close a finalReceipt, "
8325  "without also closing all related receipts. "
8326  "(Those that share the IN REF TO number.)\n",
8327  __FUNCTION__);
8328  bSuccessFindingAllTransactions = false;
8329  break;
8330  }
8331  // Upon success, these numbers will be removed from the
8332  // Nym's additional record of "cron item IDs".
8333  //
8334 
8335  // Server side stores a list of open cron items on each Nym.
8336  // The closing transaction number on the final receipt
8337  // SHOULD be on that list.
8338  //
8339  std::set<int64_t>& theIDSet = theNym.GetSetOpenCronItems();
8340 
8341  std::set<int64_t>::iterator theSetIT =
8342  theIDSet.find(pServerTransaction->GetClosingNum());
8343 
8344  // If we FOUND it on the Nym, then we add it to the list to
8345  // be removed from Nym's open cron items.
8346  // (If it wasn't there before, then we wouldn't want to
8347  // "re-add" it, now would we?)
8348  //
8349  if (theIDSet.end() != theSetIT) // FOUND IT!
8350  theTempClosingNumNym.AddIssuedNum(
8351  server_->m_strServerID,
8352  pServerTransaction->GetClosingNum()); // Schedule to
8353  // remove
8354  // GetClosingNum() from
8355  // server-side list of Nym's
8356  // open cron items. (By
8357  // adding it to
8358  // theTempClosingNumNym.)
8359  else
8361  1, "%s: expected to find "
8362  "pServerTransaction->GetClosingNum() (%ld) on "
8363  "Nym's (%s) "
8364  "list of open cron items. (Maybe he didn't see "
8365  "the notice in his Nymbox yet.)\n",
8366  __FUNCTION__, pServerTransaction->GetClosingNum(),
8367  strUserID.Get());
8368  // else error log.
8369  }
8370 
8371  // ---- COUNT is correct and closing num is on list of open cron
8372  // items. (FINAL RECEIPT FALLS THROUGH HERE!!! no break)
8373 
8375  // IF it's actually there on theNym, then schedule it for
8376  // removal.
8377  // (Otherwise we'd end up improperly re-adding it.)
8378  //
8379  if (theNym.VerifyIssuedNum(server_->m_strServerID,
8380  pServerTransaction->GetClosingNum()))
8381  theTempNym.AddIssuedNum(
8382  server_->m_strServerID,
8383  pServerTransaction->GetClosingNum());
8384  else {
8385  bSuccessFindingAllTransactions = false;
8386 
8387  OTLog::vError("%s: basket or final receipt, trying to "
8388  "'remove' an issued "
8389  "number (%ld) that already wasn't on Nym's "
8390  "issued list. (So what is this in the inbox, "
8391  "then?)\n",
8392  __FUNCTION__,
8393  pServerTransaction->GetClosingNum());
8394  }
8395 
8396  break;
8397  case OTItem::acceptPending:
8398  // IF I'm accepting a pending transfer, then add the amount to
8399  // my counter of total amount being accepted.
8400  //
8401  lTotalBeingAccepted += pServerTransaction->GetReceiptAmount();
8402  bSuccessFindingAllTransactions = true;
8403  break;
8405  bSuccessFindingAllTransactions = true;
8406  {
8407  // If I'm accepting an item receipt (which will remove my
8408  // responsibility for that item) then add it
8409  // to the temp Nym (which is a list of transaction numbers
8410  // that will be removed from my responsibility if
8411  // all is successful.) Also remove all the Temp Nym numbers
8412  // from theNym, so we can verify the Balance
8413  // Statement AS IF they were already removed.
8414  //
8415  // What number do I remove here? the user is accepting a
8416  // transfer receipt, which
8417  // is in reference to the recipient's acceptPending. THAT
8418  // item is in reference to
8419  // my original transfer (or contains a cheque with my
8420  // original number.) (THAT's the # I need.)
8421  //
8422  OTString strOriginalItem;
8423  pServerTransaction->GetReferenceString(strOriginalItem);
8424 
8425  std::unique_ptr<OTItem> pOriginalItem(
8427  strOriginalItem, SERVER_ID,
8428  pServerTransaction->GetReferenceToNum()));
8429 
8430  if (nullptr != pOriginalItem) {
8431  // If pOriginalItem is acceptPending, that means the
8432  // client is accepting the transfer receipt from the
8433  // server, (from his inbox),
8434  // which has the recipient's acceptance inside of the
8435  // client's transfer as the original item. This means
8436  // the transfer that
8437  // the client originally sent is now finally closed!
8438  //
8439  // If it's a depositCheque, that means the client is
8440  // accepting the cheque receipt from the server, (from
8441  // his inbox)
8442  // which has the recipient's deposit inside of it as the
8443  // original item. This means that the cheque that
8444  // the client originally wrote is now finally closed!
8445  //
8446  // In both cases, the "original item" itself is not from
8447  // the client, but from the recipient! Therefore,
8448  // the number on that item is useless for removing
8449  // numbers from the client's list of issued numbers.
8450  // Rather, I need to load that original cheque, or
8451  // pending transfer, from WITHIN the original item,
8452  // in order to get THAT number, to remove it from the
8453  // client's issued list. (Whether for real, or for
8454  // setting up dummy data in order to verify the balance
8455  // agreement.) *sigh*
8456  //
8457  if (OTItem::depositCheque ==
8458  pOriginalItem->GetType()) // client is accepting a
8459  // cheque receipt, which
8460  // has a depositCheque
8461  // (from the recipient) as
8462  // the original item
8463  // within.
8464  {
8465  // Get the cheque from the Item and load it up into
8466  // a Cheque object.
8467  OTString strCheque;
8468  pOriginalItem->GetAttachment(strCheque);
8469 
8470  OTCheque theCheque; // allocated on the stack :-)
8471 
8472  if (false ==
8473  ((strCheque.GetLength() > 2) &&
8474  theCheque.LoadContractFromString(strCheque))) {
8475  OTLog::vError("%s: ERROR loading cheque from "
8476  "string:\n%s\n",
8477  __FUNCTION__, strCheque.Get());
8478  bSuccessFindingAllTransactions = false;
8479  }
8480  else // Since the client wrote the cheque, and he
8481  // is now accepting the cheque receipt, he
8482  // can be cleared for that transaction
8483  // number...
8484  {
8485  // IF it's actually there on theNym, then
8486  // schedule it for removal.
8487  // (Otherwise we'd end up improperly re-adding
8488  // it.)
8489  //
8490  if (theNym.VerifyIssuedNum(
8491  server_->m_strServerID,
8492  theCheque.GetTransactionNum()))
8493  theTempNym.AddIssuedNum(
8494  server_->m_strServerID,
8495  theCheque.GetTransactionNum());
8496  else {
8497  bSuccessFindingAllTransactions = false;
8498 
8499  OTLog::vError(
8500  "%s: cheque receipt, trying to "
8501  "'remove' an issued "
8502  "number (%ld) that already wasn't on "
8503  "Nym's issued list. (So what is this "
8504  "in the inbox, "
8505  "then?)\n",
8506  __FUNCTION__,
8507  theCheque.GetTransactionNum());
8508  }
8509  }
8510  }
8511  // client is accepting a transfer receipt, which has an
8512  // acceptPending from the recipient as the original item
8513  // within,
8514  else if (OTItem::acceptPending ==
8515  pOriginalItem->GetType()) // (which is in
8516  // reference to the
8517  // client's outoing
8518  // original
8519  // transfer.)
8520  {
8521  // IF it's actually there on theNym, then schedule
8522  // it for removal.
8523  // (Otherwise we'd end up improperly re-adding it.)
8524  //
8525  if (theNym.VerifyIssuedNum(
8526  server_->m_strServerID,
8527  pOriginalItem->GetNumberOfOrigin()))
8528  theTempNym.AddIssuedNum(
8529  server_->m_strServerID,
8530  pOriginalItem->GetNumberOfOrigin());
8531  else {
8532  bSuccessFindingAllTransactions = false;
8533 
8534  OTLog::vError(
8535  "%s: transfer receipt, trying to 'remove' "
8536  "an issued "
8537  "number (%ld) that already wasn't on Nym's "
8538  "issued list. (So what is this in the "
8539  "inbox, "
8540  "then?)\n",
8541  __FUNCTION__,
8542  pOriginalItem->GetReferenceToNum());
8543  }
8544  }
8545  else {
8546  OTString strOriginalItemType;
8547  pOriginalItem->GetTypeString(strOriginalItemType);
8548  OTLog::vError("%s: Original item has wrong type, "
8549  "while accepting item receipt:\n%s\n",
8550  __FUNCTION__,
8551  strOriginalItemType.Get());
8552  bSuccessFindingAllTransactions = false;
8553  }
8554  }
8555  else {
8556  OTLog::vError("%s: Unable to load original item from "
8557  "string while accepting item "
8558  "receipt:\n%s\n",
8559  __FUNCTION__, strOriginalItem.Get());
8560  bSuccessFindingAllTransactions = false;
8561  }
8562  } // pItem is acceptItemReceipt --------------------
8563 
8564  break;
8565  default:
8566  OTLog::Error("Wrong item type in "
8567  "Notary::NotarizeProcessInbox. (2nd notice.)\n");
8568  bSuccessFindingAllTransactions = false;
8569  break;
8570  } // switch --------------------------------------------
8571 
8572  // I'll also go ahead and remove each transaction from pInbox, and
8573  // pass said inbox into the VerifyBalanceAgreement call...
8574  // (So it can simulate as if the inbox was already processed, and
8575  // the total is already calculated, and if it succeeds,
8576  // then we can allow the giant loop below to do it all for real.)
8577  // (I'm not saving this copy of the inbox anyway--there's another
8578  // one below.)
8579  //
8580  if (bSuccessFindingAllTransactions) {
8581  // WE'RE REMOVING THE TRANSACTIONS FROM AN INBOX COPY, IN ORDER
8582  // TO VERIFY THE
8583  // BALANCE AGREEMENT (WITH THAT INBOX COPY SET UP AS THOUGH THE
8584  // TRANSACTION HAD
8585  // ALREADY BEEN A SUCCESS.)
8586  // I'm not ACTUALLY removing though, until AFTER the loop (in
8587  // case the rest of the
8588  // loop needs the data still, in that inbox.) So we save in a
8589  // list, and remove AFTER the loop.
8590  //
8591  theListOfInboxReceiptsBeingRemoved.push_back(
8592  pServerTransaction->GetTransactionNum());
8593  }
8594  else // If there was an error above, then we don't want to keep
8595  // looping. We want the below error block.
8596  break;
8597  } // for loop (list of "process inbox" items)
8598 
8599  if (!bSuccessFindingAllTransactions) {
8600  OTLog::vOutput(0, "%s: transactions in processInbox message do not "
8601  "match actual inbox.\n",
8602  __FUNCTION__);
8603  }
8604  else { // Remove certain receipts (determined in the big loop above)
8605  // from the inbox copy,
8606  // to see if it will verify in the balance agreement.
8607  //
8608  while (!theListOfInboxReceiptsBeingRemoved.empty()) {
8609  int64_t lTemp = theListOfInboxReceiptsBeingRemoved.front();
8610  theListOfInboxReceiptsBeingRemoved.pop_front();
8611 
8612  // Notice I don't call DeleteBoxReceipt(lTemp) here like I
8613  // normally would when calling
8614  // RemoveTransaction(lTemp), since this is only a copy of my
8615  // inbox and not the real thing.
8616  //
8617  if (false ==
8618  pInbox->RemoveTransaction(lTemp)) // <================
8619  OTLog::vError(
8620  "%s: Failed removing receipt from Inbox copy: %ld \n"
8621  "Meaning the client probably has an old copy of his "
8622  "inbox. "
8623  "We don't even see the receipt that he still thinks he "
8624  "has.\n",
8625  __FUNCTION__, lTemp);
8626  }
8627  // Remove certain issued numbers (determined in the big loop above)
8628  // from the Nym,
8629  // to see if it will verify in the balance agreement (we'll re-add
8630  // them after.)
8631  // Also, we're ONLY removing these because we verified above that
8632  // they were really there.
8633  // Otherwise it'd be pretty stupid to "re-add" them, eh?
8634  //
8635  for (int32_t i = 0; i < theTempNym.GetIssuedNumCount(SERVER_ID);
8636  i++) {
8637  int64_t lTemp = theTempNym.GetIssuedNum(SERVER_ID, i);
8638  theNym.RemoveIssuedNum(server_->m_strServerID, lTemp);
8639  }
8640 
8641  // FINALLY after all that setup, we can do the balance agreement!!
8642  //
8643  const bool bVerifiedBalanceStatement =
8644  pBalanceItem->VerifyBalanceStatement(
8645  lTotalBeingAccepted, // <========================
8646  theNym, *pInbox, *pOutbox, theAccount, tranIn);
8647 
8648  // Here, add all the issued nums back (that had been temporarily
8649  // removed from theNym) that were stored on theTempNym for
8650  // safe-keeping.
8651  for (int32_t i = 0; i < theTempNym.GetIssuedNumCount(SERVER_ID);
8652  i++) {
8653  int64_t lTemp = theTempNym.GetIssuedNum(SERVER_ID, i);
8654  theNym.AddIssuedNum(server_->m_strServerID, lTemp);
8655  }
8656  // (They are removed for real at the bottom of this function, IF
8657  // everything is successful between now and then.)
8658 
8659  if (!bVerifiedBalanceStatement) {
8660  OTLog::vOutput(0, "Notary::NotarizeProcessInbox: ERROR "
8661  "verifying balance statement for transaction "
8662  "%ld.\n",
8663  tranIn.GetTransactionNum());
8664  }
8665  else // BALANCE AGREEMENT WAS SUCCESSFUL.......
8666  {
8667  pResponseBalanceItem->SetStatus(
8668  OTItem::acknowledgement); // the transaction agreement was
8669  // successful.
8670 
8671  // THE ABOVE LOOP WAS JUST A TEST RUN
8672  //
8673  // (TO VERIFY BALANCE AGREEMENT BEFORE WE BOTHERED TO RUN THIS
8674  // LOOP BELOW...)
8675 
8676  // loop through the items that make up the incoming transaction
8677  //
8678  for (auto& it_bigloop_two : tranIn.GetItemList()) {
8679  pItem = it_bigloop_two;
8680  OT_ASSERT_MSG(nullptr != pItem,
8681  "Pointer should not have been nullptr.");
8682 
8683  // We already handled this one (if we're even in this block
8684  // in the first place.)
8685  //
8686  if (OTItem::balanceStatement == pItem->GetType()) {
8687  continue;
8688  }
8689 
8690  // If the client sent an accept item, (or reject/dispute)
8691  // then let's process it.
8692  if ((OTItem::request == pItem->GetStatus()) &&
8694  pItem->GetType()) || // Accepting notice of market
8695  // trade or payment processing.
8696  // (Original in Cron Receipt.)
8697  // (OTItem::disputeCronReceipt
8699  pItem->GetType()) || // Accepted item receipt (cheque,
8700  // transfer)
8702  pItem->GetType()) || // Accepting notice of pending
8703  // transfer
8705  pItem->GetType()) || // Accepting finalReceipt
8707  pItem->GetType()) // Accepting basketReceipt
8708  )) {
8709  // The response item will contain a copy of the "accept"
8710  // request.
8711  // So I'm just setting aside a copy now for those
8712  // purposes later.
8713  strInReferenceTo.Release();
8714  pItem->SaveContractRaw(strInReferenceTo);
8715 
8716  OTItem::itemType theReplyItemType;
8717  switch (pItem->GetType()) {
8718  case OTItem::acceptPending:
8719  theReplyItemType = OTItem::atAcceptPending;
8720  break;
8721  case OTItem::rejectPending:
8722  theReplyItemType = OTItem::atRejectPending;
8723  break;
8725  theReplyItemType = OTItem::atAcceptCronReceipt;
8726  break;
8728  theReplyItemType = OTItem::atDisputeCronReceipt;
8729  break;
8731  theReplyItemType = OTItem::atAcceptItemReceipt;
8732  break;
8734  theReplyItemType = OTItem::atDisputeItemReceipt;
8735  break;
8737  theReplyItemType = OTItem::atAcceptFinalReceipt;
8738  break;
8740  theReplyItemType = OTItem::atDisputeFinalReceipt;
8741  break;
8743  theReplyItemType = OTItem::atAcceptBasketReceipt;
8744  break;
8746  theReplyItemType = OTItem::atDisputeBasketReceipt;
8747  break;
8748  default:
8749  OTLog::Error("Should never happen.\n");
8750  theReplyItemType =
8751  OTItem::error_state; // should never happen
8752  // based on above 'if'
8753  // statement.
8754  break; // saving this anyway just cause it's
8755  // cleaner.
8756  }
8757 
8758  // Server response item being added to server response
8759  // transaction (tranOut)
8760  // They're getting SOME sort of response item.
8761 
8762  pResponseItem = OTItem::CreateItemFromTransaction(
8763  tranOut, theReplyItemType);
8764  pResponseItem->SetStatus(
8765  OTItem::rejection); // the default.
8766  pResponseItem->SetReferenceString(
8767  strInReferenceTo); // the response item carries a
8768  // copy of what it's responding
8769  // to.
8770  pResponseItem->SetReferenceToNum(
8771  pItem->GetTransactionNum());
8772  pResponseItem->SetNumberOfOrigin(*pItem);
8773 
8774  tranOut.AddItem(*pResponseItem); // the Transaction's
8775  // destructor will
8776  // cleanup the item. It
8777  // "owns" it now.
8778 
8779  // Need to load the Inbox first, in order to look up the
8780  // transaction that
8781  // the client is accepting. This is possible because the
8782  // client has included
8783  // the transaction number. I'll just look it up in his
8784  // inbox and then
8785  // process it.
8786  // theAcctID is the ID on the client Account that was
8787  // passed in.
8788  OTLedger theInbox(USER_ID, ACCOUNT_ID, SERVER_ID);
8789 
8790  OTTransaction* pServerTransaction = nullptr;
8791 
8792  if (!theInbox.LoadInbox()) {
8793  OTLog::Error(
8794  "Error loading inbox during processInbox\n");
8795  }
8796  else if (false ==
8797  theInbox.VerifyAccount(
8798  server_->m_nymServer)) {
8799  OTLog::Error(
8800  "Error verifying inbox during processInbox\n");
8801  }
8802  //
8803  // Warning! In the case of a
8804  // OTTransaction::paymentReceipt or
8805  // OTTransaction::marketReceipt,
8806  // the "in reference to" string will NOT contain an
8807  // OTItem at all, but an OTPaymentPlan or
8808  // an OTTrade!! Also, a paymentReceipt might be for a
8809  // smart contract, in which case there's
8810  // a smartcontract inside, instead of a payment plan! I
8811  // handle these cases first, here:
8812  else if ( // MARKET RECEIPT, or PAYMENT RECEIPT.....
8814  pItem->GetType()) // This is checked
8815  // above, but just
8816  // keeping this safe.
8817  ) // especially in case this block moves
8818  // or is used elsewhere.
8819  &&
8820  (nullptr !=
8821  (pServerTransaction = theInbox.GetTransaction(
8822  pItem->GetReferenceToNum()))) &&
8824  pServerTransaction->GetType()) ||
8826  pServerTransaction->GetType()))) {
8827  // pItem contains the current user's attempt to
8828  // accept the Receipt
8829  // represented by pServerTransaction. Therefore we
8830  // have the user's
8831  // item AND the receipt he is trying to accept.
8832 
8833  pServerTransaction->DeleteBoxReceipt(
8834  theInbox); // faster.
8835  theInbox.RemoveTransaction(
8836  pServerTransaction->GetTransactionNum());
8837 
8838  theInbox.ReleaseSignatures();
8839  theInbox.SignContract(server_->m_nymServer);
8840  theInbox.SaveContract();
8841  theAccount.SaveInbox(theInbox);
8842  theAccount.ReleaseSignatures();
8843  theAccount.SignContract(server_->m_nymServer);
8844  theAccount.SaveContract();
8845  theAccount.SaveAccount();
8846 
8847  // Now we can set the response item as an
8848  // acknowledgement instead of the default
8849  // (rejection)
8850  pResponseItem->SetStatus(OTItem::acknowledgement);
8851  }
8852  else if ( // FINAL RECEIPT
8854  pItem->GetType()) // This is checked
8855  // above, but just
8856  // keeping this safe.
8857  ) // especially in case this block moves
8858  // or is used elsewhere.
8859  &&
8860  (nullptr !=
8861  (pServerTransaction = theInbox.GetTransaction(
8862  pItem->GetReferenceToNum()))) &&
8864  pServerTransaction->GetType()))) {
8865  // pItem contains the current user's attempt to
8866  // accept the Receipt
8867  // represented by pServerTransaction. Therefore we
8868  // have the user's
8869  // item AND the receipt he is trying to accept.
8870 
8871  pServerTransaction->DeleteBoxReceipt(
8872  theInbox); // faster.
8873  theInbox.RemoveTransaction(
8874  pServerTransaction->GetTransactionNum());
8875 
8876  theInbox.ReleaseSignatures();
8877  theInbox.SignContract(server_->m_nymServer);
8878  theInbox.SaveContract();
8879  theAccount.SaveInbox(theInbox);
8880  theAccount.ReleaseSignatures();
8881  theAccount.SignContract(server_->m_nymServer);
8882  theAccount.SaveContract();
8883  theAccount.SaveAccount();
8884 
8885  // Now we can set the response item as an
8886  // acknowledgement instead of the default
8887  // (rejection)
8888  pResponseItem->SetStatus(OTItem::acknowledgement);
8889  }
8890  else if ( // BASKET RECEIPT
8892  pItem->GetType()) // This is checked
8893  // above, but just
8894  // keeping this safe.
8895  ) // especially in case this block moves
8896  // or is used elsewhere.
8897  &&
8898  (nullptr !=
8899  (pServerTransaction = theInbox.GetTransaction(
8900  pItem->GetReferenceToNum()))) &&
8902  pServerTransaction->GetType()))) {
8903  // pItem contains the current user's attempt to
8904  // accept the Receipt
8905  // represented by pServerTransaction. Therefore we
8906  // have the user's
8907  // item AND the receipt he is trying to accept.
8908 
8909  pServerTransaction->DeleteBoxReceipt(
8910  theInbox); // faster.
8911  theInbox.RemoveTransaction(
8912  pServerTransaction->GetTransactionNum());
8913 
8914  theInbox.ReleaseSignatures();
8915  theInbox.SignContract(server_->m_nymServer);
8916  theInbox.SaveContract();
8917  theAccount.SaveInbox(theInbox);
8918  theAccount.ReleaseSignatures();
8919  theAccount.SignContract(server_->m_nymServer);
8920  theAccount.SaveContract();
8921  theAccount.SaveAccount();
8922 
8923  // Now we can set the response item as an
8924  // acknowledgement instead of the default
8925  // (rejection)
8926  pResponseItem->SetStatus(OTItem::acknowledgement);
8927  }
8928 
8929  // Careful here. I'm looking up the original
8930  // transaction number (1, say) which is stored
8931  // in my inbox as a "in reference to" on transaction
8932  // number 41. (Which is a pending transaction
8933  // or receipt
8934  // that the server created in my inbox, and only REFERS
8935  // to the original transaction, but is not
8936  // the original transaction in and of itself.)
8937  //
8938  // In other words, in this case below, I am looking for
8939  // the transaction in the Inbox
8940  // that REFERS to the same transaction that the accept
8941  // item REFERS to. That process, necessary
8942  // for pending transactions and cheque receipts, is NOT
8943  // the case above, with receipts from cron.
8944  else if (((OTItem::acceptItemReceipt ==
8945  pItem->GetType()) // acceptItemReceipt
8946  // includes checkReceipt
8947  // and transferReceipts.
8948  ||
8950  pItem->GetType()) // acceptPending includes
8951  // checkReceipts. Because
8952  // they are
8953  ) &&
8954  (nullptr !=
8955  (pServerTransaction = theInbox.GetTransaction(
8956  pItem->GetReferenceToNum()))) &&
8958  pServerTransaction
8959  ->GetType()) || // pending transfer.
8961  pServerTransaction->GetType()) || // transfer
8962  // receipt.
8964  pServerTransaction->GetType()) || // voucher
8965  // receipt.
8967  pServerTransaction->GetType()) // cheque
8968  // receipt is
8969  // down here
8970  // in the
8971  // pending
8972  // section,
8973  ) // because this is where an OTItem is loaded
8974  // up (since it
8975  ) // originated with a deposit transaction, not
8976  // a cron receipt.)
8977  {
8978  // The accept item will come with the transaction
8979  // number that
8980  // it's referring to. So we'll just look up that
8981  // transaction
8982  // in the inbox, and now that it's been accepted,
8983  // we'll process it.
8984 
8985  // At this point, pItem points to the client's
8986  // attempt to accept pServerTransaction
8987  // and pServerTransaction is the server's created
8988  // transaction in my inbox that contains
8989  // the original item (from the sender) as the
8990  // "referenced to" object. So let's extract
8991  // it.
8992  OTString strOriginalItem;
8993  pServerTransaction->GetReferenceString(
8994  strOriginalItem);
8995 
8996  std::unique_ptr<OTItem> pOriginalItem(
8998  strOriginalItem, SERVER_ID,
8999  pServerTransaction->GetReferenceToNum()));
9000 
9001  if (nullptr != pOriginalItem) {
9002 
9003  // What are we doing in this code?
9004  //
9005  // I need to accept various items that are
9006  // sitting in my inbox, such as:
9007  //
9008  // -- transfers waiting to be accepted (or
9009  // rejected.)
9010  //
9011  // -- cheque deposit receipts waiting to be
9012  // accepted (they cannot be rejected.)
9013  //
9014  // -- transfer receipts waiting to be accepted
9015  // (they cannot be rejected.)
9016 
9017  //
9018  // ONLY in the case of pending transfers also do
9019  // I need to mess around with my account,
9020  // and the sender's inbox and outbox. In the
9021  // other cases, I merely need to remove
9022  // the item from my inbox.
9023  // Although when 'accepting the reject', I do
9024  // need to take the money back into
9025  // my inbox...
9026 
9027  // The depositCheque request OTItem is saved as
9028  // a "in reference to" field
9029  // on the inbox chequeReceipt transaction.
9030 
9031  // Therefore, if I am processing an
9032  // acceptPending item from the client,
9033  // for accepting a chequeReceipt Transaction
9034  // that's in his inbox, and
9035  // the original item (that the receipt is for)
9036  // is a depositCheque,
9037  // then I can go ahead and clear it from his
9038  // inbox.
9039 
9040  // The below block only executes for ACCEPTING a
9041  // CHEQUE deposit receipt, or
9042  // for 'Accepting an ACCEPT.'
9043  //
9044  // I can't 'Accept a REJECT' without also
9045  // transferring the rejected money back into
9046  // my own account. And that means fiddling with
9047  // my account, and that means it will
9048  // be in a different block of code than this
9049  // one.
9050  //
9051  // Whereas with accepting a cheque deposit
9052  // receipt, or accepting an accepted transfer
9053  // notice,
9054  // in both of those cases, my account balance
9055  // doesn't change at all. I just need to accept
9056  // those notices in order to get them out of my
9057  // inbox. So that's the simplest case, and it's
9058  // handled by THIS block of code:
9059  //
9061  pItem->GetType()) &&
9063  pServerTransaction->GetType()) &&
9065  pOriginalItem->GetType())) ||
9067  pServerTransaction->GetType()) ||
9069  pServerTransaction->GetType())) &&
9071  pOriginalItem->GetType())))) { // (The
9072  // funds
9073  // are
9074  // already
9075  // paid
9076  // out...)
9077  // pItem contains the current user's attempt
9078  // to accept the
9079  // ['depositCheque' OR 'acceptPending']
9080  // located in theOriginalItem.
9081  // Now we have the user's item and the item
9082  // he is trying to accept.
9083 
9084  pServerTransaction->DeleteBoxReceipt(
9085  theInbox); // faster.
9086  theInbox.RemoveTransaction(
9087  pServerTransaction
9088  ->GetTransactionNum());
9089  theInbox.ReleaseSignatures();
9090  theInbox.SignContract(server_->m_nymServer);
9091  theInbox.SaveContract();
9092  theAccount.SaveInbox(theInbox);
9093  theAccount.ReleaseSignatures();
9094  theAccount.SignContract(
9095  server_->m_nymServer);
9096  theAccount.SaveContract();
9097  theAccount.SaveAccount();
9098 
9099  // Now we can set the response item as an
9100  // acknowledgement instead of the default
9101  // (rejection)
9102  pResponseItem->SetStatus(
9104 
9105  // Don't I need to remove from
9106  // responsibility list?
9107  // No, because that is done at the bottom of
9108  // the function.
9109  //
9110  } // its type is OTItem::acceptPending or
9111  // OTItem::depositCheque
9112 
9113  // TODO: 'Accept a REJECT' -- NEED TO PERFORM
9114  // THE TRANSFER OF FUNDS BACK TO THE SENDER'S
9115  // ACCOUNT WHEN TRANSFER IS REJECTED.
9116 
9117  // The below block only executes for ACCEPTING a
9118  // TRANSFER
9119  else if ((OTTransaction::pending ==
9120  pServerTransaction->GetType()) &&
9121  (OTItem::transfer ==
9122  pOriginalItem->GetType())) {
9123  // pItem contains the current user's attempt
9124  // to accept the transfer located in
9125  // theOriginalItem.
9126  // Now we have both items.
9127  OTIdentifier IDFromAccount(
9128  pOriginalItem->GetPurportedAccountID());
9129  OTIdentifier IDToAccount(
9130  pOriginalItem->GetDestinationAcctID());
9131 
9132  // I'm using the operator== because it
9133  // exists.
9134  // If the ID on the "To" account from the
9135  // original transaction does not
9136  // match the Acct ID of the client trying to
9137  // accept the transaction...
9138  if (!(ACCOUNT_ID == IDToAccount)) {
9139  OTLog::Error(
9140  "Error: Destination account ID on "
9141  "the transaction does not match "
9142  "account ID of client transaction "
9143  "item.\n");
9144  }
9145 
9146  // The 'from' outbox is loaded to remove the
9147  // outgoing transfer, since it has been
9148  // accepted.
9149  // The 'from' inbox is loaded in order to
9150  // put a notice of this acceptance for the
9151  // sender's records.
9152  OTLedger theFromOutbox(
9153  IDFromAccount,
9154  SERVER_ID), // Sender's *OUTBOX*
9155  theFromInbox(
9156  IDFromAccount,
9157  SERVER_ID); // Sender's *INBOX*
9158 
9159  bool bSuccessLoadingInbox =
9160  theFromInbox.LoadInbox();
9161  bool bSuccessLoadingOutbox =
9162  theFromOutbox.LoadOutbox();
9163 
9164  // THE FROM INBOX -- We are adding an item
9165  // here (acceptance of transfer),
9166  // so we will create this inbox if we have
9167  // to, so we can add that record to it.
9168 
9169  if (true == bSuccessLoadingInbox)
9170  bSuccessLoadingInbox =
9171  theFromInbox.VerifyAccount(
9172  server_->m_nymServer);
9173  else
9174  OTLog::Error("ERROR missing 'from' "
9175  "inbox in "
9176  "Notary::"
9177  "NotarizeProcessInbox.\n");
9178  // THE FROM OUTBOX -- We are removing an
9179  // item, so this outbox SHOULD already
9180  // exist.
9181 
9182  if (true == bSuccessLoadingOutbox)
9183  bSuccessLoadingOutbox =
9184  theFromOutbox.VerifyAccount(
9185  server_->m_nymServer);
9186  else // If it does not already exist, that
9187  // is an error condition. For now, log
9188  // and fail.
9189  OTLog::Error("ERROR missing 'from' "
9190  "outbox in "
9191  "Notary::"
9192  "NotarizeProcessInbox.\n");
9193  if (!bSuccessLoadingInbox ||
9194  false == bSuccessLoadingOutbox) {
9195  OTLog::Error("ERROR loading 'from' "
9196  "inbox or outbox in "
9197  "Notary::"
9198  "NotarizeProcessInbox.\n");
9199  }
9200  else {
9201  // Generate a new transaction number for
9202  // the sender's inbox (to notice him of
9203  // acceptance.)
9204  int64_t lNewTransactionNumber = 0;
9205  server_->transactor_
9207  server_->m_nymServer,
9208  lNewTransactionNumber,
9209  false); // bStoreTheNumber =
9210  // false
9211 
9212  // Generate a new transaction... (to
9213  // notice the sender of acceptance.)
9214  OTTransaction* pInboxTransaction =
9216  theFromInbox,
9218  lNewTransactionNumber);
9219 
9220  if (nullptr == pInboxTransaction)
9221  OT_FAIL;
9222 
9223  // Here we give the sender (by dropping
9224  // into his inbox) a copy of my
9225  // acceptItem (for
9226  // his transfer), including the
9227  // transaction number of my acceptance
9228  // of his transfer.
9229  //
9230  pInboxTransaction->SetReferenceString(
9231  strInReferenceTo);
9232  pInboxTransaction->SetReferenceToNum(
9233  pItem
9234  ->GetTransactionNum()); // Right
9235  // now
9236  // this
9237  // has
9238  // the
9239  // 'accept
9240  // the
9241  // transfer'
9242  // transaction
9243  // number.
9244  // It could be changed to the original
9245  // transaction number, as a better
9246  // receipt for the original sender.
9247  // TODO? Decisions....
9248 
9249  pInboxTransaction->SetNumberOfOrigin(
9250  *pItem);
9251 
9252  // Now we have created a new transaction
9253  // from the server to the sender's inbox
9254  // Let's sign it and add to his inbox.
9255  pInboxTransaction->ReleaseSignatures();
9256  pInboxTransaction->SignContract(
9257  server_->m_nymServer);
9258  pInboxTransaction->SaveContract();
9259 
9260  // At this point I have theInbox ledger,
9261  // theFromOutbox ledger, theFromINBOX
9262  // ledger,
9263  // and theAccount. So I should remove
9264  // the appropriate item from each
9265  // ledger, and
9266  // add the acceptance to the sender's
9267  // inbox, and credit the account....
9268 
9269  // First try to credit the amount to the
9270  // account...
9271  if (theAccount.Credit(
9272  pOriginalItem->GetAmount())) {
9273  // Add a transfer receipt to the
9274  // sender's inbox, containing the
9275  // "accept" transaction as the ref
9276  // string.
9277  // (to notify him that his transfer
9278  // was accepted; once he accepts it,
9279  // the trans# can be removed from
9280  // his issued list.)
9281  //
9282  theFromInbox.AddTransaction(
9283  *pInboxTransaction);
9284 
9285  // The original item carries the
9286  // transaction number that the
9287  // original
9288  // sender used to generate the
9289  // transfer in the first place. This
9290  // is the number
9291  // by which that transaction is
9292  // available in the sender's outbox.
9293  //
9294  // Then ANOTHER transaction was
9295  // created, by the server, in order
9296  // to put
9297  // a pending transfer into the
9298  // recipient's inbox. This has its
9299  // own transaction
9300  // number, generated by the server
9301  // at that time.
9302  //
9303  // So we remove the original
9304  // transfer from the sender's outbox
9305  // using the
9306  // transaction number on the
9307  // original item, and we remove the
9308  // pending transfer
9309  // from the recipient's inbox using
9310  // the transaction number from the
9311  // pending
9312  // transaction.
9313 
9314  // UPDATE: These two transactions
9315  // correspond to each other, so I am
9316  // now creating
9317  // them with the same transaction
9318  // number. As you can see, this
9319  // makes them easy
9320  // to remove as well.
9321 
9322  pServerTransaction
9323  ->DeleteBoxReceipt(
9324  theFromOutbox); // faster.
9325  theFromOutbox.RemoveTransaction(
9326  pServerTransaction
9327  ->GetTransactionNum());
9328 
9329  pServerTransaction
9330  ->DeleteBoxReceipt(
9331  theInbox); // faster.
9332  theInbox.RemoveTransaction(
9333  pServerTransaction
9334  ->GetTransactionNum());
9335 
9336  // NOTICE BTW, warning: Notice that
9337  // the box receipts are marked for
9338  // deletion
9339  // the instant they are removed from
9340  // their respective boxes.
9341  // Meanwhile, the client
9342  // may not have actually DOWNLOADED
9343  // those box receipts. Once they are
9344  // ACTUALLY
9345  // deleted, then client will never
9346  // have the chance. It's assumed
9347  // that client doesn't
9348  // care, since the receipts are
9349  // already out of his box.
9350 
9351  theFromInbox.ReleaseSignatures();
9352  theFromOutbox.ReleaseSignatures();
9353 
9354  theFromInbox.SignContract(
9355  server_->m_nymServer);
9356  theFromOutbox.SignContract(
9357  server_->m_nymServer);
9358 
9359  theFromInbox.SaveContract();
9360  theFromOutbox.SaveContract();
9361 
9362  theFromInbox.SaveInbox();
9363  theFromOutbox.SaveOutbox();
9364 
9365  // Release any signatures that were
9366  // there before (Old ones won't
9367  // verify anymore anyway, since the
9368  // content has changed.)
9369  theInbox.ReleaseSignatures();
9370  theInbox.SignContract(
9371  server_->m_nymServer);
9372  theInbox.SaveContract();
9373  theAccount.SaveInbox(theInbox);
9374  theAccount.ReleaseSignatures();
9375  theAccount.SignContract(
9376  server_->m_nymServer);
9377  theAccount.SaveContract();
9378  theAccount.SaveAccount();
9379 
9380  // Now we can set the response item
9381  // as an acknowledgement instead of
9382  // the default (rejection)
9383  // otherwise, if we never entered
9384  // this block, then it would still
9385  // be set to rejection, and the
9386  // new items would never have been
9387  // added to the inbox/outboxes, and
9388  // those files, along with
9389  // the account file, would never
9390  // have had their signatures
9391  // released, or been re-signed or
9392  // re-saved back to file. The debit
9393  // failed, so all of those other
9394  // actions would fail also.
9395  // BUT... if the message comes back
9396  // with acknowledgement--then all of
9397  // these actions must have
9398  // happened, and here is the
9399  // server's signature to prove it.
9400  // Otherwise you get no items and no
9401  // signature. Just a rejection item
9402  // in the response transaction.
9403  pResponseItem->SetStatus(
9405 
9406  // This goes with the call above to
9407  // theFromInbox.AddTransaction().
9408  // Adding a receipt to any box, for
9409  // real, requires saving the box
9410  // receipt
9411  // as well. (Which is stored in a
9412  // separate file.)
9413  //
9414  pInboxTransaction->SaveBoxReceipt(
9415  theFromInbox);
9416  }
9417  else {
9418  delete pInboxTransaction;
9419  pInboxTransaction = nullptr;
9420  OTLog::Error(
9421  "Unable to credit account in "
9422  "Notary::"
9423  "NotarizeProcessInbox.\n");
9424  }
9425  } // outbox was successfully loaded
9426  } // its type is OTItem::transfer
9427  } // loaded original item from string
9428  else {
9429  OTLog::Error("Error loading original item from "
9430  "inbox transaction.\n");
9431  }
9432  }
9433  else {
9434  OTLog::vError("Error finding original receipt or "
9435  "transfer that client is trying to "
9436  "accept: %ld\n",
9437  pItem->GetReferenceToNum());
9438  }
9439 
9440  // sign the response item before sending it back (it's
9441  // already been added to the transaction above)
9442  // Now, whether it was rejection or acknowledgement, it
9443  // is set properly and it is signed, and it
9444  // is owned by the transaction, who will take it from
9445  // here.
9446  pResponseItem->SignContract(server_->m_nymServer);
9447  pResponseItem->SaveContract();
9448  }
9449  else {
9450  OTString strItemType;
9451  pItem->GetTypeString(strItemType);
9452 
9453  OTLog::vError("Notary::%s: Error, unexpected "
9454  "OTItem::itemType: %s\n",
9455  __FUNCTION__, strItemType.Get());
9456  } // if type == ACCEPT, REJECT, DISPUTE
9457  } // for LOOP (each item)
9458  } // else (balance agreement verified.)
9459  } // else bSuccessFindingAllTransactions = true
9460  } // Balance Agreement item found.
9461 
9462  // I put this here so it's signed/saved whether the balance agreement itself
9463  // was successful OR NOT.
9464  // (Or whether it even existed or not.)
9465  //
9466  pResponseBalanceItem->ReleaseSignatures();
9467  pResponseBalanceItem->SignContract(server_->m_nymServer);
9468  pResponseBalanceItem->SaveContract();
9469  tranOut.ReleaseSignatures();
9470  tranOut.SignContract(server_->m_nymServer);
9471  tranOut.SaveContract();
9472  OTString strPath; // SAVE THE RECEIPT TO LOCAL STORAGE (for dispute
9473  // resolution.)
9474 
9475  // On the server side, response will only have chance to succeed if balance
9476  // agreement succeeds first.
9477  // Therefore, you will never see successful response but failed balance,
9478  // since it would stop at the
9479  // balance and response itself would remain failed with no chance of
9480  // changing.
9481  //
9482  // Thus, "success" must be when balance succeeded and transaction succeeded,
9483  // and "failure" must be when balance succeeded but transaction failed.
9484  //
9485  // If NEITHER succeeded, then there is no point recording it to a file, now
9486  // is there?
9487 
9488  const OTString strAcctID(ACCOUNT_ID);
9489 
9490  if (tranOut.GetSuccess()) {
9491  // Balance agreement was a success, AND process inbox was a success.
9492  // Therefore, remove any relevant issued numbers from theNym (those he's
9493  // now officially no longer responsible for), and save.
9494  //
9495  for (int32_t i = 0; i < theTempNym.GetIssuedNumCount(SERVER_ID); i++) {
9496  int64_t lTemp = theTempNym.GetIssuedNum(SERVER_ID, i);
9497  theNym.RemoveIssuedNum(server_->m_nymServer, server_->m_strServerID,
9498  lTemp, false); // bSave = false (saved below)
9499  }
9500  // The Nym (server side) stores a list of all opening and closing cron
9501  // #s.
9502  // So when the number is released from the Nym, we also take it off that
9503  // list.
9504  //
9505  std::set<int64_t>& theIDSet = theNym.GetSetOpenCronItems();
9506  for (int32_t i = 0;
9507  i < theTempClosingNumNym.GetIssuedNumCount(SERVER_ID); i++) {
9508  int64_t lTemp = theTempClosingNumNym.GetIssuedNum(SERVER_ID, i);
9509  theIDSet.erase(lTemp); // now it's erased from within the Nym.
9510  }
9511  theNym.SaveSignedNymfile(server_->m_nymServer);
9512  bOutSuccess = true; // the processInbox was successful.
9513  strPath.Format((char*)"%s.success", strAcctID.Get());
9514  }
9515  else
9516  strPath.Format((char*)"%s.fail", strAcctID.Get());
9517 
9518  const char* szFoldername = OTFolders::Receipt().Get();
9519 
9520  // Save the receipt. (My outgoing transaction including the client's signed
9521  // request that triggered it.)
9522  tranOut.SaveContract(szFoldername, strPath.Get());
9523 }
static EXPORT void vError(const char *szError,...)
Definition: OTLog.cpp:800
static EXPORT OTTransaction * GenerateTransaction(const OTIdentifier &theUserID, const OTIdentifier &theAccountID, const OTIdentifier &theServerID, transactionType theType, int64_t lTransactionNum=0)
static EXPORT OTItem * CreateItemFromString(const OTString &strItem, const OTIdentifier &theServerID, int64_t lTransactionNumber)
Definition: OTItem.cpp:1473
bool issueNextTransactionNumber(OTPseudonym &nym, int64_t &txNumber, bool storeNumber=true)
Definition: Transactor.cpp:211
#define NYM_IS_ALLOWED(SZ_NYM_ID, BOOL_VAR_NAME)
Definition: Macros.hpp:146
static EXPORT OTItem * CreateItemFromTransaction(const OTTransaction &theOwner, OTItem::itemType theType, const OTIdentifier *pDestinationAcctID=nullptr)
Definition: OTItem.cpp:1451
static EXPORT void Error(const char *szError)
Definition: OTLog.cpp:831
static EXPORT const OTString & Receipt()
Definition: OTFolders.cpp:355
#define OT_ASSERT_MSG(x, s)
Definition: Assert.hpp:155
static bool __transact_process_inbox
#define OT_FAIL
Definition: Assert.hpp:139
EXPORT const char * Get() const
Definition: OTString.cpp:1045
static EXPORT void vOutput(int32_t nVerbosity, const char *szOutput,...)
Definition: OTLog.cpp:768
void opentxs::Notary::NotarizeProcessNymbox ( OTPseudonym theNym,
OTTransaction tranIn,
OTTransaction tranOut,
bool &  bOutSuccess 
)

The client may send multiple transactions in the ledger when he calls processNymbox. This function will be called for each of those. Each processNymbox transaction may contain multiple items accepting or rejecting certain transactions. The server acknowledges and notarizes those transactions accordingly. (And each of those transactions must be accepted or rejected in whole.)

Definition at line 7402 of file Notary.cpp.

7404 {
7405  // The outgoing transaction is an "atProcessNymbox", that is, "a reply to
7406  // the process nymbox request"
7407  tranOut.SetType(OTTransaction::atProcessNymbox);
7408  OTItem* pItem = nullptr;
7409  OTItem* pBalanceItem = tranIn.GetItem(OTItem::transactionStatement);
7410  OTItem* pResponseItem = nullptr;
7411  OTItem* pResponseBalanceItem = nullptr;
7412 
7413  // Grab the actual server ID from this object, and use it as the server ID
7414  // here.
7415  const OTIdentifier SERVER_ID(server_->m_strServerID), USER_ID(theNym);
7416  OTPseudonym theTempNym;
7417 
7418  OTLedger theNymbox(USER_ID, USER_ID, SERVER_ID);
7419  OTString strNymID(USER_ID);
7420 
7421  bool bSuccessLoadingNymbox = theNymbox.LoadNymbox();
7422 
7423  if (true == bSuccessLoadingNymbox)
7424  bSuccessLoadingNymbox = theNymbox.VerifyAccount(
7425  server_->m_nymServer); // make sure it's all good.
7426  pResponseBalanceItem = OTItem::CreateItemFromTransaction(
7428  pResponseBalanceItem->SetStatus(OTItem::rejection); // the default.
7429  tranOut.AddItem(*pResponseBalanceItem); // the Transaction's destructor will
7430  // cleanup the item. It "owns" it
7431  // now.
7432  bool bNymboxHashRegenerated = false;
7433  OTIdentifier NYMBOX_HASH; // In case the Nymbox hash is updated, we will
7434  // have the updated version here.
7435  if (!bSuccessLoadingNymbox) {
7437  0, "Notary::%s: Failed loading or verifying Nymbox for user:\n%s\n",
7438  __FUNCTION__, strNymID.Get());
7439  }
7440  else if (nullptr == pBalanceItem) {
7441  const OTString strTransaction(tranIn);
7442  OTLog::vOutput(0, "Notary::%s: No Transaction Agreement item found "
7443  "on this transaction %ld (required):\n\n%s\n\n",
7444  __FUNCTION__, tranIn.GetTransactionNum(),
7445  strTransaction.Get());
7446  }
7447  else {
7448  OTString strBalanceItem;
7449 
7450  pBalanceItem->SaveContractRaw(strBalanceItem);
7451 
7452  pResponseBalanceItem->SetReferenceString(
7453  strBalanceItem); // the response item carries a copy of what it's
7454  // responding to.
7455  pResponseBalanceItem->SetReferenceToNum(
7456  pBalanceItem->GetTransactionNum()); // This response item is IN
7457  // RESPONSE to tranIn's balance
7458  // agreement
7459 
7460  // The incoming transaction accepts various messages and transaction
7461  // numbers.
7462  // So when it's all finished, my list of transaction numbers will be
7463  // higher.
7464  //
7465  // I would like to not even process the whole giant loop below,
7466  // if I can verify here now that the transaction agreement is wrong.
7467  //
7468  // Thus I will actually loop through the acceptTransaction items in
7469  // tranIn, and then for each one, I'll
7470  // lookup the ACTUAL transaction in the nymbox, and get its ACTUAL
7471  // value. (And store them all up on a temp nym.)
7472  //
7473  // The ones being accepted will therefore be added to my Nym, so the
7474  // Transaction Statement will be signed
7475  // as if that is already the case. (So they'll match.)
7476  //
7477  // I need to add them all to the Nym, verify the transaction statement,
7478  // and then remove them again.
7479  // (which is why I stored them on a temp Nym :-) Then if it succeeds for
7480  // real, at the bottom of this function,
7481  // I'll go ahead and add them properly (so it adds them to both lists.)
7482 
7483  bool bSuccessFindingAllTransactions = true;
7484 
7485  for (auto& it : tranIn.GetItemList()) {
7486  pItem = it;
7487  OT_ASSERT_MSG(nullptr != pItem,
7488  "Pointer should not have been nullptr.");
7489 
7490  if (pItem->GetType() == OTItem::acceptTransaction) {
7491  OTTransaction* pTransaction =
7492  theNymbox.GetTransaction(pItem->GetReferenceToNum());
7493 
7494  if ((nullptr != pTransaction) &&
7495  (pTransaction->GetType() ==
7496  OTTransaction::blank)) // The user is referencing a blank
7497  // in the nymbox, which indeed is
7498  // actually there.
7499  {
7500  bSuccessFindingAllTransactions = true;
7501 
7502  OTNumList listNumbersNymbox, listNumbersUserItem;
7503 
7504  pItem->GetNumList(listNumbersUserItem);
7505  pTransaction->GetNumList(listNumbersNymbox);
7506 
7507  // MAKE SURE THEY MATCH. (Otherwise user could be signing
7508  // numbers that differ from the
7509  // actual ones in the Nymbox.)
7510  //
7511  if (!listNumbersNymbox.Verify(listNumbersUserItem))
7512  OTLog::Error(
7513  "Notary::NotarizeProcessNymbox: Failed "
7514  "verifying: The numbers on the actual blank "
7515  "transaction in the nymbox do not match the list "
7516  "of numbers sent over by the user.\n");
7517  else // INSTEAD of merely adding the TRANSACTION NUMBER of
7518  // the blank to the Nym,
7519  { // we actually add an entire list of numbers retrieved
7520  // from the blank, including
7521  // its main number.
7522  std::set<int64_t> theNumbers;
7523  listNumbersNymbox.Output(theNumbers);
7524 
7525  // Looping through the transaction numbers on the Nymbox
7526  // blank transaction.
7527  // (There's probably 20 of them.)
7528  //
7529  for (auto& it : theNumbers) {
7530  const int64_t lTransactionNumber = it;
7531  // (We don't add it if it's already there.)
7532  //
7533  if (false ==
7534  theNym.VerifyIssuedNum(server_->m_strServerID,
7535  lTransactionNumber)) {
7536  theNym.AddIssuedNum(server_->m_strServerID,
7537  lTransactionNumber);
7538  theTempNym.AddIssuedNum(
7539  server_->m_strServerID,
7540  lTransactionNumber); // so I can remove from
7541  // theNym after
7542  // VerifyTransactionStatement
7543  // call
7544  }
7545  else
7546  OTLog::vError("Notary::NotarizeProcessNymbox:"
7547  " tried to add an issued trans# "
7548  "(%ld) to a nym who "
7549  "ALREADY had that number...\n",
7550  lTransactionNumber);
7551  }
7552  }
7553  }
7554  else {
7555  bSuccessFindingAllTransactions = false;
7556  break;
7557  }
7558  }
7559  }
7560 
7561  // NOTICE: We're adding up all the new transaction numbers being added.
7562  // (OTItem::acceptTransaction)...
7563  // but we're NOT bothering with the ones being REMOVED
7564  // (OTItem::acceptFinalReceipt) here in NotarizeProecessNymbox.
7565  // Why not? BECAUSE THEY WERE ALREADY REMOVED. They were removed when
7566  // the Cron Item expired, or was canceled.
7567  // The finalReceipt notice that went into the Nymbox was ONLY A COURTESY
7568  // -- the NUMBER was ALREADY REMOVED.
7569  // Thus, we don't need to remove it now, although we DO need to add the
7570  // new transaction numbers (acceptTransaction).
7571  //
7572  // (Of course, I will still remove the finalReceipt from the Nymbox. I
7573  // just don't have to juggle any
7574  // transaction numbers on the NYM as a result of this.)
7575  //
7576 
7577  if (!bSuccessFindingAllTransactions) {
7578  OTLog::vOutput(0, "%s: transactions in processNymbox message do "
7579  "not match actual nymbox.\n",
7580  __FUNCTION__);
7581 
7582  // Remove all issued nums from theNym that are stored on theTempNym
7583  // HERE.
7584  for (int32_t i = 0; i < theTempNym.GetIssuedNumCount(SERVER_ID);
7585  i++) {
7586  int64_t lTemp = theTempNym.GetIssuedNum(SERVER_ID, i);
7587  theNym.RemoveIssuedNum(server_->m_strServerID, lTemp);
7588  }
7589  }
7590  // (else true == success finding all transaction...)
7591  //
7592  // VERIFY TRANSACTION STATEMENT!
7593  //
7594  else if (false ==
7595  pBalanceItem->VerifyTransactionStatement(
7596  theNym, tranIn, false)) // bIsRealTransaction=false (since
7597  // we're doing Nymbox) // <========
7598  {
7599  OTLog::vOutput(0, "%s: ERROR verifying transaction statement.\n",
7600  __FUNCTION__);
7601 
7602  // Remove all issued nums from theNym that are stored on theTempNym
7603  // HERE.
7604  for (int32_t i = 0; i < theTempNym.GetIssuedNumCount(SERVER_ID);
7605  i++) {
7606  int64_t lTemp = theTempNym.GetIssuedNum(SERVER_ID, i);
7607  theNym.RemoveIssuedNum(server_->m_strServerID, lTemp);
7608  }
7609  }
7610  else // TRANSACTION AGREEMENT WAS SUCCESSFUL.......
7611  {
7612  // Remove all issued nums from theNym that are stored on theTempNym
7613  // HERE.
7614  for (int32_t i = 0; i < theTempNym.GetIssuedNumCount(SERVER_ID);
7615  i++) {
7616  int64_t lTemp = theTempNym.GetIssuedNum(SERVER_ID, i);
7617  theNym.RemoveIssuedNum(server_->m_strServerID, lTemp);
7618  }
7619 
7620  pResponseBalanceItem->SetStatus(
7621  OTItem::acknowledgement); // the transaction statement was
7622  // successful.
7623 
7624  // THE ABOVE LOOP WAS JUST A TEST RUN
7625  //
7626  // (TO **VERIFY TRANSACTION STATEMENT** BEFORE WE BOTHERED TO RUN
7627  // THIS LOOP BELOW...)
7628  // (AND ALSO SO WE COULD GET THE LIST OF NUMBERS FOR THE STATEMENT
7629  // ONTO TEMP NYM.)
7630 
7631  // loop through the items that make up the incoming transaction, and
7632  // add them
7633  // to the Nym, and remove them from the Nymbox, as appropriate.
7634  //
7635  for (auto& it : tranIn.GetItemList()) {
7636  pItem = it;
7637  OT_ASSERT_MSG(nullptr != pItem,
7638  "Pointer should not have been nullptr.");
7639 
7640  // We already handled this one (if we're even in this block in
7641  // the first place.)
7642  //
7643  if (OTItem::transactionStatement == pItem->GetType()) {
7644  continue;
7645  }
7646 
7647  // If the client sent an accept item then let's process it.
7648  if ((OTItem::request == pItem->GetStatus()) &&
7650  pItem->GetType()) || // Clearing out a finalReceipt
7651  // notice.
7653  pItem->GetType()) || // Accepting new transaction number.
7655  pItem->GetType()) || // Accepted message.
7657  pItem->GetType()) // Accepted server notification.
7658  )) {
7659  OTString strInReferenceTo;
7660 
7661  // The response item will contain a copy of the "accept"
7662  // request.
7663  // So I'm just setting aside a copy now for those purposes
7664  // later.
7665  pItem->SaveContractRaw(strInReferenceTo);
7666 
7667  OTItem::itemType theReplyItemType;
7668  switch (pItem->GetType()) {
7670  theReplyItemType = OTItem::atAcceptFinalReceipt;
7671  break;
7673  theReplyItemType = OTItem::atAcceptTransaction;
7674  break;
7675  case OTItem::acceptMessage:
7676  theReplyItemType = OTItem::atAcceptMessage;
7677  break;
7678  case OTItem::acceptNotice:
7679  theReplyItemType = OTItem::atAcceptNotice;
7680  break;
7681  default:
7682  OTLog::Error("Should never happen.\n");
7683  theReplyItemType =
7684  OTItem::error_state; // should never happen based on
7685  // above 'if' statement.
7686  continue; // saving this anyway just cause it's cleaner.
7687  }
7688 
7689  // Server response item being added to server response
7690  // transaction (tranOut)
7691  // They're getting SOME sort of response item.
7692 
7693  pResponseItem = OTItem::CreateItemFromTransaction(
7694  tranOut, theReplyItemType);
7695  pResponseItem->SetStatus(OTItem::rejection); // the default.
7696  pResponseItem->SetReferenceString(
7697  strInReferenceTo); // the response item carries a copy
7698  // of what it's responding to.
7699  // pResponseItem->SetReferenceToNum(pItem->GetTransactionNum());
7700  // // This was just 0 every time, since Nymbox needs no
7701  // transaction numbers.
7702  pResponseItem->SetReferenceToNum(
7703  pItem->GetReferenceToNum()); // So the reference was
7704  // useless. I'm hoping to
7705  // change it to this and
7706  // make sure nothing
7707  // breaks.
7708  // ReferenceNum actually means you can match it up against
7709  // the request items, and also, that is where THEY store it.
7710  tranOut.AddItem(*pResponseItem); // the Transaction's
7711  // destructor will cleanup
7712  // the item. It "owns" it
7713  // now.
7714 
7715  OTTransaction* pServerTransaction = nullptr;
7716 
7717  if ((nullptr !=
7718  (pServerTransaction = theNymbox.GetTransaction(
7719  pItem->GetReferenceToNum()))) &&
7721  pServerTransaction->GetType()) || // finalReceipt
7722  // (notice that an
7723  // opening num was
7724  // closed.)
7726  pServerTransaction->GetType()) || // new transaction
7727  // number waiting to
7728  // be picked up.
7730  pServerTransaction->GetType()) || // message in the
7731  // nymbox
7733  pServerTransaction->GetType()) || // replyNotice
7734  // containing a
7735  // server
7736  // reply to a previous request.
7737  // (Some replies are so important,
7738  // this is used to make sure users
7739  // get them.)
7741  pServerTransaction->GetType()) || // successNotice
7742  // that you signed
7743  // out a
7744  // transaction#.
7746  pServerTransaction->GetType()) || // server
7747  // notification, in
7748  // the nymbox
7750  pServerTransaction->GetType()) // A financial
7751  // instrument sent from
7752  // another user.
7753  // (Nymbox=>PaymentInbox)
7754  )) {
7755  // the accept item will come with the transaction number
7756  // that
7757  // it's referring to. So we'll just look up that
7758  // transaction
7759  // in the nymbox, and now that it's been accepted, we'll
7760  // process it.
7761 
7762  // At this point, pItem points to the client's attempt
7763  // to accept pServerTransaction
7764  // and pServerTransaction is the server's created
7765  // transaction in my nymbox that might
7766  // have a message or transaction number on it I might
7767  // find useful.
7768 
7769  // What are we doing in this code?
7770  //
7771  // I need to accept various items that are sitting in my
7772  // nymbox, such as:
7773  //
7774  // -- transaction numbers waiting to be accepted (they
7775  // cannot be rejected.)
7776  //
7777  // -- messages waiting to be accepted (they cannot be
7778  // rejected.)
7779  //
7780 
7781  // The below block only executes for ACCEPTING a MESSAGE
7782  if ((OTItem::acceptMessage == pItem->GetType()) &&
7784  pServerTransaction->GetType())) {
7785  // pItem contains the current user's attempt to
7786  // accept the
7787  // ['message'] located in pServerTransaction.
7788  // Now we have the user's item and the item he is
7789  // trying to accept.
7790  pServerTransaction->DeleteBoxReceipt(
7791  theNymbox); // faster.
7792  theNymbox.RemoveTransaction(
7793  pServerTransaction->GetTransactionNum());
7794 
7795  theNymbox.ReleaseSignatures();
7796  theNymbox.SignContract(server_->m_nymServer);
7797  theNymbox.SaveContract();
7798  theNymbox.SaveNymbox();
7799 
7800  // Now we can set the response item as an
7801  // acknowledgement instead of the default
7802  // (rejection)
7803  pResponseItem->SetStatus(OTItem::acknowledgement);
7804  } // its type is OTItem::aacceptMessage
7805 
7806  // The below block only executes for ACCEPTING a NOTICE
7807  else if ((OTItem::acceptNotice == pItem->GetType()) &&
7809  pServerTransaction->GetType()) ||
7811  pServerTransaction->GetType()) ||
7813  pServerTransaction->GetType()) ||
7815  pServerTransaction->GetType()))) {
7816  // pItem contains the current user's attempt to
7817  // accept the
7818  // ['notice'] or replyNotice or successNotice or
7819  // instrumentNotice
7820  // located in pServerTransaction.
7821  // Now we have the user's item and the item he is
7822  // trying to accept.
7823 
7824  pServerTransaction->DeleteBoxReceipt(
7825  theNymbox); // faster.
7826  theNymbox.RemoveTransaction(
7827  pServerTransaction->GetTransactionNum());
7828 
7829  theNymbox.ReleaseSignatures();
7830  theNymbox.SignContract(server_->m_nymServer);
7831  theNymbox.SaveContract();
7832  theNymbox.SaveNymbox();
7833 
7834  // Now we can set the response item as an
7835  // acknowledgement instead of the default
7836  // (rejection)
7837  pResponseItem->SetStatus(OTItem::acknowledgement);
7838 
7839  } // its type is OTItem::acceptNotice
7840 
7841  // The below block only executes for ACCEPTING a
7842  // TRANSACTION NUMBER
7843  // It also places a success notice into the Nymbox, to
7844  // solve sync issues.
7845  // (We'll make SURE the client got the notice! Probably
7846  // should do this
7847  // for cash withdrawals as well...)
7848  else if ((OTItem::acceptTransaction ==
7849  pItem->GetType()) &&
7851  pServerTransaction->GetType())) {
7852  // Add the success notice to the Nymbox, so if the
7853  // Nym fails to see the server reply, he can still
7854  // get his
7855  // transaction # later, from the notice, instead of
7856  // going out of sync.
7857  //
7858  int64_t lSuccessNoticeTransNum = 0;
7859  bool bGotNextTransNum =
7860  server_->transactor_.issueNextTransactionNumber(
7861  server_->m_nymServer,
7862  lSuccessNoticeTransNum,
7863  false); // bool bStoreTheNumber = false
7864 
7865  if (!bGotNextTransNum) {
7866  lSuccessNoticeTransNum = 0;
7867  OTLog::Error("Error getting next transaction "
7868  "number in "
7869  "Notary::NotarizeProcessNymbox "
7870  "for OTTransaction::blank (for "
7871  "the successNotice)\n");
7872  }
7873  else {
7874  // Drop SUCCESS NOTICE in the Nymbox
7875  //
7876  OTTransaction* pSuccessNotice =
7878  theNymbox, OTTransaction::successNotice,
7879  lSuccessNoticeTransNum);
7880 
7881  if (nullptr !=
7882  pSuccessNotice) // The above has an
7883  // OT_ASSERT within,
7884  // but I just like
7885  // to check my
7886  // pointers.
7887  {
7888  // If I accepted blank trans#10, then this
7889  // successNotice is in reference to #10.
7890  //
7891  pSuccessNotice->SetReferenceToNum(
7892  pServerTransaction
7893  ->GetTransactionNum());
7894 
7895  // Contains a copy of the OTItem where I
7896  // actually accepted the blank transaction
7897  // #.
7898  // (which generated the notice in the first
7899  // place...)
7900  //
7901  pSuccessNotice->SetReferenceString(
7902  strInReferenceTo);
7903 
7904  OTNumList theOutput;
7905  pServerTransaction->GetNumList(
7906  theOutput); // now theOutput contains
7907  // the numlist from the
7908  // server-side nymbox's copy
7909  // of the blank. (containing
7910  // 20 transaction #s)
7911 
7912  pSuccessNotice->AddNumbersToTransaction(
7913  theOutput); // Now we add those numbers
7914  // to the success notice.
7915  // That way client can add
7916  // those numbers to his
7917  // issued and transaction
7918  // lists.
7919 
7920  pSuccessNotice->SignContract(
7921  server_->m_nymServer);
7922  pSuccessNotice->SaveContract();
7923 
7924  theNymbox.AddTransaction(
7925  *pSuccessNotice); // Add the
7926  // successNotice to
7927  // the nymbox. It
7928  // takes ownership.
7929 
7930  pSuccessNotice->SaveBoxReceipt(theNymbox);
7931  }
7932  }
7933  // pItem contains the current user's attempt to
7934  // accept the
7935  // transaction number located in pServerTransaction.
7936  // Now we have the user's item and the item he is
7937  // trying to accept.
7938 
7939  // Here we remove the blank transaction that was
7940  // just accepted.
7941  //
7942  pServerTransaction->DeleteBoxReceipt(
7943  theNymbox); // faster.
7944  theNymbox.RemoveTransaction(
7945  pServerTransaction->GetTransactionNum());
7946 
7947  theNymbox.ReleaseSignatures();
7948  theNymbox.SignContract(server_->m_nymServer);
7949  theNymbox.SaveContract();
7950  theNymbox.SaveNymbox(&NYMBOX_HASH);
7951 
7952  bNymboxHashRegenerated = true;
7953 
7954  // Now we can set the response item as an
7955  // acknowledgement instead of the default
7956  // (rejection)
7957  pResponseItem->SetStatus(OTItem::acknowledgement);
7958  }
7959 
7960  // The below block only executes for CLEARING a
7961  // finalReceipt
7962  // (an OPENING TRANSACTION NUMBER was already removed),
7963  // and this was
7964  // a notice that that had occurred. The client has seen
7965  // the notice and is
7966  // now clearing it from the box.
7967  else if ((OTItem::acceptFinalReceipt ==
7968  pItem->GetType()) &&
7970  pServerTransaction->GetType())) {
7971  // pItem contains the current user's attempt to
7972  // clear the
7973  // finalReceipt located in pServerTransaction.
7974  // Now we have the user's item and the item he is
7975  // trying to accept.
7976 
7977  pServerTransaction->DeleteBoxReceipt(
7978  theNymbox); // faster.
7979  theNymbox.RemoveTransaction(
7980  pServerTransaction->GetTransactionNum());
7981 
7982  theNymbox.ReleaseSignatures();
7983  theNymbox.SignContract(server_->m_nymServer);
7984  theNymbox.SaveContract();
7985  theNymbox.SaveNymbox(&NYMBOX_HASH);
7986 
7987  bNymboxHashRegenerated = true;
7988 
7989  // Now we can set the response item as an
7990  // acknowledgement instead of the default
7991  // (rejection)
7992  pResponseItem->SetStatus(OTItem::acknowledgement);
7993  }
7994  }
7995  else {
7996  OTLog::vError("Error finding original Nymbox "
7997  "transaction that client is trying to "
7998  "accept: %ld\n",
7999  pItem->GetReferenceToNum());
8000  }
8001 
8002  // sign the response item before sending it back (it's
8003  // already been added to the transaction above)
8004  // Now, whether it was rejection or acknowledgement, it is
8005  // set properly and it is signed, and it
8006  // is owned by the transaction, who will take it from here.
8007  pResponseItem->ReleaseSignatures();
8008  pResponseItem->SignContract(server_->m_nymServer);
8009  pResponseItem->SaveContract();
8010  }
8011  else {
8012  const int32_t nStatus = pItem->GetStatus();
8013  OTString strItemType;
8014  pItem->GetTypeString(strItemType);
8015 
8016  OTLog::vError("Error, unexpected item type (%s) and/or "
8017  "status (%d) in "
8018  "Notary::NotarizeProcessNymbox\n",
8019  strItemType.Get(), nStatus);
8020  }
8021  }
8022  }
8023  }
8024 
8025  pResponseBalanceItem->ReleaseSignatures();
8026  pResponseBalanceItem->SignContract(server_->m_nymServer);
8027  pResponseBalanceItem->SaveContract();
8028  tranOut.ReleaseSignatures();
8029  tranOut.SignContract(server_->m_nymServer);
8030  tranOut.SaveContract();
8031 
8032  if (bNymboxHashRegenerated) {
8033  theNym.SetNymboxHashServerSide(NYMBOX_HASH); // server-side
8034  theNym.SaveSignedNymfile(
8035  server_->m_nymServer); // todo: make objects like nym
8036  // saveable and dirty-able, so
8037  // they are only saved once and
8038  // not multiple times
8039  // redundantly.
8040  }
8041 
8042  OTString strPath;
8043 
8044  // On the server side, response will only have chance to succeed if balance
8045  // agreement succeeds first.
8046  // Therefore, you will never see successful response but failed balance,
8047  // since it would stop at the
8048  // balance and response itself would remain failed with no chance of
8049  // changing.
8050  //
8051  // Thus, "success" must be when balance succeeded and transaction succeeded,
8052  // and "failure" must be when balance succeeded but transaction failed.
8053  //
8054  // If NEITHER succeeded, then there is no point recording it to a file, now
8055  // is there?
8056 
8057  if ((nullptr != pResponseBalanceItem) &&
8058  (OTItem::acknowledgement == pResponseBalanceItem->GetStatus())) {
8059  if (tranOut.GetSuccess()) {
8060  // Transaction agreement was a success, AND process nymbox was a
8061  // success.
8062  // Therefore, add any new issued numbers to theNym, and save.
8063 
8064  theNym.HarvestIssuedNumbers(SERVER_ID, server_->m_nymServer,
8065  theTempNym, true); // bSave=true
8066 
8067  bOutSuccess = true; // the processNymbox was successful.
8068 
8069  strPath.Format((char*)"%s.success", strNymID.Get());
8070  }
8071  else
8072  strPath.Format((char*)"%s.fail", strNymID.Get());
8073 
8074  const char* szFoldername = OTFolders::Receipt().Get();
8075 
8076  tranOut.SaveContract(szFoldername, strPath.Get());
8077  }
8078 }
static EXPORT void vError(const char *szError,...)
Definition: OTLog.cpp:800
static EXPORT OTTransaction * GenerateTransaction(const OTIdentifier &theUserID, const OTIdentifier &theAccountID, const OTIdentifier &theServerID, transactionType theType, int64_t lTransactionNum=0)
bool issueNextTransactionNumber(OTPseudonym &nym, int64_t &txNumber, bool storeNumber=true)
Definition: Transactor.cpp:211
static EXPORT OTItem * CreateItemFromTransaction(const OTTransaction &theOwner, OTItem::itemType theType, const OTIdentifier *pDestinationAcctID=nullptr)
Definition: OTItem.cpp:1451
static EXPORT void Error(const char *szError)
Definition: OTLog.cpp:831
static EXPORT const OTString & Receipt()
Definition: OTFolders.cpp:355
#define OT_ASSERT_MSG(x, s)
Definition: Assert.hpp:155
EXPORT const char * Get() const
Definition: OTString.cpp:1045
static EXPORT void vOutput(int32_t nVerbosity, const char *szOutput,...)
Definition: OTLog.cpp:768
void opentxs::Notary::NotarizeSmartContract ( OTPseudonym nym,
OTAccount activatingAccount,
OTTransaction tranIn,
OTTransaction tranOut,
bool &  outSuccess 
)

Definition at line 4805 of file Notary.cpp.

4809 {
4810  // The outgoing transaction is an "atSmartContract", that is, "a reply to
4811  // the smartContract request"
4812  tranOut.SetType(OTTransaction::atSmartContract);
4813 
4814  OTItem* pItem = nullptr;
4815  OTItem* pBalanceItem = nullptr;
4816  OTItem* pResponseItem = nullptr;
4817  OTItem* pResponseBalanceItem = nullptr;
4818 
4819  // The incoming transaction may be sent to inboxes and outboxes, and it
4820  // will definitely be bundled in our reply to the user as well. Therefore,
4821  // let's grab it as a string.
4822  OTString strInReferenceTo;
4823  OTString strBalanceItem;
4824 
4825  // Grab the actual server ID from this object, and use it as the server ID
4826  // here.
4827  const OTIdentifier SERVER_ID(server_->m_strServerID),
4828  ACTIVATOR_USER_ID(theNym), SERVER_USER_ID(server_->m_nymServer),
4829  ACTIVATOR_ACCT_ID(theActivatingAccount), USER_ID(theNym);
4830  const OTString strUserID(USER_ID);
4831  pItem = tranIn.GetItem(OTItem::smartContract);
4832  pBalanceItem = tranIn.GetItem(OTItem::transactionStatement);
4833  pResponseItem =
4835  pResponseItem->SetStatus(OTItem::rejection); // the default.
4836  tranOut.AddItem(*pResponseItem); // the Transaction's destructor will
4837  // cleanup the item. It "owns" it now.
4838  pResponseBalanceItem = OTItem::CreateItemFromTransaction(
4840  pResponseBalanceItem->SetStatus(OTItem::rejection); // the default.
4841  tranOut.AddItem(*pResponseBalanceItem); // the Transaction's destructor will
4842  // cleanup the item. It "owns" it
4843  // now.
4844  if ((nullptr != pItem) &&
4845  (false == NYM_IS_ALLOWED(strUserID.Get(),
4847  OTLog::vOutput(0, "%s: User %s cannot do this transaction (All smart "
4848  "contracts are disallowed in server.cfg)\n",
4849  __FUNCTION__, strUserID.Get());
4850  }
4851  // For now, there should only be one of these smartContract items inside the
4852  // transaction.
4853  // So we treat it that way... I either get it successfully or not.
4854  else if ((nullptr == pItem) || (nullptr == pBalanceItem)) {
4855  OTLog::vError("%s: Error, expected OTItem::smartContract and "
4856  "OTItem::transactionStatement.\n",
4857  __FUNCTION__);
4858  }
4859  else {
4860  if (ACTIVATOR_ACCT_ID != pItem->GetPurportedAccountID()) {
4861  OTLog::vOutput(0, "%s: Error: Source account ID on the transaction "
4862  "does not match activator's account ID on the "
4863  "transaction item.\n",
4864  __FUNCTION__);
4865  }
4866  else if (false ==
4867  pBalanceItem->VerifyTransactionStatement(theNym, tranIn)) {
4868  OTLog::vOutput(0, "%s: Failed verifying transaction statement.\n",
4869  __FUNCTION__);
4870  }
4871  else {
4872  pResponseBalanceItem->SetStatus(
4873  OTItem::acknowledgement); // the transaction agreement was
4874  // successful.
4875 
4876  // The response item will contain a copy of the request item. So I
4877  // save it into a string
4878  // here so it can be saved into the "in reference to" field.
4879  pItem->SaveContractRaw(strInReferenceTo);
4880  pBalanceItem->SaveContractRaw(strBalanceItem);
4881 
4882  // Server response item being added to server response transaction
4883  // (tranOut)
4884  // They're getting SOME sort of response item.
4885 
4886  pResponseItem->SetReferenceString(
4887  strInReferenceTo); // the response item carries a copy of what
4888  // it's responding to.
4889  pResponseItem->SetReferenceToNum(
4890  pItem->GetTransactionNum()); // This response item is IN
4891  // RESPONSE to pItem and its Owner
4892  // Transaction.
4893 
4894  pResponseBalanceItem->SetReferenceString(
4895  strBalanceItem); // the response item carries a copy of what
4896  // it's responding to.
4897  pResponseBalanceItem->SetReferenceToNum(
4898  pItem->GetTransactionNum()); // This response item is IN
4899  // RESPONSE to pItem and its Owner
4900  // Transaction.
4901 
4902  // Also load up the smart contract from inside the transaction item.
4903  OTString strContract;
4904  pItem->GetAttachment(strContract);
4905  OTSmartContract* pContract = new OTSmartContract(SERVER_ID);
4906  OT_ASSERT(nullptr != pContract);
4907 
4908  // If we failed to load the smart contract...
4909  if ((false == pContract->LoadContractFromString(strContract))) {
4910  OTLog::vError(
4911  "%s: ERROR loading smart contract from string:\n\n%s\n\n",
4912  __FUNCTION__, strContract.Get());
4913  }
4914  else if (pContract->GetServerID() != SERVER_ID) {
4915  const OTString strWrongID(pContract->GetServerID());
4916  OTLog::vOutput(0, "%s: ERROR bad server ID (%s) on smart "
4917  "contract. Expected %s\n",
4918  __FUNCTION__, strWrongID.Get(),
4919  server_->m_strServerID.Get());
4920  }
4921  else {
4922  // CANCELING, or ACTIVATING?
4923  //
4924  OTIdentifier theCancelerNymID;
4925  const bool bCancelling =
4926  (pContract->IsCanceled() &&
4927  pContract->GetCancelerID(theCancelerNymID));
4928  const int64_t lFoundNum = pContract->GetTransactionNum();
4929  const int64_t lExpectedNum = pItem->GetTransactionNum();
4930  int64_t lFoundOpeningNum = 0;
4931  int64_t lFoundClosingNum = 0;
4932 
4933  OTIdentifier FOUND_USER_ID;
4934  OTIdentifier FOUND_ACCT_ID;
4935 
4936  if (!bCancelling) // ACTIVATING
4937  {
4939  0, "Attempting to activate smart contract...\n");
4940 
4941  lFoundOpeningNum = pContract->GetOpeningNum();
4942  lFoundClosingNum = pContract->GetClosingNum();
4943 
4944  FOUND_USER_ID = pContract->GetSenderUserID();
4945  FOUND_ACCT_ID = pContract->GetSenderAcctID();
4946  }
4947  else // CANCELING
4948  {
4949  OTLog::vOutput(0,
4950  "Attempting to cancel smart contract...\n");
4951 
4952  lFoundOpeningNum = pContract->GetOpeningNumber(
4953  theCancelerNymID); // See if there's an opening number
4954  // for the canceling Nym.
4955  lFoundClosingNum = pContract->GetClosingNumber(
4956  ACTIVATOR_ACCT_ID); // See if there's a closing number
4957  // for the current account.
4958 
4959  if (lFoundOpeningNum > 0) FOUND_USER_ID = theCancelerNymID;
4960  if (lFoundClosingNum > 0) FOUND_ACCT_ID = ACTIVATOR_ACCT_ID;
4961  }
4962 
4963  if (lFoundNum != lExpectedNum) {
4965  0, "%s: ERROR bad main opening transaction number on "
4966  "smart contract. Found: %ld Expected: %ld\n"
4967  "FYI, pItem->GetTransactionNum() is %ld.\n",
4968  __FUNCTION__, lFoundNum, lExpectedNum,
4969  pItem->GetTransactionNum());
4970  }
4971  else if (lFoundOpeningNum != lExpectedNum) {
4973  0, "%s: ERROR bad opening transaction number on smart "
4974  "contract. Found: %ld Expected: %ld\n",
4975  __FUNCTION__, lFoundOpeningNum, lExpectedNum);
4976  }
4977  else if (FOUND_USER_ID != ACTIVATOR_USER_ID) {
4978  const OTString strWrongID(ACTIVATOR_USER_ID);
4979  const OTString strRightID(FOUND_USER_ID);
4980  OTLog::vOutput(0, "%s: ERROR wrong user ID (%s) used while "
4981  "%s smart contract. Expected from "
4982  "contract: %s\n",
4983  __FUNCTION__, strWrongID.Get(),
4984  bCancelling ? "canceling" : "activating",
4985  strRightID.Get());
4986  }
4987  else if (FOUND_ACCT_ID != ACTIVATOR_ACCT_ID) {
4988  const OTString strSenderAcctID(FOUND_ACCT_ID),
4989  strActivatorAcctID(ACTIVATOR_ACCT_ID);
4990  OTLog::vOutput(0, "%s: ERROR wrong asset Acct ID used (%s) "
4991  "to %s smart contract. Expected from "
4992  "contract: %s\n",
4993  __FUNCTION__, strActivatorAcctID.Get(),
4994  bCancelling ? "cancel" : "activate",
4995  strSenderAcctID.Get());
4996  }
4997  // The transaction number opens the smart contract, but there
4998  // must also be a closing number for closing it.
4999  else if ((pContract->GetCountClosingNumbers() <
5000  1) || // the transaction number was verified before we
5001  // entered this function, so only the closing #
5002  // is left...
5003  !server_->transactor_.verifyTransactionNumber(
5004  theNym, lFoundClosingNum)) // Verify that it can
5005  // still be USED (not
5006  // closed... that's
5007  // VerifyIssuedNum())
5008  {
5009  OTLog::vOutput(0, "%s: ERROR: the Closing number %ld "
5010  "wasn't available for use while %s a "
5011  "smart contract.\n",
5012  __FUNCTION__, lFoundClosingNum,
5013  bCancelling ? "canceling" : "activating");
5014  }
5015  // NOTE: since theNym has ALREADY been substituted for the
5016  // Server's Nym by this point, if indeed they are the same Nym,
5017  // then I could probably just ALLOW the server to be a party to
5018  // a smart contract. It will definitely be on the "list of
5019  // nyms that are already loaded" due to the substitution. So
5020  // really it's just a matter of security review, and the below
5021  // block could be commented out (or not.) ALSO: If I'm going to
5022  // enforce this, then I need to do it for ALL parties, not just
5023  // the activator!
5024  else if ((pContract->GetSenderUserID() == SERVER_USER_ID) ||
5025  (nullptr !=
5026  pContract->FindPartyBasedOnNymAsAgent(
5027  server_->m_nymServer))) {
5029  0,
5030  "%s: ** SORRY ** but the server itself is NOT ALLOWED "
5031  "to be a party "
5032  "to any smart contracts. (Pending security review.)\n",
5033  __FUNCTION__);
5034  }
5035  //
5036  // VERIFY SMART CONTRACT
5037  /*
5038  -- Loop through all parties and load up the authorizing
5039  agent's Nym, if not already loaded, for each.
5040  -- Verify each party, that the authorizing agent is good, and
5041  verify his signature on the party's copy
5042  of the contract.
5043  -- Definitely during this, need to make sure that the contents
5044  of the signed version match the contents
5045  of the main version, for each signer.
5046  -- Verify that the authorizing agent actually has the opening
5047  transaction # for the party issued to him.
5048  -- EVEN IF VERIFICATION FAILS HALFWAY THOUGH, REMOVE that
5049  opening transaction # for each-and-every agent.
5050  (So he can't use it twice--leaving it as issued, but no longer
5051  as "available to be used on another
5052  transaction".) Otherwise, if verification failed halfway
5053  through, with half of the parties having their
5054  opening numbers already burned, and the other half not, then
5055  it would be impossible to tell, based on
5056  the failed message itself, which group YOU are in, and
5057  therefore whether YOU need to harvest that number
5058  back or not (in order to avoid going out-of-sync.) THEREFORE
5059  WE BURN ALL OPENING NUMBERS so the client API
5060  can just assume the opening number is burned, if the
5061  transaction ran at all. (And, as normal, if the
5062  transaction did NOT run at all, e.g. if the message failed
5063  before the transaction had a chance to run,
5064  then all opening numbers are still good, for all
5065  parties--including the activator.)
5066 
5067  -- NOTE: this means, if it succeeds, the opening numbers are
5068  marked as IN USE
5069  (RemoveTransactionNum but NOT RemoveIssuedNum.) But if it
5070  FAILS, then we also need to RemoveIssuedNum...
5071  So I'm adding that to VerifySmartContract.
5072 
5073  -- Next, loop through all the asset accounts...
5074  -- For each, get a pointer to the authorized agent and verify
5075  the CLOSING number for that asset acct.
5076  (AND mark that number as "used but still issued.") Again, do
5077  this for ALL asset accounts on the smart
5078  contract, even if some of them fail the verification process.
5079  (It's also okay to skip the accounts for
5080  parties who failed verification.) If anything fails, then at
5081  the very end, add the closing numbers back
5082  again as "available for use" on those nyms.
5083 
5084  -- Since we're looping through all the agents, and looping
5085  through all the asset accounts, and
5086  checking the agent for each asset account, then we might as
5087  well make sure that each agent is
5088  a legit agent for the party, and that each account has a legit
5089  agent lording over it.
5090  */
5091  else if (bCancelling && !pContract->VerifySignature(theNym)) {
5092  OTLog::vOutput(0, "%s: Failed verifying canceler signature "
5093  "while canceling smart contract.\n",
5094  __FUNCTION__);
5095  }
5096 
5097  // We let it run through the verifier here, even if we are
5098  // cancelling.
5099  // The reason is because this is where the various
5100  // opening/closing numbers
5101  // are burned/reserved/etc. So even cancellation needs this part
5102  // done.
5103  //
5104  else if (!pContract->VerifySmartContract(
5105  theNym, theActivatingAccount, server_->m_nymServer,
5106  true)) // bBurnTransNo=false by default, but here
5107  // we pass TRUE.
5108  {
5109  if (bCancelling) {
5110  tranOut.SetAsCancelled();
5111 
5112  OTLog::vOutput(0, "%s: Canceling a smart contract "
5113  "before it was ever even activated "
5114  "(at user's request.)\n",
5115  __FUNCTION__);
5116  }
5117  else
5119  0,
5120  "%s: This smart contract has FAILED to verify.\n",
5121  __FUNCTION__);
5122 
5123  /*
5124 
5125  ------ TODO: Smart Contracts -----------
5126 
5127  Done: Whenever a party confirms a smart contract (sending
5128  it on to the next party) then a copy of
5129  the smart contract should go into that party's
5130  paymentOutbox. Same thing if the party is the last
5131  one in the chain, and has activated it on to the server. A
5132  copy sits in the paymentOutbox until
5133  that smart contract is either successfully activated, or
5134  FAILS to activate.
5135 
5136  If a smart contract activates,
5137  OTAgreement::DropServerNoticeToNymbox already sends an
5138  'acknowledgment' notice to all parties.
5139 
5140  Done: If a smart contract fails to activate, it should
5141  ALSO send a notice ('rejection') to
5142  all parties.
5143 
5144  TODO: When a party receives a rejection notice in his
5145  Nymbox for a certain smart contract,
5146  he looks up that same smart contract in his paymentOutbox,
5147  HARVESTS THE CLOSING NUMBERS, and
5148  then moves the notice from his outpayments box to his
5149  recordBox.
5150  NOTE: the notice might be in his payments inbox
5151  (sometimes) instead of his outpayments box.
5152  Possibly even both. How so? See below. Point being: Need
5153  to check both, at this point.
5154 
5155  Until this is added, then clients will go out of sync on
5156  rejected smart contracts. (Not the kind
5157  of out-of-sync where they can't do any transactions, but
5158  rather, the kind where they have certain
5159  numbers signed out forever but then never use them on
5160  anything because their client thinks those
5161  numbers were already used on a smart contract somewhere,
5162  and without the above code they would
5163  never have clawed back those numbers.)
5164 
5165  MORE DETAILS:
5166 
5167  *** When I send a smart contract on to the next party,
5168  remember it's sitting in my payments inbox
5169  at first. When I confirm it, a copy goes into my
5170  outpayments box. Then when I actually SEND it, a
5171  copy goes into my outpayments box AGAIN. (This is already
5172  smart enough to remove this first copy,
5173  when this happens.) If I activate it (rather than sending
5174  it on, perhaps I'm the last one) then it's
5175  already in my outpayments box from the confirmation.
5176 
5177  BUT WHEN DO I REMOVE IT FROM THE payments *INBOX* ?
5178  Answer: when the successful server reply is
5179  received from the sendUserInstrument. What if I don't send
5180  it to another user? Perhaps I activate it.
5181  In that case, whether the activation succeeds or fails, I
5182  will get an acknowledgment (or rejection)
5183  notice in my Nymbox. Therefore I can harvest the numbers
5184  back when that notice is received (or not.)
5185  That will be from my outpayments box. But removing it from
5186  my INBOX should happen when I get the server
5187  response to the activation (just as when I get the server
5188  response to sendUserInstrument.)
5189  If I never tried to activate it, and never tried to send
5190  it to the next party, and never discarded it,
5191  then it should remain in my inbox, until I choose to do
5192  one of those things.
5193 
5194 
5195  *** The sent contract remains in the outPayments box
5196  until:
5197  A. Activated. When: When the acknowledgment of activation
5198  is received through the Nymbox.
5199  B. Failed activation. When: Rejection of activation
5200  received through the Nymbox.
5201  C. Expiration. Expired notices may be harvested from the
5202  outpayments box. After all,
5203  they were apparently never activated or even attempted,
5204  since either of those actions
5205  would have resulted in a rejection notice which would have
5206  already removed the outpayments
5207  box. So the transaction numbers can be harvested. BUT make
5208  sure you have latest version of
5209  files first, so you know for sure that the contract never
5210  really was activated or attempted.
5211 
5212  *** What if the incoming smart contract is discarded,
5213  instead of confirmed?
5214  This means it never goes into my outbox in the first
5215  place. It's in my inbox, then I discard it.
5216  Then what? In one scenario, the user simply throws it
5217  away. He removes it from the box and never
5218  notifies anyone. This is physically possible so we must
5219  consider it. In that case, it's still sitting
5220  in other people's outboxes, and will eventually expire,
5221  and then those people will just harvest back
5222  their transaction numbers. It's kind of rude not to notify
5223  them, but everything will still be OKAY.
5224  They also still have the power, since it hasn't been
5225  activated, to "false activate" it, which will fail
5226  since it's not fully-confirmed yet, and then the rejection
5227  notice will come through and remove it from
5228  their outboxes. All parties are notified in that case.
5229  The polite thing to do, instead of just discarding it,
5230  would be for me to do the same (false-activate it)
5231  meaning I activate it, but without signing it. And
5232  possibly putting some other "This must fail" indicator
5233  on the message, so the server doesn't waste a lot of time
5234  figuring that out. Then the failure causes all
5235  the parties who DID sign it, to get a rejection
5236  notification, and I can remove it from my payments inbox
5237  at
5238  that time, when they are all removing it from their
5239  outboxes.
5240 
5241  *** What if the incoming contract is discarded AFTER it
5242  was confirmed? From the outbox, meaning it hasn't
5243  been activated yet. Perhaps I sent someone a cheque that
5244  hasn't been cashed yet. Perhaps I sent someone
5245  a signed smart contract but they haven't activated it yet.
5246  Therefore I still have a chance to cancel it.
5247  I can't just discard it, since they can still deposit
5248  their copy whenever they want. But if I RUN IT THROUGH,
5249  then it will be INVALIDATED thereafter -- and if I beat
5250  them to the punch, then it will work. Of course, if
5251  they activate it, then I will get an activation notice,
5252  which will automatically remove it from my outbox.
5253  So I beat them to the punch, by activating / depositing it
5254  myself, which fails, and then we both get rejection
5255  notices. That removes it from my outbox, as well as the
5256  inbox of the guy who I had been stuck waiting on in
5257  the first place.
5258 
5259 
5260  WHY WAS IT in whichever box it was in? (Just curious.)
5261  Well...
5262  If inbox, because I discarded it without confirming, yet
5263  wanted to be nice and let people who
5264  had, harvest their numbers back. (Otherwise they'd still
5265  eventually expire.) If outpayments box,
5266  because I activated it (so it's in that box) and it's just
5267  legitimately a failed attempt on my
5268  part, or because I confirmed it and sent to the next guy,
5269  and he hasn't activated it yet, and
5270  I've changed my mind and wish to cancel it. Either way,
5271  once I do, I will get the notice (as will
5272  any other parties) and then it will be removed from that
5273  box (and placed in the records box.)
5274  Another scenario: It's removed from my inbox when some
5275  other confirming party "false activates" it
5276  in order to cancel it and remove it from his outbox. He
5277  HAD been sitting there waiting on me, while
5278  the notice sat in my inbox. But now that it's been
5279  invalidated at the server, I will get a rejection
5280  notice from the server which should remove the one that
5281  was sitting in my inbox, to the record box.
5282 
5283 
5284  ACTIONS:
5285 
5286  -- When successful "sendUserInstrument" server reply is
5287  received,
5288  remove that instrument from payments inbox. (If it's there
5289  -- it can be.)
5290 
5291  -- When party receives notice that smart contract has been
5292  activated,
5293  remove the instrument from outpayments box. (If it's there
5294  -- it can be.)
5295 
5296  -- When party receives notice that smart contract has
5297  failed activation attempt, then remove
5298  the instrument from payments inbox AND outpayments box.
5299  (If there -- could be for either.)
5300 
5301  Does this cover all cases?
5302 
5303  -- Any _sent_ instrument will properly be removed from the
5304  payments inbox.
5305  -- It will go into the outpayments box. Once it activates,
5306  it will be removed again from that box. (For all parties.)
5307  -- If it fails to activate, or if a party discards it from
5308  inbox (through a deliberate failed activation) or if a
5309  party
5310  discards it from the outbox (through a deliberate failed
5311  activation) either way, it will be removed from both
5312  boxes.
5313  -- If it expires while sitting in my inbox, my high-level
5314  API is responsible to remove it and harvest the numbers.
5315  -- It if expires while sitting in my outbox, my high-level
5316  API is responsible to remove it and harvest the numbers.
5317 
5318  It can be sent, discarded (from outbox, as a
5319  scramble-to-discard-it-before-next-guy-deposits it),
5320  discarded (from inbox,
5321  when I decide I won't sign it), it can be ignored until
5322  expiration (either box), and it can legitimately activate
5323  or fail
5324  to activate, and either way, all the parties who confirmed
5325  it will get a notice and harvest (if necessary.)
5326 
5327  THIS SEEMS TO COVER ALL CASES!
5328 
5329  One more thing, just noticed: Whether success or fail, the
5330  opening AND closing numbers are marked as "used but not
5331  closed"
5332  on the Nym's record. We do this above for all Nyms just
5333  doing verification, since we can't fail halfway through
5334  and have
5335  inconsistent results between them. (All or nothing.)
5336 
5337  THERFORE: 1. When the Nyms receive "SUCCESS" activating
5338  the smart contract, they ALL know that the opening AND
5339  closing
5340  numbers are marked off as used, and can only be closed
5341  thereafter through the final receipt. 2. When the Nyms
5342  receive
5343  FAILED activating the smart contract... Do they harvest
5344  the numbers back? NOT if they were all marked off already!
5345  So
5346  next, if failure here I need to mark them all as closed,
5347  right? Since we failed? And then the client side, when he
5348  gets
5349  the notice, he needs to mark them as closed as well. (NOT
5350  harvest them.) We could alternately mark them all as
5351  "still
5352  available" on the server side (or all closing numbers
5353  anyway) and mark all the opening numbers as closed. But
5354  whatever we
5355  do, the client side needs to do the same thing.
5356  The only time we harvest ALL the numbers is then when we
5357  haven't even sent it to the server yet? Otherwise we mark
5358  them
5359  as "used and not closed" (if success) or if failure, we
5360  mark them as: ????? Perhaps all still open except the
5361  main opening
5362  one? Or perhaps all the closing numbers are still
5363  available and the opening numbers are burned? Or just ALL
5364  numbers are
5365  burned? Which? Why?
5366 
5367  NOTE: I found the answer in the comments in
5368  OTSmartContract::VerifySmartContract. (And there are very
5369  good reasons
5370  involved for why I went the way that I did. Read it for
5371  those reasons.) Conclusion:
5372 
5373  If there is a failed activation attempt, then all parties
5374  get a notice, and all parties can CLOSE the opening
5375  number,
5376  which was burned, and they can HARVEST the closing
5377  numbers, which were made new again.
5378 
5379  But if the activation attempt succeeded, then all parties
5380  get a notice, and all parties will continue as they were:
5381  with the opening AND closing numbers marked as "Still
5382  issued but in use." Their opening numbers will not close
5383  until
5384  the smart contract is deactivated, and their closing
5385  numbers will not close until their final receipts have
5386  been closed.
5387  You might ask, "Then why send the notice, if the
5388  transaction numbers are already set up correctly on the
5389  client side?"
5390  The answer is, because the client still does things based
5391  on that notice. Like for example, it removes the confirmed
5392  copy of that smart contract from its outpayments box.
5393 
5394  */
5395 
5396  // DROP REJECTION NOTICE HERE TO ALL PARTIES....
5397  // SO THEY CAN CLAW BACK THEIR TRANSACTION #s....
5398  //
5399  int64_t lNewTransactionNumber = 0;
5400  server_->transactor_.issueNextTransactionNumber(
5401  server_->m_nymServer, lNewTransactionNumber, false);
5402 
5403  if (false ==
5404  pContract->SendNoticeToAllParties(
5405  false, server_->m_nymServer, SERVER_ID,
5406  lNewTransactionNumber,
5407  // // Each party has its own opening number. Handled
5408  // internally.
5409  strContract, nullptr, nullptr, &theNym)) {
5410  // NOTE: A party may deliberately try to activate a
5411  // smart contract without signing it.
5412  // (As a way of rejecting it.) This will cause rejection
5413  // notices to go to all the other
5414  // parties, allowing them to harvest back their closing
5415  // numbers.
5416  // Since that is expected to happen, that means if you
5417  // have 5 parties, and the 3rd one
5418  // "activates" the contract, then this piece of code
5419  // here will DEFINITELY fail to send
5420  // the rejection notice to the last 2 parties (since
5421  // they hadn't even signed the contract
5422  // yet.)
5423  //
5424  // (Since we expect that to normally happen, we don't
5425  // log an error here.)
5426  }
5427  } // smart contract is no good.
5428 
5429  // The smart contract is good...
5430  //
5431  // NOTIFY ALL PARTIES and ACTIVATE.
5432  //
5433  // This is important to notify first, because the hooks in
5434  // OTSmartContract::onActivate() could very
5435  // potentially trigger MORE receipts, and we want to make sure
5436  // the activation receipt comes first.
5437  //
5438  else {
5439  int64_t lNewTransactionNumber = 0;
5440  server_->transactor_.issueNextTransactionNumber(
5441  server_->m_nymServer, lNewTransactionNumber, false);
5442 
5443  if (false ==
5444  pContract->SendNoticeToAllParties(
5445  true, server_->m_nymServer, SERVER_ID,
5446  lNewTransactionNumber,
5447  // // Each party has its own opening number. Handled
5448  // internally.
5449  strContract, nullptr, nullptr, &theNym)) {
5451  0, "%s: Failed notifying parties while trying to "
5452  "activate smart contract: %ld.\n",
5453  __FUNCTION__, pContract->GetTransactionNum());
5454  }
5455  // Add it to Cron...
5456  else if (server_->m_Cron.AddCronItem(
5457  *pContract, &theNym, true,
5458  OTTimeGetCurrentTime())) {
5459  // We add the smart contract to the server's Cron
5460  // object, which does regular processing.
5461  // That object will take care of processing the smart
5462  // contract according to its terms.
5463  //
5464  // NOTE: FYI, inside AddCronItem, since this is a new
5465  // CronItem, a Cron Receipt will
5466  // be saved with the User's signature on it, containing
5467  // the Cron Item from the user's
5468  // original request. After that, the item is stored
5469  // internally to Cron itself, and
5470  // signed by the server--and changes over time as cron
5471  // processes. (The original receipt
5472  // can always be loaded when necessary.)
5473  //
5474 
5475  // Now we can set the response item as an
5476  // acknowledgement instead of rejection (the default)
5477  pResponseItem->SetStatus(OTItem::acknowledgement);
5478  bOutSuccess = true; // The smart contract activation was
5479  // successful.
5480  OTLog::vOutput(0, "%s: Successfully added smart "
5481  "contract to Cron object.\n",
5482  __FUNCTION__);
5483  } // If smart contract verified.
5484  else {
5485  OTLog::vOutput(0, "%s: Unable to add smart contract to "
5486  "Cron object.\n",
5487  __FUNCTION__);
5488  }
5489  } // contract verifies, activate it.
5490  } // else
5491  // If the smart contract WAS successfully added to Cron, then we
5492  // don't need to
5493  // delete it here, since Cron owns it now, and will deal with
5494  // cleaning it up at the right time.
5495  if ((nullptr != pContract) &&
5496  (pResponseItem->GetStatus() != OTItem::acknowledgement)) {
5497  delete pContract;
5498  pContract = nullptr;
5499  }
5500  }
5501  }
5502 
5503  // sign the response item before sending it back (it's already been added to
5504  // the transaction above)
5505  // Now, whether it was rejection or acknowledgement, it is set properly and
5506  // it is signed, and it
5507  // is owned by the transaction, who will take it from here.
5508  pResponseItem->SignContract(server_->m_nymServer);
5509  pResponseItem->SaveContract(); // the signing was of no effect because I
5510  // forgot to save.
5511 
5512  pResponseBalanceItem->SignContract(server_->m_nymServer);
5513  pResponseBalanceItem->SaveContract();
5514 }
static EXPORT void vError(const char *szError,...)
Definition: OTLog.cpp:800
bool issueNextTransactionNumber(OTPseudonym &nym, int64_t &txNumber, bool storeNumber=true)
Definition: Transactor.cpp:211
#define NYM_IS_ALLOWED(SZ_NYM_ID, BOOL_VAR_NAME)
Definition: Macros.hpp:146
bool verifyTransactionNumber(OTPseudonym &nym, const int64_t &transactionNumber)
Definition: Transactor.cpp:278
EXPORT bool AddCronItem(OTCronItem &theItem, OTPseudonym *pActivator, bool bSaveReceipt, time64_t tDateAdded)
Definition: OTCron.cpp:731
static EXPORT OTItem * CreateItemFromTransaction(const OTTransaction &theOwner, OTItem::itemType theType, const OTIdentifier *pDestinationAcctID=nullptr)
Definition: OTItem.cpp:1451
time64_t OTTimeGetCurrentTime()
Definition: Common.hpp:211
#define OT_ASSERT(x)
Definition: Assert.hpp:150
static bool __transact_smart_contract
EXPORT const char * Get() const
Definition: OTString.cpp:1045
static EXPORT void vOutput(int32_t nVerbosity, const char *szOutput,...)
Definition: OTLog.cpp:768
void opentxs::Notary::NotarizeTransaction ( OTPseudonym theNym,
OTTransaction tranIn,
OTTransaction tranOut,
bool &  bOutSuccess 
)

If the server receives a notarizeTransactions command, it will be accompanied by a payload containing a ledger to be notarized. UserCmdNotarizeTransactions will loop through that ledger, and for each transaction within, it calls THIS method. TODO think about error reporting here and sending a message back to user.

Definition at line 7023 of file Notary.cpp.

7025 {
7026  const int64_t lTransactionNumber = tranIn.GetTransactionNum();
7027  const OTIdentifier SERVER_ID(server_->m_strServerID);
7028  OTIdentifier USER_ID;
7029  theNym.GetIdentifier(USER_ID);
7030  const OTString strIDNym(USER_ID);
7031 
7032  OTAccount theFromAccount(USER_ID, tranIn.GetPurportedAccountID(),
7033  SERVER_ID);
7034 
7035  // Make sure the "from" account even exists...
7036  if (!theFromAccount.LoadContract()) {
7037  const OTString strIDAcct(tranIn.GetPurportedAccountID());
7038  OTLog::vOutput(0, "%s: Error loading asset account: %s\n", __FUNCTION__,
7039  strIDAcct.Get());
7040  }
7041  // Make sure the "from" account isn't marked for deletion.
7042  else if (theFromAccount.IsMarkedForDeletion()) {
7043  const OTString strIDAcct(tranIn.GetPurportedAccountID());
7044  OTLog::vOutput(0, "%s: Failed attempt to use an Asset account that was "
7045  "marked for deletion: %s\n",
7046  __FUNCTION__, strIDAcct.Get());
7047  }
7048  // Make sure the Account ID loaded from the file matches the one we just set
7049  // and used as the filename.
7050  else if (!theFromAccount.VerifyContractID()) {
7051  // this should never happen. How did the wrong ID get into the account
7052  // file, if the right
7053  // ID is on the filename itself? and vice versa.
7054  const OTString strIDAcct(tranIn.GetPurportedAccountID());
7055  OTLog::vError("%s: Error verifying account ID: %s\n", __FUNCTION__,
7056  strIDAcct.Get());
7057  }
7058  // Make sure the nymID loaded up in the account as its actual owner matches
7059  // the nym who was
7060  // passed in to this function requesting a transaction on this account...
7061  // otherwise any asshole
7062  // could do transactions on your account, no?
7063  else if (!theFromAccount.VerifyOwner(theNym)) {
7064  const OTIdentifier idAcct(theFromAccount);
7065  const OTString strIDAcct(idAcct);
7067  0, "%s: Error verifying account ownership... Nym: %s Acct: %s\n",
7068  __FUNCTION__, strIDNym.Get(), strIDAcct.Get());
7069  }
7070  // Make sure I, the server, have signed this file.
7071  else if (!theFromAccount.VerifySignature(server_->m_nymServer)) {
7072  const OTIdentifier idAcct(theFromAccount);
7073  const OTString strIDAcct(idAcct);
7074  OTLog::vError(
7075  "%s: Error verifying server signature on account: %s for Nym: %s\n",
7076  __FUNCTION__, strIDAcct.Get(), strIDNym.Get());
7077  }
7078  // No need to call VerifyAccount() here since the above calls go above and
7079  // beyond that method.
7080  else if (!server_->transactor_.verifyTransactionNumber(
7081  theNym, lTransactionNumber)) {
7082  const OTIdentifier idAcct(theFromAccount);
7083  const OTString strIDAcct(idAcct);
7084  // The user may not submit a transaction using a number he's already
7085  // used before.
7086  OTLog::vOutput(0, "%s: Error verifying transaction number %ld on user "
7087  "Nym: %s Account: %s\n",
7088  __FUNCTION__, lTransactionNumber, strIDNym.Get(),
7089  strIDAcct.Get());
7090  }
7091 
7092  // The items' acct and server ID were already checked in VerifyContractID()
7093  // when they were loaded.
7094  // Now this checks a little deeper, to verify ownership, signatures, and
7095  // transaction number
7096  // on each item. That way those things don't have to be checked for
7097  // security over and over
7098  // again in the subsequent calls.
7099  //
7100  else if (!tranIn.VerifyItems(theNym)) {
7101  const OTIdentifier idAcct(theFromAccount);
7102  const OTString strIDAcct(idAcct);
7103  OTLog::vOutput(0, "%s: Error verifying transaction items. Trans: %ld "
7104  "Nym: %s Account: %s\n",
7105  __FUNCTION__, lTransactionNumber, strIDNym.Get(),
7106  strIDAcct.Get());
7107  }
7108 
7109  // any other security stuff?
7110  // Todo do I need to verify the server ID here as well?
7111  else {
7112  // We don't want any transaction number being used twice.
7113  // (The number, at this point, is STILL issued to the user, who is still
7114  // responsible
7115  // for that number and must continue signing for it. All this means here
7116  // is that the
7117  // user no longer has the number on his AVAILABLE list. Removal from
7118  // issued list happens separately.)
7119  //
7120  if (false ==
7121  server_->transactor_.removeTransactionNumber(
7122  theNym, lTransactionNumber, true)) // bSave=true
7123  {
7124  OTLog::Error("Error removing transaction number (as available) "
7125  "from user nym in Notary::NotarizeTransaction\n");
7126  }
7127  else {
7128  OTItem::itemType theReplyItemType = OTItem::error_state;
7129 
7130  switch (tranIn.GetType()) {
7131  // TRANSFER (account to account)
7132  // Alice sends a signed request to the server asking it to
7133  // transfer from her account ABC to the inbox of account DEF.
7134  // A copy will also remain in her outbox until canceled or accepted.
7136  OTLog::Output(0, "NotarizeTransaction type: Transfer\n");
7137  NotarizeTransfer(theNym, theFromAccount, tranIn, tranOut,
7138  bOutSuccess);
7139  theReplyItemType = OTItem::atTransfer;
7140  break;
7141 
7142  // PROCESS INBOX (currently, all incoming transfers must be
7143  // accepted.)
7144  // Bob sends a signed request to the server asking it to reject
7145  // some of his inbox items and/or accept some into his account DEF.
7147  OTLog::Output(0, "NotarizeTransaction type: Process Inbox\n");
7148  NotarizeProcessInbox(theNym, theFromAccount, tranIn, tranOut,
7149  bOutSuccess);
7150  // theReplyItemType = OTItem::atProcessInbox;
7151  // // Nonexistent, and here, unused.
7152  // (There is a processInbox message that carries that
7153  // transaction...)
7154  break;
7155 
7156  // WITHDRAWAL (cash or voucher)
7157  // Alice sends a signed request to the server asking it to debit her
7158  // account ABC and then issue her a purse full of blinded cash
7159  // tokens
7160  // --OR-- a voucher (a cashier's cheque, made out to any recipient's
7161  // User ID, or made out to a blank recipient, just like a blank
7162  // cheque.)
7164  OTItem* pItemVoucher = tranIn.GetItem(OTItem::withdrawVoucher);
7165  OTItem* pItemCash = tranIn.GetItem(OTItem::withdrawal);
7166 
7167  if (nullptr != pItemCash) {
7168  theReplyItemType = OTItem::atWithdrawal;
7169  OTLog::Output(
7170  0, "NotarizeTransaction type: Withdrawal (cash)\n");
7171  }
7172  else if (nullptr != pItemVoucher) {
7173  theReplyItemType = OTItem::atWithdrawVoucher;
7174  OTLog::Output(
7175  0, "NotarizeTransaction type: Withdrawal (voucher)\n");
7176  }
7177  NotarizeWithdrawal(theNym, theFromAccount, tranIn, tranOut,
7178  bOutSuccess);
7179  } break;
7180 
7181  // DEPOSIT (cash or cheque)
7182  // Bob sends a signed request to the server asking it to deposit
7183  // into his
7184  // account ABC. He includes with his request a signed cheque made
7185  // out to
7186  // Bob's user ID (or blank), --OR-- a purse full of tokens.
7188  OTLog::Output(0, "NotarizeTransaction type: Deposit\n");
7189  NotarizeDeposit(theNym, theFromAccount, tranIn, tranOut,
7190  bOutSuccess);
7191  theReplyItemType = OTItem::atDeposit;
7192  break;
7193 
7194  // PAY DIVIDEND
7195  // Bob sends a signed request to the server asking it to pay all
7196  // shareholders
7197  // of a given asset type at the rate of $X per share, where X and $
7198  // are both
7199  // configurable.
7201  OTLog::Output(0, "NotarizeTransaction type: Pay Dividend\n");
7202  NotarizePayDividend(theNym, theFromAccount, tranIn, tranOut,
7203  bOutSuccess);
7204  theReplyItemType = OTItem::atPayDividend;
7205  break;
7206 
7207  // MARKET OFFER
7208  // Bob sends a signed request to the server asking it to put an
7209  // offer
7210  // on the market. He includes with his request a signed trade
7211  // listing
7212  // the relevant information, asset types and account IDs.
7214  OTLog::Output(0, "NotarizeTransaction type: Market Offer\n");
7215  NotarizeMarketOffer(theNym, theFromAccount, tranIn, tranOut,
7216  bOutSuccess);
7217  theReplyItemType = OTItem::atMarketOffer;
7218  break;
7219 
7220  // PAYMENT PLAN
7221  // Bob sends a signed request to the server asking it to make
7222  // regular
7223  // payments to Alice. (BOTH Alice AND Bob must have signed the same
7224  // contract.)
7226  OTLog::Output(0, "NotarizeTransaction type: Payment Plan\n");
7227  NotarizePaymentPlan(theNym, theFromAccount, tranIn, tranOut,
7228  bOutSuccess);
7229  theReplyItemType = OTItem::atPaymentPlan;
7230  break;
7231 
7232  // SMART CONTRACT
7233  // Bob sends a signed request to the server asking it to activate a
7234  // smart contract.
7235  // Bob is the authorizing agent for one of the parties, all of whom
7236  // have signed it,
7237  // and have provided transaction #s for it.
7239  OTLog::Output(0, "NotarizeTransaction type: Smart Contract\n");
7240 
7241  // For all transaction numbers used on cron items, we keep track
7242  // of them in
7243  // the GetSetOpenCronItems. This will be removed again below, if
7244  // the transaction
7245  // fails.
7246  std::set<int64_t>& theIDSet = theNym.GetSetOpenCronItems();
7247  theIDSet.insert(lTransactionNumber);
7248  NotarizeSmartContract(theNym, theFromAccount, tranIn, tranOut,
7249  bOutSuccess);
7250  theReplyItemType = OTItem::atSmartContract;
7251  } break;
7252 
7253  // CANCEL CRON ITEM
7254  // (Cron items: market offers, payment plans...)
7255  // Bob sends a signed request to the server asking it to cancel a
7256  // REGULARLY PROCESSING CONTRACT that he had previously created.
7258  OTLog::Output(0, "NotarizeTransaction type: cancelCronItem\n");
7259  NotarizeCancelCronItem(theNym, theFromAccount, tranIn, tranOut,
7260  bOutSuccess);
7261  theReplyItemType = OTItem::atCancelCronItem;
7262  break;
7263 
7264  // EXCHANGE BASKET
7265  // Bob sends a signed request to the server asking it to exchange
7266  // funds
7267  // in or out of a basket currency. (From-or-to his main basket
7268  // account and his
7269  // various sub-accounts for each member currency in the basket.)
7271  OTLog::Output(0, "NotarizeTransaction type: Exchange Basket\n");
7272  NotarizeExchangeBasket(theNym, theFromAccount, tranIn, tranOut,
7273  bOutSuccess);
7274  theReplyItemType = OTItem::atExchangeBasket;
7275  break;
7276 
7277  default:
7278  OTLog::vError("%s: Error, unexpected type: %s\n", __FUNCTION__,
7279  tranIn.GetTypeString());
7280  break;
7281  }
7282 
7283  // Where appropriate, remove a transaction number from my issued
7284  // list
7285  // (the list of numbers I must sign for in every balance agreement.)
7286  bool bIsCronItem = false;
7287 
7288  switch (tranIn.GetType()) {
7292  bIsCronItem = true; // Falls through...
7293 
7295  // If success, then Issued number stays on Nym's issued list
7296  // until the transfer, paymentPlan, marketOffer, or smart
7297  // contract is entirely closed and removed. In the case of
7298  // transfer, that's when the transfer receipt is accepted.
7299  // In the case of markets and paymentplans, that's when they've
7300  // been entirely removed from Cron (many
7301  // intermediary receipts might occur before that happens.) At
7302  // that time, a final receipt is issued with
7303  // a closing transaction number (to make sure the user closes
7304  // all of the related market receipts.)
7305  //
7306  // But if failure, then Issued number is immediately removed.
7307  // (It already can't be used again, and there's no receipt to
7308  // clear later, thus no reason to save it...)
7309  {
7310  OTItem* pItem = tranOut.GetItem(theReplyItemType);
7311 
7312  if ((nullptr != pItem)) {
7313  if (OTItem::rejection == pItem->GetStatus()) {
7314  // If this is a cron item, then we need to remove it
7315  // from the
7316  // list of open cron items as well.
7317  if (bIsCronItem) {
7318  std::set<int64_t>& theIDSet =
7319  theNym.GetSetOpenCronItems();
7320  std::set<int64_t>::iterator theSetIT =
7321  theIDSet.find(lTransactionNumber);
7322  if (theSetIT != theIDSet.end()) // Found it.
7323  theIDSet.erase(lTransactionNumber);
7324  }
7325  if (!server_->transactor_.removeIssuedNumber(
7326  theNym, lTransactionNumber,
7327  true)) // bSave=true
7328  {
7329  const OTString strNymID(USER_ID);
7330  OTLog::vError("%s: Error removing issued "
7331  "number %ld from user nym: %s\n",
7332  __FUNCTION__, lTransactionNumber,
7333  strNymID.Get());
7334  }
7335  }
7336  }
7337  }
7338  break;
7339  // In the case of the below transaction types, the transaction
7340  // number is removed from the Nym's
7341  // issued list SUCCESS OR FAIL. (It's closed either way.)
7342  //
7349  if (!server_->transactor_.removeIssuedNumber(
7350  theNym, lTransactionNumber, true)) // bSave=true
7351  {
7352  const OTString strNymID(USER_ID);
7353  OTLog::vError("%s: Error removing issued number %ld from "
7354  "user nym: %s\n",
7355  __FUNCTION__, lTransactionNumber,
7356  strNymID.Get());
7357  }
7358  break;
7359  default:
7360  OTLog::vError("%s: Error, unexpected type: %s\n", __FUNCTION__,
7361  tranIn.GetTypeString());
7362  break;
7363  }
7364  }
7365  }
7366 
7367  // sign the outoing transaction
7368  tranOut.SignContract(server_->m_nymServer);
7369  tranOut.SaveContract(); // don't forget to save (to internal raw file
7370  // member)
7371 
7372  // Contracts store an internal member that contains the "Raw File" contents
7373  // That is, the unsigned XML portion, plus the signatures, attached in a
7374  // standard
7375  // PGP-compatible format. It's not enough to sign it, you must also save it
7376  // into
7377  // that Raw file member variable (using SaveContract) and then you must
7378  // sometimes
7379  // THEN save it into a file (or a string or wherever you want to put it.)
7380 }
static EXPORT void vError(const char *szError,...)
Definition: OTLog.cpp:800
static EXPORT void Output(int32_t nVerbosity, const char *szOutput)
Definition: OTLog.cpp:710
bool verifyTransactionNumber(OTPseudonym &nym, const int64_t &transactionNumber)
Definition: Transactor.cpp:278
void NotarizeDeposit(OTPseudonym &nym, OTAccount &account, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
for depositing a cheque or cash.
Definition: Notary.cpp:2256
void NotarizeWithdrawal(OTPseudonym &nym, OTAccount &account, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
Definition: Notary.cpp:661
void NotarizeMarketOffer(OTPseudonym &nym, OTAccount &assetAccount, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
Definition: Notary.cpp:6618
bool removeTransactionNumber(OTPseudonym &nym, const int64_t &transactionNumber, bool save=false)
Definition: Transactor.cpp:320
void NotarizePayDividend(OTPseudonym &nym, OTAccount &account, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
Definition: Notary.cpp:1460
static EXPORT void Error(const char *szError)
Definition: OTLog.cpp:831
void NotarizeProcessInbox(OTPseudonym &nym, OTAccount &account, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
Definition: Notary.cpp:8088
bool removeIssuedNumber(OTPseudonym &nym, const int64_t &transactionNumber, bool save=false)
Definition: Transactor.cpp:354
void NotarizeExchangeBasket(OTPseudonym &nym, OTAccount &sourceAccount, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
Definition: Notary.cpp:5724
void NotarizePaymentPlan(OTPseudonym &nym, OTAccount &depositorAccount, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
Definition: Notary.cpp:4065
void NotarizeCancelCronItem(OTPseudonym &nym, OTAccount &assetAccount, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
Definition: Notary.cpp:5536
static EXPORT void vOutput(int32_t nVerbosity, const char *szOutput,...)
Definition: OTLog.cpp:768
void NotarizeSmartContract(OTPseudonym &nym, OTAccount &activatingAccount, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
Definition: Notary.cpp:4805
void NotarizeTransfer(OTPseudonym &nym, OTAccount &fromAccount, OTTransaction &tranIn, OTTransaction &tranOut, bool &outSuccess)
Definition: Notary.cpp:174
void opentxs::Notary::NotarizeTransfer ( OTPseudonym nym,
OTAccount fromAccount,
OTTransaction tranIn,
OTTransaction tranOut,
bool &  outSuccess 
)

Definition at line 174 of file Notary.cpp.

177 {
178  // The outgoing transaction is an "atTransfer", that is, "a reply to the
179  // transfer request"
180  tranOut.SetType(OTTransaction::atTransfer);
181 
182  OTItem* pItem = nullptr;
183  OTItem* pBalanceItem = nullptr;
184  OTItem* pResponseItem = nullptr;
185  OTItem* pResponseBalanceItem = nullptr;
186 
187  // The incoming transaction may be sent to inboxes and outboxes, and it
188  // will probably be bundled in our reply to the user as well. Therefore,
189  // let's grab it as a string.
190  OTString strInReferenceTo;
191  OTString strBalanceItem;
192 
193  // Grab the actual server ID from this object, and use it as the server ID
194  // here.
195  const OTIdentifier SERVER_ID(server_->m_strServerID), USER_ID(theNym),
196  ACCOUNT_ID(theFromAccount),
197  ASSET_TYPE_ID(theFromAccount.GetAssetTypeID());
198 
199  OTString strUserID(USER_ID), strAccountID(ACCOUNT_ID);
200  pResponseBalanceItem =
202  pResponseBalanceItem->SetStatus(OTItem::rejection); // the default.
203  tranOut.AddItem(*pResponseBalanceItem); // the Transaction's destructor will
204  // cleanup the item. It "owns" it
205  // now.
206  pResponseItem =
208  pResponseItem->SetStatus(OTItem::rejection); // the default.
209  tranOut.AddItem(*pResponseItem); // the Transaction's destructor will
210  // cleanup the item. It "owns" it now.
211 
212  if (false ==
214  OTLog::vOutput(0, "Notary::NotarizeTransfer: User %s cannot do this "
215  "transaction (All acct-to-acct transfers are "
216  "disallowed in server.cfg)\n",
217  strUserID.Get());
218  }
219  else if (nullptr ==
220  (pBalanceItem = tranIn.GetItem(OTItem::balanceStatement))) {
221  OTString strTemp(tranIn);
222  OTLog::vOutput(0, "Notary::NotarizeTransfer: Expected "
223  "OTItem::balanceStatement in trans# %ld: \n\n%s\n\n",
224  tranIn.GetTransactionNum(),
225  strTemp.Exists()
226  ? strTemp.Get()
227  : " (ERROR LOADING TRANSACTION INTO STRING) ");
228  }
229  // For now, there should only be one of these transfer items inside the
230  // transaction.
231  // So we treat it that way... I either get it successfully or not.
232  else if (nullptr == (pItem = tranIn.GetItem(OTItem::transfer))) {
233  OTString strTemp(tranIn);
234  OTLog::vOutput(0, "Notary::NotarizeTransfer: Expected "
235  "OTItem::transfer in trans# %ld: \n\n%s\n\n",
236  tranIn.GetTransactionNum(),
237  strTemp.Exists()
238  ? strTemp.Get()
239  : " (ERROR LOADING TRANSACTION INTO STRING) ");
240  }
241  else if (ACCOUNT_ID == pItem->GetDestinationAcctID()) {
242  OTString strTemp(tranIn);
244  0, "Notary::NotarizeTransfer: Failed attempt by user %s in "
245  "trans# %ld, to transfer money \"To the From Acct\": \n\n%s\n\n",
246  strUserID.Get(), tranIn.GetTransactionNum(),
247  strTemp.Exists() ? strTemp.Get()
248  : " (ERROR LOADING TRANSACTION INTO STRING) ");
249  }
250  else {
251  // The response item, as well as the inbox and outbox items, will
252  // contain a copy
253  // of the request item. So I save it into a string here so they can all
254  // grab a copy of it
255  // into their "in reference to" fields.
256  pItem->SaveContractRaw(strInReferenceTo);
257  pBalanceItem->SaveContractRaw(strBalanceItem);
258 
259  // IDFromAccount is the ID on the "from" Account that was passed in.
260  // IDItemFromAccount is the "from" account ID on the transaction Item we
261  // are currently examining.
262  // IDItemToAccount is the "to" account ID on the transaction item we are
263  // currently examining.
264  OTIdentifier IDFromAccount(theFromAccount);
265 
266  // Server response item being added to server response transaction
267  // (tranOut)
268  // They're getting SOME sort of response item.
269 
270  pResponseItem->SetReferenceString(strInReferenceTo); // the response
271  // item carries a
272  // copy of what
273  // it's responding
274  // to.
275  pResponseItem->SetReferenceToNum(
276  pItem->GetTransactionNum()); // This response item is IN RESPONSE to
277  // pItem and its Owner Transaction.
278  pResponseItem->SetNumberOfOrigin(*pItem);
279 
280  pResponseBalanceItem->SetReferenceString(
281  strBalanceItem); // the response item carries a copy of what it's
282  // responding to.
283  pResponseBalanceItem->SetReferenceToNum(
284  pItem->GetTransactionNum()); // This response item is IN RESPONSE to
285  // pItem and its Owner Transaction.
286  pResponseBalanceItem->SetNumberOfOrigin(*pItem);
287 
288  // Set the ID on the To Account based on what the transaction request
289  // said. (So we can load it up.)
290  std::unique_ptr<OTAccount> pDestinationAcct(
291  OTAccount::LoadExistingAccount(pItem->GetDestinationAcctID(),
292  SERVER_ID));
293 
294  // Only accept transfers with positive amounts.
295  if (0 > pItem->GetAmount()) {
296  OTLog::Output(0, "Notary::NotarizeTransfer: Failure: Attempt to "
297  "transfer negative balance.\n");
298  }
299 
300  // I'm using the operator== because it exists.
301  // If the ID on the "from" account that was passed in,
302  // does not match the "Acct From" ID on this transaction item
303  else if (!(IDFromAccount == pItem->GetPurportedAccountID())) {
304  OTLog::Output(0, "Notary::NotarizeTransfer: Error: 'From' "
305  "account ID on the transaction does not match "
306  "'from' account ID on the transaction item.\n");
307  }
308  // ok so the IDs match. Does the destination account exist?
309  else if (nullptr == pDestinationAcct) {
310  OTLog::Output(0, "Notary::NotarizeTransfer: ERROR verifying "
311  "existence of the 'to' account.\n");
312  }
313  // Is the destination a legitimate other user's acct, or is it just an
314  // internal server account?
315  // (That is, stash accounts, voucher accounts, basket accounts, etc are
316  // only used internally,
317  // and may not be recipients to user transfers...)
318  //
319  else if (pDestinationAcct->IsInternalServerAcct()) {
320  OTLog::Output(0, "Notary::NotarizeTransfer: Failure: Destination "
321  "account is used internally by the server, and is "
322  "not a valid recipient for this transaction.\n");
323  }
324  // Are both of the accounts of the same Asset Type?
325  else if (!(theFromAccount.GetAssetTypeID() ==
326  pDestinationAcct->GetAssetTypeID())) {
327  OTString strFromAssetID(theFromAccount.GetAssetTypeID()),
328  strDestinationAssetID(pDestinationAcct->GetAssetTypeID());
330  0, "ERROR - user attempted to transfer between accounts of 2 "
331  "different "
332  "asset types in Notary::NotarizeTransfer:\n%s\n%s\n",
333  strFromAssetID.Get(), strDestinationAssetID.Get());
334  }
335  // Does it verify?
336  // I call VerifySignature here since VerifyContractID was already called
337  // in LoadExistingAccount().
338  else if (!pDestinationAcct->VerifySignature(server_->m_nymServer)) {
339  OTLog::Output(0, "ERROR verifying signature on, the 'to' account "
340  "in Notary::NotarizeTransfer\n");
341  }
342 
343  // This entire function can be divided into the top and bottom halves.
344  // The top half is oriented around finding the "transfer" item (in the
345  // "transfer" transaction)
346  // and setting up the response item that will go into the response
347  // transaction.
348  // The bottom half is oriented, in the case of success, around creating
349  // the necessary inbox
350  // and outbox entries, and debiting the account, and basically
351  // performing the actual transfer.
352  else {
353  // Okay then, everything checks out. Let's add this to the sender's
354  // outbox and the recipient's inbox.
355  // IF they can be loaded up from file, or generated, that is.
356 
357  // Load the inbox/outbox in case they already exist
358  OTLedger theFromOutbox(USER_ID, IDFromAccount, SERVER_ID),
359  theToInbox(pItem->GetDestinationAcctID(), SERVER_ID);
360 
361  bool bSuccessLoadingInbox = theToInbox.LoadInbox();
362  bool bSuccessLoadingOutbox = theFromOutbox.LoadOutbox();
363  // ...or generate them otherwise...
364 
365  // NOTE:
366  // 1. Any normal user had his inbox created at the same time as his
367  // asset account was created.
368  // 2. If there is an error now, we don't necessarily just want to
369  // re-create (and overwrite) that file.
370  // 3. Therefore I do not generate the ledger for safety reasons, per
371  // 2.
372  // 4. Also, what if an attempt is being made to transfer to an
373  // account that isn't SUPPOSED to have
374  // an inbox? For example, a server voucher account (where backing
375  // funds for vouchers are stored) does
376  // not have an inbox, and should not be able to receive
377  // transfers. In that case, we definitely don't want
378  // to just "generate" an inbox here! Instead, we want it to fail.
379  // In fact, I'm adding a check, above, for
380  // the account type. In fact, I'm adding a new method to
381  // OTAccount where we can just ask it, for each
382  // transaction type, whether it can even be used for that purpose
383  // in the first place.
384  // Update: appears OTAccount::IsInternalServerAcct already
385  // basically fits the bill.
386 
387  if (true == bSuccessLoadingInbox)
388  bSuccessLoadingInbox =
389  theToInbox.VerifyAccount(server_->m_nymServer);
390  else
391  OTLog::Error(
392  "Notary::NotarizeTransfer: Error loading 'to' inbox.\n");
393 
394  if (true == bSuccessLoadingOutbox)
395  bSuccessLoadingOutbox =
396  theFromOutbox.VerifyAccount(server_->m_nymServer);
397  else
398  OTLog::Error("Notary::NotarizeTransfer: Error loading 'from' "
399  "outbox.\n");
400 
401  std::unique_ptr<OTLedger> pInbox(
402  theFromAccount.LoadInbox(server_->m_nymServer));
403  std::unique_ptr<OTLedger> pOutbox(
404  theFromAccount.LoadOutbox(server_->m_nymServer));
405 
406  if (nullptr == pInbox) {
407  OTLog::Error("Error loading or verifying inbox.\n");
408  }
409  else if (nullptr == pOutbox) {
410  OTLog::Error("Error loading or verifying outbox.\n");
411  }
412  else if (!bSuccessLoadingInbox ||
413  false == bSuccessLoadingOutbox) {
414  OTLog::Error(
415  "ERROR generating ledger in Notary::NotarizeTransfer.\n");
416  }
417  else {
418  // Generate new transaction number for these new transactions
419  // todo check this generation for failure (can it fail?)
420  int64_t lNewTransactionNumber = 0;
421 
422  server_->transactor_.issueNextTransactionNumber(
423  server_->m_nymServer, lNewTransactionNumber,
424  false); // bStoreTheNumber = false
425  // I create TWO Outbox transactions -- one for the real outbox,
426  // (theFromOutbox)
427  // and one for pOutbox (used for verifying the balance
428  // statement.)
429  // pTEMPOutboxTransaction (here below) is that last one,
430  // pOutbox.
431  //
432  OTTransaction* pTEMPOutboxTransaction =
435  lNewTransactionNumber);
436  OTTransaction* pOutboxTransaction =
439  lNewTransactionNumber);
440 
441  OTTransaction* pInboxTransaction =
444  lNewTransactionNumber);
445  // UPDATE: I am now issuing one new transaction number above,
446  // instead of two. This is to make it easy
447  // for the two to cross-reference each other. Later if I want to
448  // remove the transaction from the inbox
449  // and need to know the corresponding transaction # for the
450  // outbox, it will be the same number.
451 
452  // I have to set this one up just like the one below.
453  pTEMPOutboxTransaction->SetReferenceString(strInReferenceTo);
454  pTEMPOutboxTransaction->SetReferenceToNum(
455  pItem->GetTransactionNum());
456  pTEMPOutboxTransaction->SetNumberOfOrigin(*pItem);
457  // the new transactions store a record of the item they're
458  // referring to.
459  pOutboxTransaction->SetReferenceString(strInReferenceTo);
460  pOutboxTransaction->SetReferenceToNum(
461  pItem->GetTransactionNum());
462  pOutboxTransaction->SetNumberOfOrigin(*pItem);
463 
464  // todo put these two together in a method.
465  pInboxTransaction->SetReferenceString(strInReferenceTo);
466  pInboxTransaction->SetReferenceToNum(
467  pItem->GetTransactionNum());
468  pInboxTransaction->SetNumberOfOrigin(*pItem);
469 
470  // Now we have created 2 new transactions from the server to the
471  // users' boxes
472  // Let's sign them and add to their inbox / outbox.
473  pOutboxTransaction->SignContract(server_->m_nymServer);
474  pInboxTransaction->SignContract(server_->m_nymServer);
475 
476  pOutboxTransaction->SaveContract();
477  pInboxTransaction->SaveContract();
478  // Meanwhile a copy of the outbox transaction is also added to
479  // pOutbox. (It's just another copy of the outbox, but used
480  // purely for verifying the balance statement, while a different
481  // copy of the outbox is used for actually adding the receipt
482  // and saving to the outbox file.)
483  //
484  pTEMPOutboxTransaction->SignContract(server_->m_nymServer);
485  pTEMPOutboxTransaction->SaveContract();
486 
487  // No need to save a box receipt in this case, like we normally
488  // would
489  // when adding a transaction to a box.
490  pOutbox->AddTransaction(
491  *pTEMPOutboxTransaction); // pOutbox will clean this up
492 
493  // The balance item from the user, for the outbox transaction,
494  // will not have
495  // the correct transaction number (because I just generated it
496  // above, so the user
497  // could not possibly have known that when he sent his message.)
498  // Currently it is
499  // set to "1" in the user request, but I just put the actual
500  // number in the pOutbox
501  // above (since I now have the actual number.)
502  //
503  // So when the receipt is saved (the output transaction) it will
504  // show the user's
505  // signed request with "1" in the outbox, included in the
506  // server's signed reply
507  // with lNewTransactionNumber in the outbox to correspond to it.
508  // The user saves
509  // a copy of the same receipt, thus he will be unable to produce
510  // a receipt signed
511  // by the server, without producing the exact same thing.
512  // ("1" in the request and lNewTransactionNumber in the signed
513  // response.)
514  //
515  // This all means that the below call to
516  // VerifyBalanceStatement() needs to verify
517  // the number "1" on the user request, as lNewTransactionNumber
518  // in pOutbox, in order
519  // to handle this special case, since otherwise the verification
520  // would fail.
521  //
522  if (!(pBalanceItem->VerifyBalanceStatement(
523  pItem->GetAmount() * (-1), // My acct balance will be
524  // smaller as a result of
525  // this transfer.
526  theNym, *pInbox, *pOutbox, theFromAccount, tranIn,
527  lNewTransactionNumber))) {
528  OTLog::vOutput(0, "ERROR verifying balance statement while "
529  "performing transfer. Acct ID:\n%s\n",
530  strAccountID.Get());
531  }
532  else {
533  pResponseBalanceItem->SetStatus(
534  OTItem::acknowledgement); // the balance agreement (just
535  // above) was successful.
536  pResponseBalanceItem->SetNewOutboxTransNum(
537  lNewTransactionNumber); // So the receipt will show that
538  // the client's "1" in the
539  // outbox is now actually "34"
540  // or whatever, issued by the
541  // server as part of
542  // successfully processing the
543  // transaction.
544 
545  // Deduct the amount from the account...
546  // TODO an issuer account here, can go negative.
547  // whereas a regular account should not be allowed to go
548  // negative.
549  if (theFromAccount.Debit(
550  pItem->GetAmount())) { // todo need to be able to
551  // "roll back" if anything
552  // inside this block fails.
553  // Here the transactions we just created are actually
554  // added to the ledgers.
555  theFromOutbox.AddTransaction(*pOutboxTransaction);
556  theToInbox.AddTransaction(*pInboxTransaction);
557 
558  // Release any signatures that were there before (They
559  // won't
560  // verify anymore anyway, since the content has
561  // changed.)
562  theFromOutbox.ReleaseSignatures();
563  theToInbox.ReleaseSignatures();
564 
565  // Sign them.
566  theFromOutbox.SignContract(server_->m_nymServer);
567  theToInbox.SignContract(server_->m_nymServer);
568 
569  // Save them internally
570  theFromOutbox.SaveContract();
571  theToInbox.SaveContract();
572 
573  // Save their internals (signatures and all) to file.
574  theFromAccount.SaveOutbox(theFromOutbox);
575  pDestinationAcct->SaveInbox(theToInbox);
576 
577  theFromAccount.ReleaseSignatures();
578  theFromAccount.SignContract(server_->m_nymServer);
579  theFromAccount.SaveContract();
580  theFromAccount.SaveAccount();
581 
582  pDestinationAcct->ReleaseSignatures();
583  pDestinationAcct->SignContract(server_->m_nymServer);
584  pDestinationAcct->SaveContract();
585  pDestinationAcct->SaveAccount();
586 
587  // Now we can set the response item as an
588  // acknowledgement instead of the default (rejection)
589  // otherwise, if we never entered this block, then it
590  // would still be set to rejection, and the
591  // new items would never have been added to the
592  // inbox/outboxes, and those files, along with
593  // the account file, would never have had their
594  // signatures released, or been re-signed or
595  // re-saved back to file. The debit failed, so all of
596  // those other actions would fail also.
597  // BUT... if the message comes back with
598  // acknowledgement--then all of these actions must have
599  // happened, and here is the server's signature to prove
600  // it.
601  // Otherwise you get no items and no signature. Just a
602  // rejection item in the response transaction.
603  pResponseItem->SetStatus(OTItem::acknowledgement);
604 
605  bOutSuccess = true; // The transfer was successful.
606 
607  // Any inbox/nymbox/outbox ledger will only itself
608  // contain
609  // abbreviated versions of the receipts, including their
610  // hashes.
611  //
612  // The rest is stored separately, in the box receipt,
613  // which is created
614  // whenever a receipt is added to a box, and deleted
615  // after a receipt
616  // is removed from a box.
617  //
618  pOutboxTransaction->SaveBoxReceipt(theFromOutbox);
619  pInboxTransaction->SaveBoxReceipt(theToInbox);
620  }
621  else {
622  delete pOutboxTransaction;
623  pOutboxTransaction = nullptr;
624  delete pInboxTransaction;
625  pInboxTransaction = nullptr;
626  OTLog::vOutput(0, "%s: Unable to debit account %s in "
627  "the amount of: %ld\n",
628  __FUNCTION__, strAccountID.Get(),
629  pItem->GetAmount());
630  }
631  }
632  } // both boxes were successfully loaded or generated.
633  }
634  }
635 
636  // sign the response item before sending it back (it's already been added to
637  // the transaction above)
638  // Now, whether it was rejection or acknowledgement, it is set properly and
639  // it is signed, and it
640  // is owned by the transaction, who will take it from here.
641  pResponseItem->SignContract(server_->m_nymServer);
642  pResponseItem->SaveContract(); // the signing was of no effect because I
643  // forgot to save.
644 
645  pResponseBalanceItem->SignContract(server_->m_nymServer);
646  pResponseBalanceItem->SaveContract();
647 }
static EXPORT OTTransaction * GenerateTransaction(const OTIdentifier &theUserID, const OTIdentifier &theAccountID, const OTIdentifier &theServerID, transactionType theType, int64_t lTransactionNum=0)
static EXPORT void Output(int32_t nVerbosity, const char *szOutput)
Definition: OTLog.cpp:710
bool issueNextTransactionNumber(OTPseudonym &nym, int64_t &txNumber, bool storeNumber=true)
Definition: Transactor.cpp:211
#define NYM_IS_ALLOWED(SZ_NYM_ID, BOOL_VAR_NAME)
Definition: Macros.hpp:146
static EXPORT OTItem * CreateItemFromTransaction(const OTTransaction &theOwner, OTItem::itemType theType, const OTIdentifier *pDestinationAcctID=nullptr)
Definition: OTItem.cpp:1451
static EXPORT void Error(const char *szError)
Definition: OTLog.cpp:831
static EXPORT void vOutput(int32_t nVerbosity, const char *szOutput,...)
Definition: OTLog.cpp:768
static EXPORT OTAccount * LoadExistingAccount(const OTIdentifier &accountId, const OTIdentifier &serverId)
Definition: OTAccount.cpp:480
void opentxs::Notary::NotarizeWithdrawal ( OTPseudonym theNym,
OTAccount theAccount,
OTTransaction tranIn,
OTTransaction tranOut,
bool &  bOutSuccess 
)

NotarizeWithdrawal supports two withdrawal types:

OTItem::withdrawVoucher This is a bank voucher, like a cashier's check. Funds are transferred to the bank, who then issues a cheque drawn on an internal voucher account.

OTItem::withdrawal This is a digital cash withdrawal, in the form of untraceable, blinded tokens. Funds are transferred to the bank, who blind-signs the tokens.

Definition at line 661 of file Notary.cpp.

664 {
665  // The outgoing transaction is an "atWithdrawal", that is, "a reply to the
666  // withdrawal request"
667  tranOut.SetType(OTTransaction::atWithdrawal);
668 
669  OTItem* pItem = nullptr;
670  OTItem* pItemCash = nullptr;
671  OTItem* pItemVoucher = nullptr;
672  OTItem* pBalanceItem = nullptr;
673  OTItem* pResponseItem = nullptr;
674  OTItem* pResponseBalanceItem = nullptr;
675 
676  // The incoming transaction may be sent to inboxes and outboxes, and it
677  // will probably be bundled in our reply to the user as well. Therefore,
678  // let's grab it as a string.
679  OTString strInReferenceTo;
680  OTString strBalanceItem;
681 
682  // Grab the actual server ID from this object, and use it as the server ID
683  // here.
684  const OTIdentifier SERVER_ID(server_->m_strServerID), USER_ID(theNym),
685  ACCOUNT_ID(theAccount), SERVER_USER_ID(server_->m_nymServer),
686  ASSET_TYPE_ID(theAccount.GetAssetTypeID());
687 
688  const OTString strUserID(USER_ID), strAccountID(ACCOUNT_ID),
689  strAssetTypeID(ASSET_TYPE_ID);
690 
691  // Here we find out if we're withdrawing cash, or a voucher
692  // (A voucher is a cashier's cheque aka banker's cheque).
693  //
694  OTItem::itemType theReplyItemType = OTItem::error_state;
695 
696  pItemVoucher = tranIn.GetItem(OTItem::withdrawVoucher);
697 
698  if (nullptr == pItemVoucher) {
699  pItemCash = tranIn.GetItem(OTItem::withdrawal);
700  pItem = pItemCash;
701  if (nullptr != pItem) theReplyItemType = OTItem::atWithdrawal;
702  }
703  else {
704  pItem = pItemVoucher;
705  theReplyItemType = OTItem::atWithdrawVoucher;
706  }
707  pResponseItem =
708  OTItem::CreateItemFromTransaction(tranOut, theReplyItemType);
709  pResponseItem->SetStatus(OTItem::rejection); // the default.
710  tranOut.AddItem(*pResponseItem); // the Transaction's destructor will
711  // cleanup the item. It "owns" it now.
712 
713  pResponseBalanceItem =
715  pResponseBalanceItem->SetStatus(OTItem::rejection); // the default.
716  tranOut.AddItem(*pResponseBalanceItem); // the Transaction's destructor will
717  // cleanup the item. It "owns" it
718  // now.
719  if (nullptr == pItem) {
720  OTString strTemp(tranIn);
722  0, "Notary::NotarizeWithdrawal: Expected OTItem::withdrawal or "
723  "OTItem::withdrawVoucher in trans# %ld: \n\n%s\n\n",
724  tranIn.GetTransactionNum(),
725  strTemp.Exists() ? strTemp.Get()
726  : " (ERROR LOADING TRANSACTION INTO STRING) ");
727  }
728  // Below this point, we know that pItem is good, and that either
729  // pItemVoucher OR pItemCash is good,
730  // and that pItem points to the good one. Therefore next, let's verify
731  // permissions:
732  // This permission has to do with ALL withdrawals (cash or voucher)
733  else if (!NYM_IS_ALLOWED(strUserID.Get(),
735  OTLog::vOutput(0, "Notary::NotarizeWithdrawal: User %s cannot do "
736  "this transaction (All withdrawals are disallowed in "
737  "server.cfg)\n",
738  strUserID.Get());
739  }
740  // This permission has to do with vouchers.
741  else if ((nullptr != pItemVoucher) &&
742  (false ==
743  NYM_IS_ALLOWED(strUserID.Get(),
745  OTLog::vOutput(0, "Notary::NotarizeWithdrawal: User %s cannot do "
746  "this transaction (withdrawVoucher is disallowed in "
747  "server.cfg)\n",
748  strUserID.Get());
749  }
750  // This permission has to do with cash.
751  else if ((nullptr != pItemCash) &&
752  (false ==
753  NYM_IS_ALLOWED(strUserID.Get(),
755  OTLog::vOutput(0, "Notary::NotarizeWithdrawal: User %s cannot do "
756  "this transaction (withdraw cash is disallowed in "
757  "server.cfg)\n",
758  strUserID.Get());
759  }
760  // Check for a balance agreement...
761  //
762  else if (nullptr ==
763  (pBalanceItem = tranIn.GetItem(OTItem::balanceStatement))) {
764  OTString strTemp(tranIn);
765  OTLog::vOutput(0, "Notary::NotarizeWithdrawal: Expected "
766  "OTItem::balanceStatement, but not found in trans # "
767  "%ld: \n\n%s\n\n",
768  tranIn.GetTransactionNum(),
769  strTemp.Exists()
770  ? strTemp.Get()
771  : " (ERROR LOADING TRANSACTION INTO STRING) ");
772  }
773  else if (pItem->GetType() == OTItem::withdrawVoucher) {
774  // The response item will contain a copy of the request item. So I save
775  // it into a string
776  // here so they can all grab a copy of it into their "in reference to"
777  // fields.
778  pItem->SaveContractRaw(strInReferenceTo);
779  pBalanceItem->SaveContractRaw(strBalanceItem);
780 
781  // Server response item being added to server response transaction
782  // (tranOut)
783  // (They're getting SOME sort of response item.)
784 
785  pResponseItem->SetReferenceString(strInReferenceTo); // the response
786  // item carries a
787  // copy of what
788  // it's responding
789  // to.
790  pResponseItem->SetReferenceToNum(
791  pItem->GetTransactionNum()); // This response item is IN RESPONSE to
792  // pItem and its Owner Transaction.
793 
794  pResponseBalanceItem->SetReferenceString(
795  strBalanceItem); // the response item carries a copy of what it's
796  // responding to.
797  pResponseBalanceItem->SetReferenceToNum(
798  pItem->GetTransactionNum()); // This response item is IN RESPONSE to
799  // pItem and its Owner Transaction.
800 
801  // OTAccount * pVoucherReserveAcct = nullptr;
802  // contains the server's funds to back vouchers of a specific asset type
803  std::shared_ptr<OTAccount> pVoucherReserveAcct;
804  std::unique_ptr<OTLedger> pInbox(
805  theAccount.LoadInbox(server_->m_nymServer));
806  std::unique_ptr<OTLedger> pOutbox(
807  theAccount.LoadOutbox(server_->m_nymServer));
808 
809  // I'm using the operator== because it exists.
810  // If the ID on the "from" account that was passed in,
811  // does not match the "Acct From" ID on this transaction item.
812  //
813  if (!(ACCOUNT_ID ==
814  pItem->GetPurportedAccountID())) { // TODO see if this is already
815  // verified by the caller
816  // function and if so, remove.
817  OTLog::Output(0, "Error: Account ID does not match account ID on "
818  "the withdrawal item.\n");
819  }
820  else if (nullptr == pInbox) {
821  OTLog::Error("Error loading or verifying inbox.\n");
822  }
823  else if (nullptr == pOutbox) {
824  OTLog::Error("Error loading or verifying outbox.\n");
825  }
826  // The server will already have a special account for issuing vouchers.
827  // Actually, a list of them --
828  // one for each asset type. Since this is the normal way of doing
829  // business, transactor_.getVoucherAccount() will
830  // just create it if it doesn't already exist, and then return the
831  // pointer. Therefore, a failure here
832  // is a catastrophic failure! Should never fail.
833  //
834  else if ((pVoucherReserveAcct = server_->transactor_.getVoucherAccount(
835  ASSET_TYPE_ID)) && // If assignment results in good
836  // pointer...
837  pVoucherReserveAcct->VerifyAccount(
838  server_->m_nymServer)) // and if it
839  // points to
840  // an acct
841  // that
842  // verifies...
843  {
844  OTString strVoucherRequest, strItemNote;
845  pItem->GetNote(strItemNote);
846  pItem->GetAttachment(strVoucherRequest);
847 
848  OTAccount& theVoucherReserveAcct = (*pVoucherReserveAcct);
849  OTIdentifier VOUCHER_ACCOUNT_ID(theVoucherReserveAcct);
850 
851  OTCheque theVoucher(SERVER_ID, ASSET_TYPE_ID),
852  theVoucherRequest(SERVER_ID, ASSET_TYPE_ID);
853 
854  bool bLoadContractFromString =
855  theVoucherRequest.LoadContractFromString(strVoucherRequest);
856 
857  if (!bLoadContractFromString) {
858  OTLog::vError("Notary::%s: ERROR loading voucher request "
859  "from string:\n%s\n",
860  __FUNCTION__, strVoucherRequest.Get());
861  }
862  else if (!server_->transactor_.verifyTransactionNumber(
863  theNym, theVoucherRequest.GetTransactionNum())) {
865  "Notary::%s: Failed verifying transaction number on the "
866  "voucher (%ld) in withdrawal request %ld for Nym: %s\n",
867  __FUNCTION__, theVoucherRequest.GetTransactionNum(),
868  tranIn.GetTransactionNum(), strUserID.Get());
869  }
870  else if (ASSET_TYPE_ID != theVoucherRequest.GetAssetID()) {
871  const OTString strFoundAssetID(theVoucherRequest.GetAssetID());
873  "Notary::%s: Failed verifying asset type ID (%s) on the "
874  "withdraw voucher request (found: %s) "
875  "for transaction %ld, voucher %ld. User: %s\n",
876  __FUNCTION__, strAssetTypeID.Get(), strFoundAssetID.Get(),
877  tranIn.GetTransactionNum(),
878  theVoucherRequest.GetTransactionNum(), strUserID.Get());
879  }
880  else if (!(pBalanceItem->VerifyBalanceStatement(
881  theVoucherRequest.GetAmount() *
882  (-1), // My account's balance will go down by
883  // this much.
884  theNym,
885  *pInbox, *pOutbox, theAccount, tranIn))) {
886  OTLog::vOutput(0, "ERROR verifying balance statement while "
887  "issuing voucher. Acct ID:\n%s\n",
888  strAccountID.Get());
889  }
890  else // successfully loaded the voucher request from the string...
891  {
892  pResponseBalanceItem->SetStatus(
893  OTItem::acknowledgement); // the transaction agreement was
894  // successful.
895  OTString strChequeMemo;
896  strChequeMemo.Format("%s%s", strItemNote.Get(),
897  theVoucherRequest.GetMemo().Get());
898 
899  // 10 minutes == 600 Seconds
900  // 1 hour == 3600 Seconds
901  // 1 day == 86400 Seconds
902  // 30 days == 2592000 Seconds
903  // 3 months == 7776000 Seconds
904  // 6 months == 15552000 Seconds
905 
906  const time64_t VALID_FROM =
907  OTTimeGetCurrentTime(); // This time is set to TODAY NOW
908  const time64_t VALID_TO = OTTimeAddTimeInterval(
909  VALID_FROM,
911 
912  // UPDATE: We now use a transaction number owned by the
913  // remitter, instead of the transaction server.
914  //
915  // int64_t lNewTransactionNumber = 0;
916  // transactor_.issueNextTransactionNumber(server_->m_nymServer,
917  // lNewTransactionNumber); // bStoreTheNumber defaults to true.
918  // We save the transaction
919  // number on the server Nym (normally we'd discard it) because
920  const int64_t lAmount =
921  theVoucherRequest.GetAmount(); // when the cheque is
922  // deposited, the server nym,
923  // as the owner of
924  const OTIdentifier& RECIPIENT_ID =
925  theVoucherRequest.GetRecipientUserID(); // the voucher
926  // account, needs to
927  // verify the
928  // transaction # on
929  // the
930  // cheque (to prevent double-spending of cheques.)
931  bool bIssueVoucher = theVoucher.IssueCheque(
932  lAmount, // The amount of the cheque.
933  theVoucherRequest.GetTransactionNum(), // Requiring a
934  // transaction number
935  // prevents
936  // double-spending of
937  // cheques.
938  VALID_FROM, // The expiration date (valid from/to dates) of
939  // the cheque
940  VALID_TO, // Vouchers are automatically starting today and
941  // lasting 6 months.
942  VOUCHER_ACCOUNT_ID, // The asset account the cheque is drawn
943  // on.
944  SERVER_USER_ID, // User ID of the sender (in this case the
945  // server.)
946  strChequeMemo.Get(), // Optional memo field. Includes item
947  // note and request memo.
948  theVoucherRequest.HasRecipient() ? (&RECIPIENT_ID)
949  : nullptr);
950 
951  // IF we successfully created the voucher, AND the voucher
952  // amount is greater than 0,
953  // AND debited the user's account,
954  // AND credited the server's voucher account,
955  //
956  // THEN save the accounts and return the voucher to the user.
957  //
958  if (bIssueVoucher && (lAmount > 0) &&
959  theAccount.Debit(theVoucherRequest.GetAmount())) {
960  if (false ==
961  pVoucherReserveAcct->Credit(
962  theVoucherRequest.GetAmount())) {
963  OTLog::Error("Notary::NotarizeWithdrawal: Failed "
964  "crediting voucher reserve account.\n");
965 
966  if (false ==
967  theAccount.Credit(theVoucherRequest.GetAmount()))
968  OTLog::Error("Notary::NotarizeWithdrawal "
969  "(voucher): Failed crediting user "
970  "account.\n");
971  }
972  else {
973  OTString strVoucher;
974  theVoucher.SetAsVoucher(
975  USER_ID, ACCOUNT_ID); // All this does is set the
976  // voucher's internal contract
977  // string to
978  // "VOUCHER" instead of "CHEQUE". Plus it saves the
979  // remitter's IDs.
980  theVoucher.SignContract(server_->m_nymServer);
981  theVoucher.SaveContract();
982  theVoucher.SaveContractRaw(strVoucher);
983 
984  pResponseItem->SetAttachment(strVoucher);
985  pResponseItem->SetStatus(OTItem::acknowledgement);
986 
987  bOutSuccess =
988  true; // The withdrawal of a voucher was successful.
989  // Release any signatures that were there before (They
990  // won't
991  // verify anymore anyway, since the content has
992  // changed.)
993  theAccount.ReleaseSignatures();
994  theAccount.SignContract(server_->m_nymServer); // Sign
995  theAccount.SaveContract(); // Save
996  theAccount.SaveAccount(); // Save to file
997 
998  // We also need to save the Voucher cash reserve
999  // account.
1000  // (Any issued voucher cheque is automatically backed by
1001  // this reserve account.
1002  // If a cheque is deposited, the funds come back out of
1003  // this account. If the
1004  // cheque expires, then after the expiry period, if it
1005  // remains in the account,
1006  // it is now the property of the transaction server.)
1007  pVoucherReserveAcct->ReleaseSignatures();
1008  pVoucherReserveAcct->SignContract(server_->m_nymServer);
1009  pVoucherReserveAcct->SaveContract();
1010  pVoucherReserveAcct->SaveAccount();
1011  }
1012  }
1013  // else{} // TODO log that there was a problem with the amount
1014 
1015  } // voucher request loaded successfully from string
1016  } // transactor_.getVoucherAccount()
1017  else {
1018  OTLog::vError(
1019  "transactor_.getVoucherAccount() failed in NotarizeWithdrawal. "
1020  "Asset Type:\n%s\n",
1021  strAssetTypeID.Get());
1022  }
1023  }
1024 
1025  // WITHDRAW DIGITAL CASH (BLINDED TOKENS)
1026  //
1027  // For now, there should only be one of these withdrawal items inside the
1028  // transaction.
1029  // So we treat it that way... I either get it successfully or not.
1030  //
1031  else if (pItem->GetType() == OTItem::withdrawal) {
1032  // The response item will contain a copy of the request item. So I save
1033  // it into a string
1034  // here so they can all grab a copy of it into their "in reference to"
1035  // fields.
1036  //
1037  pItem->SaveContractRaw(strInReferenceTo);
1038  pBalanceItem->SaveContractRaw(strBalanceItem);
1039 
1040  // Server response item being added to server response transaction
1041  // (tranOut)
1042  // They're getting SOME sort of response item.
1043  //
1044  pResponseItem->SetReferenceString(strInReferenceTo); // the response
1045  // item carries a
1046  // copy of what
1047  // it's responding
1048  // to.
1049  pResponseItem->SetReferenceToNum(
1050  pItem->GetTransactionNum()); // This response item is IN RESPONSE to
1051  // pItem and its Owner Transaction.
1052 
1053  pResponseBalanceItem->SetReferenceString(
1054  strBalanceItem); // the response item carries a copy of what it's
1055  // responding to.
1056  pResponseBalanceItem->SetReferenceToNum(
1057  pItem->GetTransactionNum()); // This response item is IN RESPONSE to
1058  // pItem and its Owner Transaction.
1059  std::unique_ptr<OTLedger> pInbox(
1060  theAccount.LoadInbox(server_->m_nymServer));
1061  std::unique_ptr<OTLedger> pOutbox(
1062  theAccount.LoadOutbox(server_->m_nymServer));
1063 
1064  Mint* pMint = nullptr;
1065  OTAccount* pMintCashReserveAcct = nullptr;
1066 
1067  if (0 > pItem->GetAmount()) {
1068  OTLog::Output(0, "Attempt to withdraw a negative amount.\n");
1069  }
1070  // If the ID on the "from" account that was passed in,
1071  // does not match the "Acct From" ID on this transaction item
1072  //
1073  else if (ACCOUNT_ID != pItem->GetPurportedAccountID()) {
1074  OTLog::Output(0, "Error: 'From' account ID on the transaction does "
1075  "not match 'from' account ID on the withdrawal "
1076  "item.\n");
1077  }
1078  else if (nullptr == pInbox) {
1079  OTLog::Error("Error loading or verifying inbox.\n");
1080  }
1081  else if (nullptr == pOutbox) {
1082  OTLog::Error("Error loading or verifying outbox.\n");
1083  }
1084  else {
1085  // The COIN REQUEST (including the prototokens) comes from the
1086  // client side.
1087  // so we assume the Token is in the payload. Now we need to
1088  // randomly choose one for
1089  // signing, and reply to the client with that number so that the
1090  // client can reply back
1091  // to us with the unblinding factors for all the other prototokens
1092  // (but that one.)
1093  //
1094  // In the meantime, I have to store this request somewhere --
1095  // presumably in the outbox or purse.
1096  //
1097  // UPDATE!!! Looks like Lucre protocol is simpler than that. The
1098  // request only needs to contain a
1099  // single blinded token, which the server signs and sends back.
1100  // Done.
1101  //
1102  // The amount is known to be safe (by the mint) because the User
1103  // asks the Mint to create
1104  // a denomination (say, 10) token. The Mint therefore uses the
1105  // "Denomination 10" key to sign
1106  // the token, and will later use the "Denomination 10" key to verify
1107  // the token. So the mint
1108  // obviously trusts its own keys... There is nothing else to "open
1109  // and verify", since only the ID
1110  // itself is what gets blinded and verified. The amount on the
1111  // token (as well as the asset type)
1112  // is only there to help the bank to look up the right key, without
1113  // which the token will DEFINITELY
1114  // NOT verify. So it is in the user's interest to supply the correct
1115  // amount, because otherwise he'll
1116  // just get the wrong key and then get rejected by the bank.
1117 
1118  OTString strPurse;
1119  pItem->GetAttachment(strPurse);
1120 
1121  // Todo do more security checking in here, like making sure the
1122  // withdrawal amount matches the
1123  // total of the proto-tokens. Update: I think this is done, since
1124  // the Debits are done one-at-a-time
1125  // for each token and it's amount/denomination
1126 
1127  Purse thePurse(SERVER_ID, ASSET_TYPE_ID);
1128  Purse theOutputPurse(SERVER_ID, ASSET_TYPE_ID);
1129  Token* pToken = nullptr;
1130  dequeOfTokenPtrs theDeque;
1131 
1132  bool bSuccess = false;
1133  bool bLoadContractFromString =
1134  thePurse.LoadContractFromString(strPurse);
1135 
1136  if (!bLoadContractFromString) {
1137  OTLog::vError("ERROR loading purse from string in "
1138  "Notary::NotarizeWithdrawal:\n%s\n",
1139  strPurse.Get());
1140  }
1141  else if (!(pBalanceItem->VerifyBalanceStatement(
1142  thePurse.GetTotalValue() * (-1), // This amount will
1143  // be subtracted
1144  // from my acct.
1145  theNym, *pInbox, *pOutbox, theAccount, tranIn))) {
1146  OTLog::vOutput(0, "ERROR verifying balance statement while "
1147  "withdrawing cash. Acct ID: %s\n",
1148  strAccountID.Get());
1149  }
1150  else // successfully loaded the purse from the string...
1151  {
1152  pResponseBalanceItem->SetStatus(
1153  OTItem::acknowledgement); // the transaction agreement was
1154  // successful.
1155 
1156  // Pull the token(s) out of the purse that was received from the
1157  // client.
1158  while ((pToken = thePurse.Pop(server_->m_nymServer)) !=
1159  nullptr) {
1160  // We are responsible to cleanup pToken
1161  // So I grab a copy here for later...
1162  theDeque.push_front(pToken);
1163 
1164  pMint = server_->transactor_.getMint(ASSET_TYPE_ID,
1165  pToken->GetSeries());
1166 
1167  if (nullptr == pMint) {
1168  OTLog::vError("Notary::NotarizeWithdrawal: Unable to "
1169  "find Mint (series %d): %s\n",
1170  pToken->GetSeries(),
1171  strAssetTypeID.Get());
1172  bSuccess = false;
1173  break; // Once there's a failure, we ditch the loop.
1174  }
1175  else if (nullptr ==
1176  (pMintCashReserveAcct =
1177  pMint->GetCashReserveAccount())) {
1178  OTLog::vError(
1179  "Notary::NotarizeWithdrawal: Unable to find cash "
1180  "reserve account for Mint (series %d): %s\n",
1181  pToken->GetSeries(), strAssetTypeID.Get());
1182  bSuccess = false;
1183  break; // Once there's a failure, we ditch the loop.
1184  }
1185  // Mints expire halfway into their token expiration period.
1186  // So if a mint creates
1187  // tokens valid from Jan 1 through Jun 1, then the Mint
1188  // itself expires Mar 1.
1189  // That's when the next series Mint is phased in to start
1190  // issuing tokens, even
1191  // though the server continues redeeming the first series
1192  // tokens until June.
1193  //
1194  else if (pMint->Expired()) {
1195  OTLog::vError(
1196  "Notary::NotarizeWithdrawal: User attempting "
1197  "withdrawal with an expired mint (series %d): %s\n",
1198  pToken->GetSeries(), strAssetTypeID.Get());
1199  bSuccess = false;
1200  break; // Once there's a failure, we ditch the loop.
1201  }
1202  else {
1203  OTString theStringReturnVal;
1204 
1205  if (pToken->GetAssetID() != ASSET_TYPE_ID) {
1206  const OTString str1(pToken->GetAssetID()),
1207  str2(ASSET_TYPE_ID);
1208  bSuccess = false;
1209  OTLog::vError("%s: ERROR while signing token: "
1210  "Expected asset ID %s but found %s "
1211  "instead. (Failure.)\n",
1212  __FUNCTION__, str2.Get(), str1.Get());
1213  break;
1214  }
1215  // TokenIndex is for cash systems that send multiple
1216  // proto-tokens, so the Mint
1217  // knows which proto-token has been chosen for signing.
1218  // But Lucre only uses a single proto-token, so the
1219  // token index is always 0.
1220  //
1221  else if (!(pMint->SignToken(server_->m_nymServer,
1222  *pToken, theStringReturnVal,
1223  0))) // nTokenIndex = 0 //
1224  // ******************************************
1225  {
1226  bSuccess = false;
1227  OTLog::vError(
1228  "%s: Failure in call: "
1229  "pMint->SignToken(server_->m_nymServer, "
1230  "*pToken, theStringReturnVal, 0). "
1231  "(Returning.)\n",
1232  __FUNCTION__);
1233  break;
1234  }
1235  else {
1236  OTASCIIArmor theArmorReturnVal(theStringReturnVal);
1237 
1238  pToken->ReleaseSignatures(); // this releases the
1239  // normal signatures,
1240  // not the Lucre signed
1241  // token from the Mint,
1242  // above.
1243 
1244  pToken->SetSignature(theArmorReturnVal,
1245  0); // nTokenIndex = 0
1246 
1247  // Sign and Save the token
1248  pToken->SignContract(server_->m_nymServer);
1249  pToken->SaveContract();
1250 
1251  // Now the token is in signedToken mode, and the
1252  // other prototokens have been released.
1253 
1254  // Deduct the amount from the account...
1255  if (theAccount.Debit(
1256  pToken->GetDenomination())) { // todo need
1257  // to be able
1258  // to "roll
1259  // back" if
1260  // anything
1261  // inside this
1262  // block
1263  // fails.
1264  bSuccess = true;
1265 
1266  // Credit the server's cash account for this
1267  // asset type in the same
1268  // amount that was debited. When the token is
1269  // deposited again, Debit that same
1270  // server cash account and deposit in the
1271  // depositor's acct.
1272  // Why, you might ask? Because if the token
1273  // expires, the money will stay in
1274  // the bank's cash account instead of being lost
1275  // (and screwing up the overall
1276  // issuer balance, with the issued money
1277  // disappearing forever.) The bank knows
1278  // that once the series expires, whatever funds
1279  // are left in that cash account are
1280  // for the bank to keep. They can be transferred
1281  // to another account and kept, instead
1282  // of being lost.
1283  if (!pMintCashReserveAcct->Credit(
1284  pToken->GetDenomination())) {
1285  OTLog::Error("Error crediting mint cash "
1286  "reserve account...\n");
1287 
1288  // Reverse the account debit (even though
1289  // we're not going to save it anyway.)
1290  if (false ==
1291  theAccount.Credit(
1292  pToken->GetDenomination()))
1293  OTLog::vError("%s: Failed crediting "
1294  "user account back.\n",
1295  __FUNCTION__);
1296 
1297  bSuccess = false;
1298  break;
1299  }
1300  }
1301  else {
1302  bSuccess = false;
1303  OTLog::vOutput(0, "%s: Unable to debit account "
1304  "%s in the amount of: %ld\n",
1305  __FUNCTION__, strAccountID.Get(),
1306  pToken->GetDenomination());
1307  break; // Once there's a failure, we ditch the
1308  // loop.
1309  }
1310  }
1311  }
1312  } // While success popping token out of the purse...
1313 
1314  if (bSuccess) {
1315  while (!theDeque.empty()) {
1316  pToken = theDeque.front();
1317  theDeque.pop_front();
1318 
1319  theOutputPurse.Push(theNym, *pToken); // these were in
1320  // reverse order.
1321  // Fixing with
1322  // theDeque.
1323 
1324  delete pToken;
1325  pToken = nullptr;
1326  }
1327 
1328  strPurse.Release(); // just in case it only concatenates.
1329 
1330  theOutputPurse.SignContract(server_->m_nymServer);
1331  theOutputPurse.SaveContract(); // todo this is probably
1332  // unnecessary
1333  theOutputPurse.SaveContractRaw(strPurse);
1334 
1335  // Add the digital cash token to the response message
1336  pResponseItem->SetAttachment(strPurse);
1337  pResponseItem->SetStatus(OTItem::acknowledgement);
1338 
1339  bOutSuccess = true; // The cash withdrawal was successful.
1340 
1341  // Release any signatures that were there before (They won't
1342  // verify anymore anyway, since the content has changed.)
1343  theAccount.ReleaseSignatures();
1344 
1345  // Sign
1346  theAccount.SignContract(server_->m_nymServer);
1347 
1348  // Save
1349  theAccount.SaveContract();
1350 
1351  // Save to file
1352  theAccount.SaveAccount();
1353 
1354  // We also need to save the Mint's cash reserve.
1355  // (Any cash issued by the Mint is automatically backed by
1356  // this reserve
1357  // account. If cash is deposited, it comes back out of this
1358  // account. If the
1359  // cash expires, then after the expiry period, if it remains
1360  // in the account,
1361  // it is now the property of the transaction server.)
1362  pMintCashReserveAcct->ReleaseSignatures();
1363  pMintCashReserveAcct->SignContract(server_->m_nymServer);
1364  pMintCashReserveAcct->SaveContract();
1365  pMintCashReserveAcct->SaveAccount();
1366 
1367  // Notice if there is any failure in the above loop, then we
1368  // will never enter this block.
1369  // Therefore the account will never be saved with the new
1370  // debited balance, and the output
1371  // purse will never be added to the response item. No
1372  // tokens will be returned to the user
1373  // and the account will not be saved, thus retaining the
1374  // original balance.
1375  //
1376  // Only if everything is successful do we enter this block,
1377  // save the output purse onto the
1378  // response, and save the newly-debitted account back to
1379  // disk.
1380  }
1381  // Still need to clean up theDeque
1382  else {
1383  while (!theDeque.empty()) {
1384  pToken = theDeque.front();
1385  theDeque.pop_front();
1386 
1387  delete pToken;
1388  pToken = nullptr;
1389  }
1390  }
1391 
1392  } // purse loaded successfully from string
1393 
1394  } // the Account ID on the item matched properly
1395  // sign the response item before sending it back (it's already been
1396  // added to the transaction above)
1397  // Now, whether it was rejection or acknowledgement, it is set properly
1398  // and it is signed, and it
1399  // is owned by the transaction, who will take it from here.
1400  pResponseItem->SignContract(server_->m_nymServer);
1401  pResponseItem->SaveContract(); // the signing was of no effect because I
1402  // forgot to save.
1403 
1404  pResponseBalanceItem->SignContract(server_->m_nymServer);
1405  pResponseBalanceItem->SaveContract();
1406  }
1407  else {
1408  OTString strTemp(tranIn);
1410  0, "Notary::NotarizeWithdrawal: Expected OTItem::withdrawal or "
1411  "OTItem::withdrawVoucher in trans# %ld: \n\n%s\n\n",
1412  tranIn.GetTransactionNum(),
1413  strTemp.Exists() ? strTemp.Get()
1414  : " (ERROR LOADING TRANSACTION INTO STRING) ");
1415  }
1416 
1417  // sign the response item before sending it back (it's already been added to
1418  // the transaction above)
1419  // Now, whether it was rejection or acknowledgement, it is set properly and
1420  // it is signed, and it
1421  // is owned by the transaction, who will take it from here.
1422  pResponseItem->SignContract(server_->m_nymServer);
1423  pResponseItem->SaveContract(); // the signing was of no effect because I
1424  // forgot to save.
1425 
1426  pResponseBalanceItem->SignContract(server_->m_nymServer);
1427  pResponseBalanceItem->SaveContract();
1428 }
static EXPORT void vError(const char *szError,...)
Definition: OTLog.cpp:800
std::deque< Token * > dequeOfTokenPtrs
Definition: Notary.cpp:167
static EXPORT void Output(int32_t nVerbosity, const char *szOutput)
Definition: OTLog.cpp:710
static bool __transact_withdraw_cash
time64_t OTTimeAddTimeInterval(time64_t lhs, int64_t rhs)
Definition: Common.hpp:238
#define NYM_IS_ALLOWED(SZ_NYM_ID, BOOL_VAR_NAME)
Definition: Macros.hpp:146
bool verifyTransactionNumber(OTPseudonym &nym, const int64_t &transactionNumber)
Definition: Transactor.cpp:278
int64_t time64_t
Definition: Common.hpp:209
std::shared_ptr< OTAccount > getVoucherAccount(const OTIdentifier &assetTypeId)
Definition: Transactor.cpp:536
#define OT_TIME_SIX_MONTHS_IN_SECONDS
Definition: Common.hpp:170
static EXPORT OTItem * CreateItemFromTransaction(const OTTransaction &theOwner, OTItem::itemType theType, const OTIdentifier *pDestinationAcctID=nullptr)
Definition: OTItem.cpp:1451
static EXPORT void Error(const char *szError)
Definition: OTLog.cpp:831
Mint * getMint(const OTIdentifier &assetTypeId, int32_t seriesCount)
Lookup the current mint for any given asset type ID and series.
Definition: Transactor.cpp:565
time64_t OTTimeGetCurrentTime()
Definition: Common.hpp:211
static bool __transact_withdraw_voucher
int64_t OTTimeGetSecondsFromTime(time64_t time)
Definition: Common.hpp:230
static EXPORT void vOutput(int32_t nVerbosity, const char *szOutput,...)
Definition: OTLog.cpp:768

The documentation for this class was generated from the following files: