Ledger::pointer LedgerHistory::getLedgerBySeq (std::uint32_t index)
{
    {
        LedgersByHash::ScopedLockType sl (m_ledgers_by_hash.peekMutex ());
        std::map <std::uint32_t, uint256>::iterator it (mLedgersByIndex.find (index));

        if (it != mLedgersByIndex.end ())
        {
            uint256 hash = it->second;
            sl.unlock ();
            return getLedgerByHash (hash);
        }
    }

    Ledger::pointer ret (Ledger::loadByIndex (index));

    if (!ret)
        return ret;

    assert (ret->getLedgerSeq () == index);

    {
        // Add this ledger to the local tracking by index
        LedgersByHash::ScopedLockType sl (m_ledgers_by_hash.peekMutex ());

        assert (ret->isImmutable ());
        m_ledgers_by_hash.canonicalize (ret->getHash (), ret);
        mLedgersByIndex[ret->getLedgerSeq ()] = ret->getHash ();
        return (ret->getLedgerSeq () == index) ? ret : Ledger::pointer ();
    }
}
Example #2
0
Ledger::pointer LedgerHistory::getLedgerBySeq (uint32 index)
{
    TaggedCache::ScopedLockType sl (mLedgersByHash.peekMutex (), __FILE__, __LINE__);
    std::map<uint32, uint256>::iterator it (mLedgersByIndex.find (index));

    if (it != mLedgersByIndex.end ())
    {
        uint256 hash = it->second;
        sl.unlock ();
        return getLedgerByHash (hash);
    }

    sl.unlock ();

    Ledger::pointer ret (Ledger::loadByIndex (index));

    if (!ret)
        return ret;

    assert (ret->getLedgerSeq () == index);

    sl.lock (__FILE__, __LINE__);
    assert (ret->isImmutable ());
    mLedgersByHash.canonicalize (ret->getHash (), ret);
    mLedgersByIndex[ret->getLedgerSeq ()] = ret->getHash ();
    return (ret->getLedgerSeq () == index) ? ret : Ledger::pointer ();
}
Example #3
0
void LedgerHistory::addLedger (Ledger::pointer ledger, bool validated)
{
    assert (ledger && ledger->isImmutable ());
    assert (ledger->peekAccountStateMap ()->getHash ().isNonZero ());

    TaggedCache::ScopedLockType sl (mLedgersByHash.peekMutex (), __FILE__, __LINE__);

    mLedgersByHash.canonicalize (ledger->getHash(), ledger, true);
    if (validated)
        mLedgersByIndex[ledger->getLedgerSeq()] = ledger->getHash();
}
bool LedgerHistory::addLedger (Ledger::pointer ledger, bool validated)
{
    assert (ledger && ledger->isImmutable ());
    assert (ledger->peekAccountStateMap ()->getHash ().isNonZero ());

    LedgersByHash::ScopedLockType sl (m_ledgers_by_hash.peekMutex ());

    const bool alreadyHad = m_ledgers_by_hash.canonicalize (ledger->getHash(), ledger, true);
    if (validated)
        mLedgersByIndex[ledger->getLedgerSeq()] = ledger->getHash();

    return alreadyHad;
}
Example #5
0
Ledger::pointer LedgerMaster::closeLedger(bool recover)
{
	boost::recursive_mutex::scoped_lock sl(mLock);
	Ledger::pointer closingLedger = mCurrentLedger;

	if (recover)
	{
		int recovers = 0;
		for (CanonicalTXSet::iterator it = mHeldTransactions.begin(), end = mHeldTransactions.end(); it != end; ++it)
		{
			try
			{
				bool didApply;
				mEngine.applyTransaction(*it->second, tapOPEN_LEDGER, didApply);
				if (didApply)
					++recovers;
			}
			catch (...)
			{
				cLog(lsWARNING) << "Held transaction throws";
			}
		}
		tLog(recovers != 0, lsINFO) << "Recovered " << recovers << " held transactions";
		mHeldTransactions.reset(closingLedger->getHash());
	}

	mCurrentLedger = boost::make_shared<Ledger>(boost::ref(*closingLedger), true);
	mEngine.setLedger(mCurrentLedger);

	return closingLedger;
}
Ledger::pointer LedgerHistory::getLedgerByHash (uint256 const& hash)
{
    Ledger::pointer ret = m_ledgers_by_hash.fetch (hash);

    if (ret)
    {
        assert (ret->isImmutable ());
        assert (ret->getHash () == hash);
        return ret;
    }

    ret = Ledger::loadByHash (hash);

    if (!ret)
        return ret;

    assert (ret->isImmutable ());
    assert (ret->getHash () == hash);
    m_ledgers_by_hash.canonicalize (ret->getHash (), ret);
    assert (ret->getHash () == hash);

    return ret;
}
Example #7
0
    /** Process a single ledger
        @param ledgerIndex The index of the ledger to process.
        @param ledgerHash  The known correct hash of the ledger.
        @param doNodes Ensure all ledger nodes are in the node db.
        @param doTxns Reprocess (account) transactions to SQL databases.
        @return `true` if the ledger was cleaned.
    */
    bool doLedger(
        LedgerIndex const& ledgerIndex,
        LedgerHash const& ledgerHash,
        bool doNodes,
        bool doTxns)
    {
        Ledger::pointer nodeLedger =
            getApp().getInboundLedgers().acquire (
                ledgerHash, ledgerIndex, InboundLedger::fcGENERIC);
        if (!nodeLedger)
        {
            m_journal.debug << "Ledger " << ledgerIndex << " not available";
            return false;
        }

        Ledger::pointer dbLedger = Ledger::loadByIndex(ledgerIndex);
        if (! dbLedger ||
            (dbLedger->getHash() != ledgerHash) ||
            (dbLedger->getParentHash() != nodeLedger->getParentHash()))
        {
            // Ideally we'd also check for more than one ledger with that index
            m_journal.debug <<
                "Ledger " << ledgerIndex << " mismatches SQL DB";
            doTxns = true;
        }

        if(! getApp().getLedgerMaster().fixIndex(ledgerIndex, ledgerHash))
        {
            m_journal.debug << "ledger " << ledgerIndex << " had wrong entry in history";
            doTxns = true;
        }

        if (doNodes && !nodeLedger->walkLedger())
        {
            m_journal.debug << "Ledger " << ledgerIndex << " is missing nodes";
            getApp().getInboundLedgers().acquire(
                ledgerHash, ledgerIndex, InboundLedger::fcGENERIC);
            return false;
        }

        if (doTxns && !nodeLedger->pendSaveValidated(true, false))
        {
            m_journal.debug << "Failed to save ledger " << ledgerIndex;
            return false;
        }

        return true;
    }
Example #8
0
 // VFALCO TODO This should return boost::optional<uint256>
 LedgerHash getLedgerHash(Ledger::pointer ledger, LedgerIndex index)
 {
     boost::optional<LedgerHash> hash;
     try
     {
         hash = hashOfSeq(*ledger, index,
             getApp().getSLECache(), m_journal);
     }
     catch (SHAMapMissingNode &)
     {
         m_journal.warning <<
             "Node missing from ledger " << ledger->getLedgerSeq();
         getApp().getInboundLedgers().acquire (
             ledger->getHash(), ledger->getLedgerSeq(), InboundLedger::fcGENERIC);
     }
     return hash ? *hash : zero; // kludge
 }
Example #9
0
// The previous version of the lookupLedger command would accept the
// "ledger_index" argument as a string and silently treat it as a request to
// return the current ledger which, while not strictly wrong, could cause a lot
// of confusion.
//
// The code now robustly validates the input and ensures that the only possible
// values for the "ledger_index" parameter are the index of a ledger passed as
// an integer or one of the strings "current", "closed" or "validated".
// Additionally, the code ensures that the value passed in "ledger_hash" is a
// string and a valid hash. Invalid values will return an appropriate error
// code.
//
// In the absence of the "ledger_hash" or "ledger_index" parameters, the code
// assumes that "ledger_index" has the value "current".
//
// Returns a Json::objectValue.  If there was an error, it will be in that
// return value.  Otherwise, the object contains the field "validated" and
// optionally the fields "ledger_hash", "ledger_index" and
// "ledger_current_index", if they are defined.
Status lookupLedger (
    Json::Value const& params,
    Ledger::pointer& ledger,
    NetworkOPs& netOps,
    Json::Value& jsonResult)
{
    if (auto status = ledgerFromRequest (params, ledger, netOps))
        return status;

    if (ledger->isClosed ())
    {
        jsonResult[jss::ledger_hash] = to_string (ledger->getHash());
        jsonResult[jss::ledger_index] = ledger->getLedgerSeq();
    }
    else
    {
        jsonResult[jss::ledger_current_index] = ledger->getLedgerSeq();
    }
    jsonResult[jss::validated] = isValidated (*ledger);
    return Status::OK;
}
Example #10
0
bool PathRequest::isValid (RippleLineCache::ref crCache)
{
    ScopedLockType sl (mLock);
    bValid = raSrcAccount.isSet () && raDstAccount.isSet () && saDstAmount > zero;
    Ledger::pointer lrLedger = crCache->getLedger ();

    if (bValid)
    {
        AccountState::pointer asSrc = getApp().getOPs ().getAccountState (crCache->getLedger(), raSrcAccount);

        if (!asSrc)
        {
            // no source account
            bValid = false;
            jvStatus = rpcError (rpcSRC_ACT_NOT_FOUND);
        }
        else
        {
            AccountState::pointer asDst = getApp().getOPs ().getAccountState (lrLedger, raDstAccount);

            Json::Value& jvDestCur = (jvStatus["destination_currencies"] = Json::arrayValue);

            if (!asDst)
            {
                // no destination account
                jvDestCur.append (Json::Value ("XRP"));

                if (!saDstAmount.isNative ())
                {
                    // only XRP can be send to a non-existent account
                    bValid = false;
                    jvStatus = rpcError (rpcACT_NOT_FOUND);
                }
                else if (saDstAmount < STAmount (lrLedger->getReserve (0)))
                {
                    // payment must meet reserve
                    bValid = false;
                    jvStatus = rpcError (rpcDST_AMT_MALFORMED);
                }
            }
            else
            {
                bool const disallowXRP (
                    asDst->peekSLE ().getFlags() & lsfDisallowXRP);

                CurrencySet usDestCurrID =
                    usAccountDestCurrencies (raDstAccount, crCache, !disallowXRP);

                for (auto const& currency : usDestCurrID)
                    jvDestCur.append (to_string (currency));

                jvStatus["destination_tag"] = (asDst->peekSLE ().getFlags () & lsfRequireDestTag) != 0;
            }
        }
    }

    if (bValid)
    {
        jvStatus["ledger_hash"] = to_string (lrLedger->getHash ());
        jvStatus["ledger_index"] = lrLedger->getLedgerSeq ();
    }
    return bValid;
}
Example #11
0
// Get state nodes from a ledger
//   Inputs:
//     limit:        integer, maximum number of entries
//     marker:       opaque, resume point
//     binary:       boolean, format
//   Outputs:
//     ledger_hash:  chosen ledger's hash
//     ledger_index: chosen ledger's index
//     state:        array of state nodes
//     marker:       resume point, if any
Json::Value doLedgerData (RPC::Context& context)
{
    context.lock_.unlock ();

    int const BINARY_PAGE_LENGTH = 256;
    int const JSON_PAGE_LENGTH = 2048;

    Ledger::pointer lpLedger;

    Json::Value jvResult = RPC::lookupLedger (context.params_, lpLedger, context.netOps_);
    if (!lpLedger)
        return jvResult;

    uint256 resumePoint;
    if (context.params_.isMember ("marker"))
    {
        Json::Value const& jMarker = context.params_["marker"];
        if (!jMarker.isString ())
            return RPC::expected_field_error ("marker", "valid");
        if (!resumePoint.SetHex (jMarker.asString ()))
            return RPC::expected_field_error ("marker", "valid");
    }

    bool isBinary = false;
    if (context.params_.isMember ("binary"))
    {
        Json::Value const& jBinary = context.params_["binary"];
        if (!jBinary.isBool ())
            return RPC::expected_field_error ("binary", "bool");
        isBinary = jBinary.asBool ();
    }

    int limit = -1;
    int maxLimit = isBinary ? BINARY_PAGE_LENGTH : JSON_PAGE_LENGTH;

    if (context.params_.isMember ("limit"))
    {
        Json::Value const& jLimit = context.params_["limit"];
        if (!jLimit.isIntegral ())
            return RPC::expected_field_error ("limit", "integer");

        limit = jLimit.asInt ();
    }

    if ((limit < 0) || ((limit > maxLimit) && (context.role_ != Config::ADMIN)))
        limit = maxLimit;

    Json::Value jvReply = Json::objectValue;

    jvReply["ledger_hash"] = to_string (lpLedger->getHash());
    jvReply["ledger_index"] = beast::lexicalCastThrow <std::string> (lpLedger->getLedgerSeq ());

    Json::Value& nodes = (jvReply["state"] = Json::arrayValue);
    SHAMap& map = *(lpLedger->peekAccountStateMap ());

    for (;;)
    {
       SHAMapItem::pointer item = map.peekNextItem (resumePoint);
       if (!item)
           break;
       resumePoint = item->getTag();

       if (limit-- <= 0)
       {
           --resumePoint;
           jvReply["marker"] = to_string (resumePoint);
           break;
       }

       if (isBinary)
       {
           Json::Value& entry = nodes.append (Json::objectValue);
           entry["data"] = strHex (item->peekData().begin(), item->peekData().size());
           entry["index"] = to_string (item->getTag ());
       }
       else
       {
           SLE sle (item->peekSerializer(), item->getTag ());
           Json::Value& entry = nodes.append (sle.getJson (0));
           entry["index"] = to_string (item->getTag ());
       }
    }

    return jvReply;
}