Exemplo n.º 1
0
// This is called by OTCronItem::HookRemovalFromCron
// (After calling this method, HookRemovalFromCron then calls
// onRemovalFromCron.)
//
void OTTrade::onFinalReceipt(OTCronItem& origCronItem,
                             const int64_t& newTransactionNumber,
                             Nym& originator, Nym* remover)
{
    const char* szFunc = "OTTrade::onFinalReceipt";

    OTCron* cron = GetCron();
    OT_ASSERT(cron != nullptr);

    Nym* serverNym = cron->GetServerNym();
    OT_ASSERT(serverNym != nullptr);

    // First, we are closing the transaction number ITSELF, of this cron item,
    // as an active issued number on the originating nym. (Changing it to
    // CLOSED.)
    //
    // Second, we're verifying the CLOSING number, and using it as the closing
    // number
    // on the FINAL RECEIPT (with that receipt being "InReferenceTo"
    // GetTransactionNum())
    //
    const int64_t openingNumber = origCronItem.GetTransactionNum();

    const int64_t closingAssetNumber =
        (origCronItem.GetCountClosingNumbers() > 0)
            ? origCronItem.GetClosingTransactionNoAt(0)
            : 0;
    const int64_t closingCurrencyNumber =
        (origCronItem.GetCountClosingNumbers() > 1)
            ? origCronItem.GetClosingTransactionNoAt(1)
            : 0;

    const String notaryID(GetNotaryID());

    // The marketReceipt ITEM's NOTE contains the UPDATED TRADE.
    // And the **UPDATED OFFER** is stored on the ATTACHMENT on the **ITEM.**
    //
    // BUT!!! This is not a marketReceipt Item, is it? ***This is a finalReceipt
    // ITEM!***
    // I'm reversing note and attachment for finalReceipt, with the
    // intention of
    // eventually reversing them for marketReceipt as well. (Making them all in
    // line with paymentReceipt.)
    //
    // WHY?  Because I want a standard convention:
    //          1. ORIGINAL (user-signed) Cron Items are always stored "in
    // reference to" on cron receipts in the Inbox (an OTTransaction).
    //          2. The UPDATED VERSION of that same cron item (a trade or
    // payment plan) is stored in the ATTACHMENT on the OTItem member.
    //          3. ADDITIONAL INFORMATION is stored in the NOTE field of the
    // OTItem member.
    //
    // Unfortunately, marketReceipt doesn't adhere to this convention, as it
    // stores the Updated Cron Item (the trade) in
    // the note instead of the attachment, and it stores the updated Offer (the
    // additional info) in the attachment instead
    // of the note.
    // Perhaps this is for the best -- it will certainly kick out any accidental
    // confusions between marketReceipt and finalReceipt!
    // todo: switch marketReceipt over to be like finalReceipt as described in
    // this paragraph.
    //
    // Once everything is consistent on the above convention -- starting here
    // and now with finalReceipt -- then we will ALWAYS
    // be able to count on a Cron Item being in the Transaction Item's
    // Attachment! We can load it using the existing factory class,
    // without regard to type, KNOWING it's a cron item every time.
    // todo: convert marketReceipt to do the same.

    // The finalReceipt Item's ATTACHMENT contains the UPDATED Cron Item.
    // (With the SERVER's signature on it!)
    //
    String updatedCronItem(*this);
    String* attachment = &updatedCronItem; // the Updated TRADE.
    String updatedOffer;
    String* note = nullptr; // the updated Offer (if available.)

    if (offer_) {
        offer_->SaveContractRaw(updatedOffer);
        note = &updatedOffer;
    }

    const String strOrigCronItem(origCronItem);

    Nym theActualNym; // unused unless it's really not already loaded.
                      // (use actualNym.)

    // The OPENING transaction number must still be signed-out.
    // It is this act of placing the final receipt, which then finally closes
    // the opening number.
    // The closing number, by contrast, is not closed out until the final
    // Receipt is ACCEPTED
    // (which happens in a "process inbox" transaction.)
    //
    if ((openingNumber > 0) &&
        originator.VerifyIssuedNum(notaryID, openingNumber)) {
        // The Nym (server side) stores a list of all opening and closing cron
        // #s.
        // So when the number is released from the Nym, we also take it off that
        // list.
        //
        std::set<int64_t>& idSet = originator.GetSetOpenCronItems();
        idSet.erase(openingNumber);

        originator.RemoveIssuedNum(*serverNym, notaryID, openingNumber,
                                   false);        // bSave=false
        originator.SaveSignedNymfile(*serverNym); // forcing a save here,
                                                  // since multiple things
                                                  // have changed.

        const Identifier& actualNymId = GetSenderNymID();

        Nym* actualNym = nullptr; // use this. DON'T use theActualNym.
        if ((serverNym != nullptr) && serverNym->CompareID(actualNymId))
            actualNym = serverNym;
        else if (originator.CompareID(actualNymId))
            actualNym = &originator;
        else if ((remover != nullptr) && remover->CompareID(actualNymId))
            actualNym = remover;

        else // We couldn't find the Nym among those already loaded--so we have
             // to load
        {    // it ourselves (so we can update its NymboxHash value.)
            theActualNym.SetIdentifier(actualNymId);

            if (!theActualNym.LoadPublicKey()) // Note: this step may be
                                               // unnecessary since we
                                               // are only updating his
                                               // Nymfile, not his key.
            {
                String strNymID(actualNymId);
                otErr << szFunc
                      << ": Failure loading public key for Nym : " << strNymID
                      << ". "
                         "(To update his NymboxHash.) \n";
            }
            else if (theActualNym.VerifyPseudonym() && // this line may be
                                                         // unnecessary.
                       theActualNym.LoadSignedNymfile(
                           *serverNym)) // ServerNym here is not theActualNym's
                                        // identity, but merely the signer on
                                        // this file.
            {
                otLog3
                    << szFunc
                    << ": Loading actual Nym, since he wasn't already loaded. "
                       "(To update his NymboxHash.)\n";
                actualNym = &theActualNym; //  <=====
            }
            else {
                String strNymID(actualNymId);
                otErr
                    << szFunc
                    << ": Failure loading or verifying Actual Nym public key: "
                    << strNymID << ". "
                                   "(To update his NymboxHash.)\n";
            }
        }

        if (!DropFinalReceiptToNymbox(GetSenderNymID(), newTransactionNumber,
                                      strOrigCronItem, note, attachment,
                                      actualNym)) {
            otErr << szFunc << ": Failure dropping receipt into nymbox.\n";
        }
    }
    else {
        otErr << szFunc << ": Problem verifying Opening Number when calling "
                           "VerifyIssuedNum(openingNumber)\n";
    }

    // ASSET ACCT
    //
    if ((closingAssetNumber > 0) &&
        originator.VerifyIssuedNum(notaryID, closingAssetNumber)) {
        DropFinalReceiptToInbox(
            GetSenderNymID(), GetSenderAcctID(), newTransactionNumber,
            closingAssetNumber, // The closing transaction number to put on the
                                // receipt.
            strOrigCronItem, note, attachment);
    }
    else {
        otErr << szFunc
              << ": Failed verifying "
                 "closingAssetNumber=origCronItem."
                 "GetClosingTransactionNoAt(0)>0 &&  "
                 "originator.VerifyTransactionNum(closingAssetNumber)\n";
    }

    // CURRENCY ACCT
    //
    if ((closingCurrencyNumber > 0) &&
        originator.VerifyIssuedNum(notaryID, closingCurrencyNumber)) {
        DropFinalReceiptToInbox(
            GetSenderNymID(), GetCurrencyAcctID(), newTransactionNumber,
            closingCurrencyNumber, // closing transaction number for the
                                   // receipt.
            strOrigCronItem, note, attachment);
    }
    else {
        otErr << szFunc
              << ": Failed verifying "
                 "closingCurrencyNumber=origCronItem."
                 "GetClosingTransactionNoAt(1)>0 "
                 "&&  "
                 "originator.VerifyTransactionNum(closingCurrencyNumber)\n";
    }

    // the RemoveIssued call means the original transaction# (to find this cron
    // item on cron) is now CLOSED.
    // But the Transaction itself is still OPEN. How? Because the CLOSING number
    // is still signed out.
    // The closing number is also USED, since the NotarizePaymentPlan or
    // NotarizeMarketOffer call, but it
    // remains ISSUED, until the final receipt itself is accepted during a
    // process inbox.
    //
    //    if (bDroppedReceiptAssetAcct || bDroppedReceiptCurrencyAcct)  // ASSET
    // ACCOUNT and CURRENCY ACCOUNT
    //    {
    // This part below doesn't happen until you ACCEPT the finalReceipt (when
    // processing your inbox.)
    //
    //      if (bDroppedReceiptAssetAcct)
    //          originator.RemoveIssuedNum(notaryID, closingAssetNumber,
    // true); //bSave=false
    //      else if (bDroppedReceiptCurrencyAcct)
    //          originator.RemoveIssuedNum(notaryID,
    // closingCurrencyNumber, true); //bSave=false
    //    }
    //    else
    //    {
    //        otErr << "OTTrade::onFinalReceipt: Failure dropping receipt into
    // asset or currency inbox.\n";
    //    }

    // QUESTION: Won't there be Cron Items that have no asset account at all?
    // In which case, there'd be no need to drop a final receipt, but I don't
    // think
    // that's the case, since you have to use a transaction number to get onto
    // cron
    // in the first place.
}
Exemplo n.º 2
0
// This is called by OTCronItem::HookRemovalFromCron
// (After calling this method, HookRemovalFromCron then calls onRemovalFromCron.)
//
void OTAgreement::onFinalReceipt(OTCronItem & theOrigCronItem,
                                 const long & lNewTransactionNumber,
                                 OTPseudonym & theOriginator,
                                 OTPseudonym * pRemover)
{    
    OTCron * pCron  = GetCron();
    OT_ASSERT(NULL != pCron);
    
    OTPseudonym * pServerNym = pCron->GetServerNym();
    OT_ASSERT(NULL != pServerNym);
    
    // -------------------------------------------------
    
    // The finalReceipt Item's ATTACHMENT contains the UPDATED Cron Item.
    // (With the SERVER's signature on it!)
    //
    OTString strUpdatedCronItem(*this);
    OTString * pstrAttachment=&strUpdatedCronItem;
    
    const OTString strOrigCronItem(theOrigCronItem);
    // -----------------------------------------------------------------

    
    OTPseudonym theRecipientNym; // Don't use this... use the pointer just below.
    
    // The Nym who is actively requesting to remove a cron item will be passed in as pRemover.
    // However, sometimes there is no Nym... perhaps it just expired and pRemover is NULL.
    // The originating Nym (if different than remover) is loaded up. Otherwise the originator
    // pointer just pointers to *pRemover.
    //
    OTPseudonym * pRecipient = NULL;
    
    if (pServerNym->CompareID(this->GetRecipientUserID()))
    {
        pRecipient = pServerNym; // Just in case the recipient Nym is also the server Nym.
    }
    // *******************************************************
    //
    // If pRemover is NOT NULL, and he has the Recipient's ID...
    // then set the pointer accordingly.
    //
    else if ((NULL != pRemover) && (true == pRemover->CompareID(this->GetRecipientUserID())))
    {
        pRecipient = pRemover; // <======== now both pointers are set (to same Nym). DONE!
    }
    // --------------------------------------------------------------------------------------------------

    if (NULL == pRecipient)
    {
        // GetSenderUserID() should be the same on THIS (updated version of the same cron item) 
        // but for whatever reason, I'm checking the userID on the original version. Sue me.
        //
        const OTIdentifier NYM_ID(this->GetRecipientUserID());
        
        theRecipientNym.SetIdentifier(NYM_ID);  
        
        if (false == theRecipientNym.LoadPublicKey())
        {
            OTString strNymID(NYM_ID);
            OTLog::vError("OTAgreement::onFinalReceipt: Failure loading Recipient's public key:\n%s\n", strNymID.Get());
        }		
        else if (theRecipientNym.VerifyPseudonym() && 
                 theRecipientNym.LoadSignedNymfile(*pServerNym)) // ServerNym here is merely the signer on this file.
        {
            pRecipient = &theRecipientNym; //  <=====
        }
        else 
        {
            OTString strNymID(NYM_ID);
            OTLog::vError("OTAgreement::onFinalReceipt: Failure verifying Recipient's public key or loading signed nymfile: %s\n",
                          strNymID.Get());
        }
    }
    
    // -------------------------------

    // First, we are closing the transaction number ITSELF, of this cron item,
    // as an active issued number on the originating nym. (Changing it to CLOSED.)
    //
    // Second, we're verifying the CLOSING number, and using it as the closing number
    // on the FINAL RECEIPT (with that receipt being "InReferenceTo" this->GetTransactionNum())
    //
    const long lRecipientOpeningNumber = this->GetRecipientOpeningNum();
    const long lRecipientClosingNumber = this->GetRecipientClosingNum();
    
    // -----------------------------------------------------------------------------------
    const long lSenderOpeningNumber = theOrigCronItem.GetTransactionNum();

    const long lSenderClosingNumber = (theOrigCronItem.GetCountClosingNumbers() > 0) ? 
        theOrigCronItem.GetClosingTransactionNoAt(0) : 0; // index 0 is closing number for sender, since GetTransactionNum() is his opening #.
    
    // ----------------------------------
        
    const OTString strServerID(GetServerID());
    
    // -----------------------------------------------------------------
    //
    
    if ((lSenderOpeningNumber > 0) &&
        theOriginator.VerifyIssuedNum(strServerID, lSenderOpeningNumber))
    {
        // The Nym (server side) stores a list of all opening and closing cron #s.
        // So when the number is released from the Nym, we also take it off that list.
        //
        std::set<long> & theIDSet = theOriginator.GetSetOpenCronItems();
        theIDSet.erase(lSenderOpeningNumber);
        
        // the RemoveIssued call means the original transaction# (to find this cron item on cron) is now CLOSED.
        // But the Transaction itself is still OPEN. How? Because the CLOSING number is still signed out.
        // The closing number is also USED, since the NotarizePaymentPlan or NotarizeMarketOffer call, but it
        // remains ISSUED, until the final receipt itself is accepted during a process inbox.
        //
        theOriginator.RemoveIssuedNum(*pServerNym, strServerID, lSenderOpeningNumber, false); //bSave=false
        theOriginator.SaveSignedNymfile(*pServerNym);
        // ------------------------------------
        
        OTPseudonym *   pActualNym = NULL;  // use this. DON'T use theActualNym.
        OTPseudonym     theActualNym; // unused unless it's really not already loaded. (use pActualNym.)
        const OTIdentifier ACTUAL_NYM_ID = GetSenderUserID();
        
        if ( (NULL != pServerNym) && pServerNym->CompareID(ACTUAL_NYM_ID) )
            pActualNym = pServerNym;
        else if (theOriginator.CompareID(ACTUAL_NYM_ID))
            pActualNym = &theOriginator;
        else if ( (NULL != pRemover) && pRemover->CompareID(ACTUAL_NYM_ID) )
            pActualNym = pRemover;
        // --------------------------
        else    // We couldn't find the Nym among those already loaded--so we have to load
        {       // it ourselves (so we can update its NymboxHash value.)
            theActualNym.SetIdentifier(ACTUAL_NYM_ID);
            
            if (false == theActualNym.LoadPublicKey()) // Note: this step may be unnecessary since we are only updating his Nymfile, not his key.
            {
                OTString strNymID(ACTUAL_NYM_ID);
                OTLog::vError("OTAgreement::onFinalReceipt: Failure loading public key for Nym: %s. "
                              "(To update his NymboxHash.) \n", strNymID.Get());
            }
            else if (theActualNym.VerifyPseudonym()	&& // this line may be unnecessary.
                     theActualNym.LoadSignedNymfile(*pServerNym)) // ServerNym here is not theActualNym's identity, but merely the signer on this file.
            {
                OTLog::Output(0, "OTAgreement::onFinalReceipt: Loading actual Nym, since he wasn't already loaded. "
                              "(To update his NymboxHash.)\n");
                pActualNym = &theActualNym; //  <=====
            }
            else
            {
                OTString strNymID(ACTUAL_NYM_ID);
                OTLog::vError("OTAgreement::onFinalReceipt: Failure loading or verifying Actual Nym public key: %s. "
                              "(To update his NymboxHash.)\n", strNymID.Get());
            }
        }
        // -------------
        
        if (false == this->DropFinalReceiptToNymbox(GetSenderUserID(),
                                                    lNewTransactionNumber,
                                                    strOrigCronItem,
                                                    NULL,
                                                    pstrAttachment,
                                                    pActualNym))
        {
            OTLog::Error("OTAgreement::onFinalReceipt: Failure dropping sender final receipt into nymbox.\n");
        }        
    }
    else
    {
        OTLog::Error("OTAgreement::onFinalReceipt: Failure verifying sender's opening number.\n");
    }
    
    // -----------------------------------------------------------------
    
    if ((lSenderClosingNumber > 0) &&
        theOriginator.VerifyIssuedNum(strServerID, lSenderClosingNumber)         
        ) // ---------------------------------------------------------------
    {
        // In this case, I'm passing NULL for pstrNote, since there is no note.
        // (Additional information would normally be stored in the note.) 
        
        if (false == this->DropFinalReceiptToInbox(GetSenderUserID(),
                                          GetSenderAcctID(),
                                          lNewTransactionNumber,
                                          lSenderClosingNumber, // The closing transaction number to put on the receipt.
                                          strOrigCronItem,
                                          NULL, 
                                          pstrAttachment))
            OTLog::Error("OTAgreement::onFinalReceipt: Failure dropping receipt into sender's inbox.\n");

        // This part below doesn't happen until theOriginator ACCEPTS the final receipt (when processing his inbox.)
        //
//      theOriginator.RemoveIssuedNum(strServerID, lSenderClosingNumber, true); //bSave=false
    }
    else
    {
        OTLog::Error("OTAgreement::onFinalReceipt: Failed verifying lSenderClosingNumber=theOrigCronItem.GetClosingTransactionNoAt(0)>0 &&  "
                     "theOriginator.VerifyTransactionNum(lSenderClosingNumber)\n");
    }
    // -----------------------------------------------------------------
    //
    if ((NULL != pRecipient) && (lRecipientOpeningNumber > 0) && 
        pRecipient->VerifyIssuedNum(strServerID, lRecipientOpeningNumber)
        )
    {
        // The Nym (server side) stores a list of all opening and closing cron #s.
        // So when the number is released from the Nym, we also take it off that list.
        //
        std::set<long> & theIDSet = pRecipient->GetSetOpenCronItems();
        theIDSet.erase(lRecipientOpeningNumber);
        
        // the RemoveIssued call means the original transaction# (to find this cron item on cron) is now CLOSED.
        // But the Transaction itself is still OPEN. How? Because the CLOSING number is still signed out.
        // The closing number is also USED, since the NotarizePaymentPlan or NotarizeMarketOffer call, but it
        // remains ISSUED, until the final receipt itself is accepted during a process inbox.
        //
        pRecipient->RemoveIssuedNum(*pServerNym, strServerID, lRecipientOpeningNumber, false); //bSave=false       
//      pRecipient->SaveSignedNymfile(*pServerNym); // Moved lower.
        // -----------------------------------------------------
        
        if (false == this->DropFinalReceiptToNymbox(GetRecipientUserID(),
                                                    lNewTransactionNumber,
                                                    strOrigCronItem,
                                                    NULL,
                                                    pstrAttachment,
                                                    pRecipient)) // NymboxHash is updated here in pRecipient.
        {
            OTLog::Error("OTAgreement::onFinalReceipt: Failure dropping recipient final receipt into nymbox.\n");
        }
        // -----------------------------------------------------

        // Saving both the Removed Issued Number, as well as the new NymboxHash.
        // NOTE: Todo: if the NymboxHash WAS updated (as it should have been) then
        // it was probably saved at that time. Below is therefore a redundant save.
        // Need to fix by making certain objects savable and dirty, and then let them
        // autosave before destruction, IF they are dirty.
        //
        pRecipient->SaveSignedNymfile(*pServerNym); 
    }
    else
    {
        OTLog::Error("OTAgreement::onFinalReceipt: Failed verifying "
                     "lRecipientClosingNumber=this->GetRecipientClosingTransactionNoAt(1)>0 &&  "
                     "pRecipient->VerifyTransactionNum(lRecipientClosingNumber) && VerifyIssuedNum(lRecipientOpeningNumber)\n");
    }
    
    // -----------------------------------------------------------------
    
    if ((NULL != pRecipient) && (lRecipientClosingNumber > 0) && 
        pRecipient->VerifyIssuedNum(strServerID, lRecipientClosingNumber)
        )
    {
        if (false == this->DropFinalReceiptToInbox(GetRecipientUserID(),
                                      GetRecipientAcctID(),
                                      lNewTransactionNumber,
                                      lRecipientClosingNumber, // The closing transaction number to put on the receipt.
                                      strOrigCronItem,
                                      NULL,
                                      pstrAttachment))
            OTLog::Error("OTAgreement::onFinalReceipt: Failure dropping receipt into recipient's inbox.\n");

        // This part below doesn't happen until pRecipient ACCEPTs the final receipt (when processing his inbox.)
        //
//      pRecipient->RemoveIssuedNum(strServerID, lRecipientClosingNumber, true); //bSave=false
    }
    else
    {
        OTLog::Error("OTAgreement::onFinalReceipt: Failed verifying "
                     "lRecipientClosingNumber=this->GetRecipientClosingTransactionNoAt(1)>0 &&  "
                     "pRecipient->VerifyTransactionNum(lRecipientClosingNumber) && VerifyIssuedNum(lRecipientOpeningNumber)\n");
    }
    
    // QUESTION: Won't there be Cron Items that have no asset account at all?
    // In which case, there'd be no need to drop a final receipt, but I don't think
    // that's the case, since you have to use a transaction number to get onto cron
    // in the first place.
    // -----------------------------------------------------------------
}