// called from Peer and when an Item tracker completes
void
PendingEnvelopes::recvSCPEnvelope(SCPEnvelope const& envelope)
{
    // do we already have this envelope?
    // do we have the qset
    // do we have the txset

    try
    {
        auto& set = mFetchingEnvelopes[envelope.statement.slotIndex];

        if (find(set.begin(), set.end(), envelope) == set.end())
        { // we aren't fetching this envelop

            auto& receivedList =
                mReceivedEnvelopes[envelope.statement.slotIndex];
            if (find(receivedList.begin(), receivedList.end(), envelope) ==
                receivedList.end())
            { // we haven't seen this envelope before

                receivedList.push_back(envelope);
                if (startFetch(envelope))
                { // fully fetched
                    envelopeReady(envelope);
                }
                else
                {
                    mFetchingEnvelopes[envelope.statement.slotIndex].insert(
                        envelope);
                }

                CLOG(DEBUG, "Herder") << "PendingEnvelopes::recvSCPEnvelope";

            } // else we already have this one
        }
        else
        { // we are fetching this envelope
            // check if we are done fetching it
            if (isFullyFetched(envelope))
            {
                envelopeReady(envelope);
            } // else just keep waiting for it to come in
        }
    }
    catch (xdr::xdr_runtime_error& e)
    {
        CLOG(TRACE, "Herder")
            << "PendingEnvelopes::recvSCPEnvelope got corrupt message: "
            << e.what();
    }
}
// called from Peer and when an Item tracker completes
void
PendingEnvelopes::recvSCPEnvelope(SCPEnvelope const& envelope)
{
    auto const& nodeID = envelope.statement.nodeID;
    if (!isNodeInQuorum(nodeID))
    {
        CLOG(DEBUG, "Herder") << "Dropping envelope from "
                              << mApp.getConfig().toShortString(nodeID)
                              << " (not in quorum)";
        return;
    }

    // do we already have this envelope?
    // do we have the qset
    // do we have the txset

    try
    {
        auto& set = mFetchingEnvelopes[envelope.statement.slotIndex];
        auto& processedList = mProcessedEnvelopes[envelope.statement.slotIndex];

        auto fetching = find(set.begin(), set.end(), envelope);

        if (fetching == set.end())
        { // we aren't fetching this envelope
            if (find(processedList.begin(), processedList.end(), envelope) ==
                processedList.end())
            { // we haven't seen this envelope before
                // insert it into the fetching set
                fetching = set.insert(envelope).first;
                startFetch(envelope);
            }
            else
            {
                // we already have this one
                fetching = set.end();
            }
        }

        if (fetching != set.end())
        { // we are fetching this envelope
            // check if we are done fetching it
            if (isFullyFetched(envelope))
            {
                // move the item from fetching to processed
                processedList.emplace_back(*fetching);
                set.erase(fetching);
                envelopeReady(envelope);
            } // else just keep waiting for it to come in
        }
    }
    catch (xdr::xdr_runtime_error& e)
    {
        CLOG(TRACE, "Herder")
            << "PendingEnvelopes::recvSCPEnvelope got corrupt message: "
            << e.what();
    }
}
// called from Peer and when an Item tracker completes
Herder::EnvelopeStatus
PendingEnvelopes::recvSCPEnvelope(SCPEnvelope const& envelope)
{
    auto const& nodeID = envelope.statement.nodeID;
    if (!isNodeInQuorum(nodeID))
    {
        CLOG(DEBUG, "Herder")
            << "Dropping envelope from "
            << mApp.getConfig().toShortString(nodeID) << " (not in quorum)";
        return Herder::ENVELOPE_STATUS_DISCARDED;
    }

    // did we discard this envelope?
    // do we already have this envelope?
    // do we have the qset
    // do we have the txset

    try
    {
        if (isDiscarded(envelope))
        {
            return Herder::ENVELOPE_STATUS_DISCARDED;
        }

        touchFetchCache(envelope);

        auto& set = mEnvelopes[envelope.statement.slotIndex].mFetchingEnvelopes;
        auto& processedList =
            mEnvelopes[envelope.statement.slotIndex].mProcessedEnvelopes;

        auto fetching = find(set.begin(), set.end(), envelope);

        if (fetching == set.end())
        { // we aren't fetching this envelope
            if (find(processedList.begin(), processedList.end(), envelope) ==
                processedList.end())
            { // we haven't seen this envelope before
                // insert it into the fetching set
                fetching = set.insert(envelope).first;
                startFetch(envelope);
            }
            else
            {
                // we already have this one
                return Herder::ENVELOPE_STATUS_PROCESSED;
            }
        }

        // we are fetching this envelope
        // check if we are done fetching it
        if (isFullyFetched(envelope))
        {
            // move the item from fetching to processed
            processedList.emplace_back(*fetching);
            set.erase(fetching);
            envelopeReady(envelope);
            updateMetrics();
            return Herder::ENVELOPE_STATUS_READY;
        } // else just keep waiting for it to come in

        updateMetrics();
        return Herder::ENVELOPE_STATUS_FETCHING;
    }
    catch (xdr::xdr_runtime_error& e)
    {
        CLOG(TRACE, "Herder")
            << "PendingEnvelopes::recvSCPEnvelope got corrupt message: "
            << e.what();
        return Herder::ENVELOPE_STATUS_DISCARDED;
    }
}