Пример #1
0
// Assuming the offer is ON the market, this will get the pointer to that offer.
// Otherwise it will try to add it to the market.
// Otherwise it will fail. (Perhaps it's a stop order, and not ready to activate
// yet.)
//
OTOffer* OTTrade::GetOffer(Identifier* offerMarketId, OTMarket** market)
{
    OT_ASSERT(GetCron() != nullptr);

    // See if the offer has already been instantiated onto a market...
    if (offer_ != nullptr) {
        offer_->SetTrade(*this); // Probably don't need this line. I'll remove
                                 // it someday while optimizing.
        // In fact since it should already be set, having this here would
        // basically
        // hide it from me if the memory was ever walked on from a bug
        // somewhere.

        // It loaded. Let's get the Market ID off of it so we can locate the
        // market.
        const Identifier OFFER_MARKET_ID(*offer_);

        if (market != nullptr) {
            OTMarket* pMarket = GetCron()->GetMarket(OFFER_MARKET_ID);

            // Sometimes the caller function would like a copy of this market
            // pointer, when available.
            // So I pass it back to him here, if he wants. That way he doesn't
            // have to do this work again
            // to look it up.
            if (pMarket != nullptr)
                *market = pMarket; // <=================
            else
                otErr << "OTTrade::" << __FUNCTION__
                      << ": offer_ already exists, yet unable to find the "
                         "market it's supposed to be on.\n";
        }

        if (offerMarketId != nullptr) {
            // Sometimes the caller function would like a copy of this ID. So I
            // give the option to pass in a pointer so I can give it here.
            offerMarketId->Assign(OFFER_MARKET_ID);
        }

        return offer_;
    } // if offer_ ALREADY EXISTS.

    // else (BELOW) offer_ IS nullptr, and thus it didn't exist yet...

    if (!marketOffer_.Exists()) {
        otErr << "OTTrade::GetOffer called with empty marketOffer_.\n";
        return nullptr;
    }

    OTOffer* offer = new OTOffer();
    OT_ASSERT(offer != nullptr);

    // Trying to load the offer from the trader's original signed request
    // (So I can use it to lookup the Market ID, so I can see the offer is
    // already there on the market.)
    if (!offer->LoadContractFromString(marketOffer_)) {
        otErr << "Error loading offer from string in OTTrade::GetOffer\n";
        delete offer;
        offer = nullptr;
        return nullptr;
    }

    // No need to do any additional security verification here on the Offer,
    // since the Offer is already heavily verified in
    // OTServer::NotarizeMarketOffer().
    // So as long as you feel safe about the Trade, then you can feel safe about
    // the Offer already, with no further checks.
    // *Also remember we saved a copy of the original in the cron folder.

    // It loaded. Let's get the Market ID off of it so we can locate the market.
    Identifier OFFER_MARKET_ID(*offer);

    if (offerMarketId != nullptr) {
        // Sometimes the caller function would like a copy of this ID. So I
        // give the option to pass in a pointer so I can give it here.
        offerMarketId->Assign(OFFER_MARKET_ID);
    }

    // Previously if a user tried to use a market that didn't exist, I'd just
    // return failure.
    // But now we will create any market that doesn't already exist.
    // (Remember, the server operator could just erase the market folder--it
    // wouldn't
    // affect anyone's balances!) Update: he probably couldn't just wipe the
    // markets folder,
    // actually, without making it impossible for certain Nyms to get rid of
    // certain issued #s.
    //
    //    OTMarket * pMarket = m_cron->GetMarket(OFFER_MARKET_ID);
    OTMarket* pMarket = GetCron()->GetOrCreateMarket(
        GetInstrumentDefinitionID(), GetCurrencyID(), offer->GetScale());

    // Couldn't find (or create) the market.
    if (pMarket == nullptr) {
        otOut
            << "OTTrade::" << __FUNCTION__
            << ": Unable to find or create market within requested parameters.";
        delete offer;
        offer = nullptr;
        return nullptr;
    }

    // If the caller passed in the address of a market pointer (optional)
    if (market != nullptr) {
        // Sometimes the caller function would like a copy of this market
        // pointer, when available.
        // So I pass it back to him here, if he wants. That way he doesn't have
        // to do this work again
        // to look it up.
        *market = pMarket;
    }

    // At this point, I have heap-allocated the offer, used it to get the Market
    // ID, and successfully
    // used that to get a pointer to the market matching that ID.
    //
    // Let's see if the offer is ALREADY allocated and on this market!
    // If so, delete the one I just allocated. If not, add it to the market.
    OTOffer* marketOffer = pMarket->GetOffer(offer->GetTransactionNum());

    // The Offer is already on the Market.
    // NOTE: It may just start out this way, without ever being added.
    // How is that possible? Because maybe it was in the market file when we
    // first loaded up,
    // and had been added on some previous run of the software. So since we
    // started running,
    // the pMarket->AddOffer() code below has literally never run for that
    // offer. Instead we
    // first find it here, and thus return the pointer before getting any
    // farther.
    //
    // IN ALL CASES, we make sure to call offer_->SetTrade() so that it has a
    // pointer BACK to
    // this Trade object! (When actually processing the offer, the market will
    // need the account
    // numbers and Nym IDs... which are stored here on the trade.)
    if (marketOffer != nullptr) {
        offer_ = marketOffer;

        // Since the Offer already exists on the market, no need anymore for the
        // one we allocated above (to get the market ID.) So we delete it now.
        delete offer;
        offer = nullptr;

        offer_->SetTrade(*this);

        return offer_;
    }

    // Okay so the offer ISN'T already on the market. If it's not a stop order,
    // let's ADD the one we
    // allocated to the market now! (Stop orders are activated through their own
    // logic, which is below
    // this, in the else block.)
    //
    if (!IsStopOrder()) {
        if (hasTradeActivated_) {
            // Error -- how has the trade already activated, yet not on the
            // market and null in my pointer?
            otErr << "How has the trade already activated, yet not on the "
                     "market and null in my pointer?\n";
        }
        else if (!pMarket->AddOffer(this, *offer, true)) // Since we're
                                                           // actually adding
                                                           // an offer to the
                                                           // market (not just
        { // loading from disk) the we actually want to save the market.
            // bSaveFile=true.
            // Error adding the offer to the market!
            otErr << "Error adding the offer to the market! (Even though "
                     "supposedly the right market.)\n";
        }
        else {
            // SUCCESS!
            offer_ = offer;

            hasTradeActivated_ = true;

            // The Trade (stored on Cron) has a copy of the Original Offer, with
            // the User's signature on it.
            // A copy of that original Trade object (itself with the user's
            // signature) is already stored in
            // the cron folder (by transaction number.) This happens when the
            // Trade is FIRST added to cron,
            // so it's already safe before we even get here.
            //
            // So thus I am FREE to release the signatures on the offer, and
            // sign with the server instead.
            // The server-signed offer will be stored by the OTMarket.
            offer_->ReleaseSignatures();
            offer_->SignContract(*(GetCron()->GetServerNym()));
            offer_->SaveContract();

            pMarket->SaveMarket();

            // Now when the market loads next time, it can verify this offer
            // using the server's signature,
            // instead of having to load the user. Because the server has
            // verified it and added it, and now
            // signs it, vouching for it.

            // The Trade itself (all its other variables) are now allowed to
            // change, since its signatures
            // are also released and it is now server-signed. (With a copy
            // stored of the original.)

            offer_->SetTrade(*this);

            return offer_;
        }
    }

    // It's a stop order, and not activated yet.
    // Should we activate it now?
    //
    else if (IsStopOrder() && !stopActivated_) {
        int64_t relevantPrice = 0;

        // If the stop order is trying to sell something, then it cares about
        // the highest bidder.
        if (offer->IsAsk())
            relevantPrice = pMarket->GetHighestBidPrice();
        else // But if the stop order is trying to buy something, then it cares
             // about the lowest ask price.
            relevantPrice = pMarket->GetLowestAskPrice();

        // It's a stop order that hasn't activated yet. SHOULD IT ACTIVATE NOW?
        if ((IsGreaterThan() && (relevantPrice > GetStopPrice())) ||
            (IsLessThan() && (relevantPrice < GetStopPrice()))) {
            // Activate the stop order!
            if (!pMarket->AddOffer(this, *offer, true)) // Since we're actually
                                                        // adding an offer to
                                                        // the market (not just
            { // loading from disk) the we actually want to save the market.
                // Error adding the offer to the market!    // bSaveFile=true.
                otErr << "Error adding the stop order to the market! (Even "
                         "though supposedly the right market.)\n";
            }
            else {
                // SUCCESS!
                offer_ = offer;

                stopActivated_ = true;
                hasTradeActivated_ = true;

                // The Trade (stored on Cron) has a copy of the Original Offer,
                // with the User's signature on it.
                // A copy of that original Trade object (itself with the user's
                // signature) is already stored in
                // the cron folder (by transaction number.) This happens when
                // the Trade is FIRST added to cron,
                // so it's already safe before we even get here.
                //
                // So thus I am FREE to release the signatures on the offer, and
                // sign with the server instead.
                // The server-signed offer will be stored by the OTMarket.
                offer_->ReleaseSignatures();
                offer_->SignContract(*(GetCron()->GetServerNym()));
                offer_->SaveContract();

                pMarket->SaveMarket();

                // Now when the market loads next time, it can verify this offer
                // using the server's signature,
                // instead of having to load the user. Because the server has
                // verified it and added it, and now
                // signs it, vouching for it.

                // The Trade itself (all its other variables) are now allowed to
                // change, since its signatures
                // are also released and it is now server-signed. (With a copy
                // stored of the original.)

                offer_->SetTrade(*this);

                return offer_;
            }
        }
    }

    delete offer;
    offer = nullptr;

    return nullptr;
}
Пример #2
0
// Assuming the offer is ON the market, this will get the pointer to that offer.
// Otherwise it will try to add it to the market.
OTOffer	* OTTrade::GetOffer(OTIdentifier * pOFFER_MARKET_ID/*=NULL*/, OTMarket ** ppMarket/*=NULL*/)
{
	OT_ASSERT(NULL != GetCron());
			  
	// See if the offer has already been instantiated.
	if (NULL != m_pOffer)
	{
		m_pOffer->SetTrade(*this);	// Probably don't need this one. I'll remove it someday while optimizing.
		return m_pOffer;			// In fact since it should already be set, having this here would basically
									// hide it from me if the memory was ever walked on from a bug somewhere.
	}
	
	if (!m_strOffer.Exists())
	{
		OTLog::Error("OTTrade::GetOffer called with empty m_strOffer.\n");
		return NULL;
	}
	
	OTOffer * pOffer = new OTOffer();
	
	OT_ASSERT(NULL != pOffer);

	// --------------------------------------------------
	
	// Trying to load the offer from the trader's original signed request
	// (So I can use it to lookup the Market ID, so I can see the offer is
	// already there on the market.)
	if (!pOffer->LoadContractFromString(m_strOffer))
	{
		OTLog::Error("Error loading offer from string in OTTrade::GetOffer\n");
		delete pOffer; pOffer = NULL;
		return NULL;
	}
	
	// No need to do any additional security verification here on the Offer,
	// since the Offer is already heavily verified in OTServer::NotarizeMarketOffer().
	// So as long as you feel safe about the Trade, then you can feel safe about
	// the Offer already, with no further checks.
	// *Also remember we saved a copy of the original in the cron folder.
	
	// It loaded. Let's get the Market ID off of it so we can locate the market.
	OTIdentifier OFFER_MARKET_ID(*pOffer);
	
	if (NULL != pOFFER_MARKET_ID)
	{
		// Sometimes the caller function would like a copy of this ID. So I 
		// give the option to pass in a pointer so I can give it here.
		pOFFER_MARKET_ID->Assign(OFFER_MARKET_ID);
	}
	
	
	// Previously if a user tried to use a market that didn't exist, I'd just return failure.
	// But now we will create any market that doesn't already exist.
	// (Remember, the server operator could just erase the market folder--it wouldn't 
	// affect anyone's balances!)
	//
//	OTMarket * pMarket = m_pCron->GetMarket(OFFER_MARKET_ID);
	OTMarket * pMarket = GetCron()->GetOrCreateMarket(GetAssetID(), GetCurrencyID(), pOffer->GetScale()); 

	
	// Couldn't find (or create) the market.
	if (NULL == pMarket)
	{
		OTLog::Output(3, "Unable to find or create market within requested parameters in OTTrade::GetOffer.");
		delete pOffer; pOffer = NULL;
		return NULL;
	}
	
	// If the caller passed in the address of a market pointer (optional)
	if (NULL != ppMarket)
	{
		// Sometimes the caller function would like a copy of this market pointer, when available.
		// So I pass it back to him here, if he wants. That way he doesn't have to do this work again
		// to look it up.
		*ppMarket = pMarket;
	}
	
	// --------------------------------------------------
	
	// At this point, I have heap-allocated the offer, used it to get the Market ID, and successfully
	// used that to get a pointer to the market matching that ID.
	//
	// Let's see if the offer is ALREADY allocated and on this market! 
	// If so, delete the one I just allocated. If not, add it to the market.
	OTOffer * pMarketOffer = pMarket->GetOffer(pOffer->GetTransactionNum());
	
	// The Offer is already on the Market.
	// NOTE: It may just start out this way, without ever being added.
	// How is that possible? Because maybe it was in the market file when we first loaded up,
	// and had been added on some previous run of the software. So since we started running,
	// the pMarket->AddOffer() code below has literally never run for that offer. Instead we
	// first find it here, and thus return the pointer before getting any farther.
	//
	// IN ALL CASES, we make sure to call m_pOffer->SetTrade() so that it has a pointer BACK to
	// this Trade object! (When actually processing the offer, the market will need the account
	// numbers and Nym IDs... which are stored here on the trade.)
	if (NULL != pMarketOffer)
	{
		m_pOffer = pMarketOffer;
		
		// Since the Offer already exists on the market, no need anymore for the
		// one we allocated above (to get the market ID.) So we delete it now.
		delete pOffer;
		pOffer = NULL;
		
		m_pOffer->SetTrade(*this);
		
		return m_pOffer;
	}
	
	// Okay so the offer ISN'T already on the market. If it's not a stop order, let's ADD the one we
	// allocated to the market now! (Stop orders are activated through their own logic, which is in the else.)
	if (!IsStopOrder())
	{
		if (m_bHasTradeActivated)
		{
			// Error -- how has the trade already activated, yet not on the market and null in my pointer?
			OTLog::Error("How has the trade already activated, yet not on the market and null in my pointer?\n");			
		}
		else if (!pMarket->AddOffer(*pOffer, true))	// Since we're actually adding an offer to the market (not just
		{											// loading from disk) the we actually want to save the market. bSaveFile=true.
			
			// Error adding the offer to the market!
			OTLog::Error("Error adding the offer to the market! (Even though supposedly the right market.)\n");
		}
		else 
		{
			// SUCCESS!
			m_pOffer = pOffer;
			
			m_bHasTradeActivated = true;
			
			// The Trade (stored on Cron) has a copy of the Original Offer, with the User's signature on it.
			// A copy of that original Trade object (itself with the user's signature) is already stored in
			// the cron folder (by transaction number.) This happens when the Trade is FIRST added to cron,
			// so it's already safe before we even get here.
			//
			// So thus I am FREE to release the signatures on the offer, and sign with the server instead.
			// The server-signed offer will be stored by the OTMarket.
			m_pOffer->ReleaseSignatures();
			m_pOffer->SignContract(*(GetCron()->GetServerNym()));
			m_pOffer->SaveContract();
			
			pMarket->SaveMarket();
			
			// Now when the market loads next time, it can verify this offer using the server's signature,
			// instead of having to load the user. Because the server has verified it and added it, and now
			// signs it, vouching for it.
			
			
			// The Trade itself (all its other variables) are now allowed to change, since its signatures
			// are also released and it is now server-signed. (With a copy stored of the original.)

			m_pOffer->SetTrade(*this);

			return m_pOffer;
		}
	}
	else if(IsStopOrder() && !m_bHasStopActivated) // It's a stop order. Should we activate it now?
	{
		long lRelevantPrice = 0;
		
		// If the stop order is trying to sell something, then it cares about the highest bidder.
		if (pOffer->IsAsk()) 
			lRelevantPrice = pMarket->GetHighestBidPrice();
		else // But if the stop order is trying to buy something, then it cares about the lowest ask price.
			lRelevantPrice = pMarket->GetLowestAskPrice();
		
		// It's a stop order that hasn't activated yet. SHOULD IT ACTIVATE NOW?
		if ((IsGreaterThan()	&& (lRelevantPrice > GetStopPrice())) ||
			(IsLessThan()		&& (lRelevantPrice < GetStopPrice())))
		{
			// Activate the stop order!
			if (!pMarket->AddOffer(*pOffer, true))	// Since we're actually adding an offer to the market (not just
			{										// loading from disk) the we actually want to save the market. bSaveFile=true.
				// Error adding the offer to the market!
				OTLog::Error("Error adding the stop order to the market! (Even though supposedly the right market.)\n");
			}
			else 
			{
				// SUCCESS!
				m_pOffer = pOffer;
				
				m_bHasStopActivated		= true;
				m_bHasTradeActivated	= true;
				
				// The Trade (stored on Cron) has a copy of the Original Offer, with the User's signature on it.
				// A copy of that original Trade object (itself with the user's signature) is already stored in
				// the cron folder (by transaction number.) This happens when the Trade is FIRST added to cron,
				// so it's already safe before we even get here.
				//
				// So thus I am FREE to release the signatures on the offer, and sign with the server instead.
				// The server-signed offer will be stored by the OTMarket.
				m_pOffer->ReleaseSignatures();
				m_pOffer->SignContract(*(GetCron()->GetServerNym()));
				m_pOffer->SaveContract();
				
				pMarket->SaveMarket();
				
				// Now when the market loads next time, it can verify this offer using the server's signature,
				// instead of having to load the user. Because the server has verified it and added it, and now
				// signs it, vouching for it.
				
				
				// The Trade itself (all its other variables) are now allowed to change, since its signatures
				// are also released and it is now server-signed. (With a copy stored of the original.)
				
				
				m_pOffer->SetTrade(*this);

				return m_pOffer;
			}
		}		
	}

	delete pOffer;
	pOffer = NULL;

	return NULL;
}