Beispiel #1
0
void
close_and_advance(Ledger::pointer& ledger, Ledger::pointer& LCL)
{
    std::shared_ptr<SHAMap> set = ledger->peekTransactionMap();
    CanonicalTXSet retriableTransactions(set->getHash());
    Ledger::pointer newLCL = std::make_shared<Ledger>(false, *LCL);
    // Set up to write SHAMap changes to our database,
    //   perform updates, extract changes
    applyTransactions(set, newLCL, newLCL, retriableTransactions, false);
    newLCL->updateSkipList();
    newLCL->setClosed();
    newLCL->peekAccountStateMap()->flushDirty(
        hotACCOUNT_NODE, newLCL->getLedgerSeq());
    newLCL->peekTransactionMap()->flushDirty(
        hotTRANSACTION_NODE, newLCL->getLedgerSeq());
    using namespace std::chrono;
    auto const epoch_offset = days(10957);  // 2000-01-01
    std::uint32_t closeTime = time_point_cast<seconds>  // now
        (system_clock::now() - epoch_offset).
        time_since_epoch().count();
    int closeResolution = seconds(LEDGER_TIME_ACCURACY).count();
    bool closeTimeCorrect = true;
    newLCL->setAccepted(closeTime, closeResolution, closeTimeCorrect);

    LCL = newLCL;
    ledger = std::make_shared<Ledger>(false, *LCL);
}
InboundLedger::pointer InboundLedgers::findCreate (uint256 const& hash, uint32 seq)
{
    assert (hash.isNonZero ());
    boost::mutex::scoped_lock sl (mLock);
    InboundLedger::pointer& ptr = mLedgers[hash];

    if (ptr)
    {
        ptr->touch ();
        return ptr;
    }

    ptr = boost::make_shared<InboundLedger> (hash, seq);

    if (!ptr->isDone ())
    {
        ptr->addPeers ();
        ptr->setTimer (); // Cannot call in constructor
    }
    else
    {
        Ledger::pointer ledger = ptr->getLedger ();
        ledger->setClosed ();
        ledger->setImmutable ();
        theApp->getLedgerMaster ().storeLedger (ledger);
        WriteLog (lsDEBUG, InboundLedger) << "Acquiring ledger we already have: " << hash;
    }

    return ptr;
}
Beispiel #3
0
// Create genesis ledger from a start amount in drops, and the public
// master RippleAddress
std::pair<Ledger::pointer, Ledger::pointer>
createGenesisLedger(std::uint64_t start_amount_drops, TestAccount const& master)
{
    initializePathfinding();
    Ledger::pointer ledger = std::make_shared<Ledger>(master.pk,
        start_amount_drops);
    ledger->updateHash();
    ledger->setClosed();
    if (!ledger->assertSane())
        throw std::runtime_error(
        "! ledger->assertSane()");
    return std::make_pair(std::move(ledger), std::make_shared<Ledger>(false, *ledger));
}
InboundLedger::pointer InboundLedgers::findCreate (uint256 const& hash, uint32 seq)
{
    assert (hash.isNonZero ());
    InboundLedger::pointer ret;

    {
        boost::mutex::scoped_lock sl (mLock);

        boost::unordered_map<uint256, InboundLedger::pointer>::iterator it = mLedgers.find (hash);
        if (it != mLedgers.end ())
        {
            ret = it->second;
            // FIXME: Should set the sequence if it's not set
        }
        else
        {
            ret = boost::make_shared<InboundLedger> (hash, seq);
            assert (ret);
            mLedgers.insert (std::make_pair (hash, ret));

            if (!ret->tryLocal())
            {
                ret->addPeers ();
                ret->setTimer (); // Cannot call in constructor
            }
            else if (!ret->isFailed ())
            {
                WriteLog (lsDEBUG, InboundLedger) << "Acquiring ledger we already have locally: " << hash;
                Ledger::pointer ledger = ret->getLedger ();
                ledger->setClosed ();
                ledger->setImmutable ();
                getApp().getLedgerMaster ().storeLedger (ledger);
            }
        }
    }

    return ret;
}
/**
 * Instantiate an application and replay a ledger history out
 * of the dump file `filename`.
 */
void
LedgerDump::loadTransactions (std::string const& filename)
{
    std::ifstream in (filename);
    require ((bool)in, "opening file");

    std::unique_ptr <Application> app (make_Application ());
    app->setup ();
    auto &lm = app->getLedgerMaster ();
    WriteLog (lsINFO, LedgerDump) << "Loading ledgers from " << filename;

    auto nTxs = 0;

    // app->setup() when called with START_UP == Config::FRESH calls
    // ApplicationImp::startNewLedger(). Unfortunately it starts the new
    // ledger at the wrong timestamp, so we call it again once we've read
    // the first ledger we're going to apply. However, it's worth
    // understanding that startNewLedger() establishes 3 ledgers:
    //
    // Ledger 0 is the genesis ledger, it's not a real ledger, just a
    //          number.
    //
    // Ledger 1 is the root-account deposit ledger, with a single pile of
    //          currency owned by a single account generated by the seed
    //          "masterpassword".
    //
    // Ledger 2 is created and closed immediately on start, not sure why.
    //
    // Ledger 3 is a new ledger chained to #2 and left open in
    //          ledgermaster.
    //
    // Ledger 3 is where replay should be starting, so (once we call
    // startNewLedger() again) we pull out ledger #2 and use it as the
    // parent of the new ledger 3 we're replaying, and throw away the #3
    // that was made by startNewLedger().

    Ledger::pointer parentLedger;

    while (in)
    {
        if ((gLedgerSeq & 0xfff) == 0) {
            Job j;
            app->doSweep (j);
        }

        Json::Value j = loadJsonRecord (in);

        Ledger::pointer deserializedLedger;
        SHAMap::pointer txSet;
        std::vector<uint256> txOrder;
        std::tie (deserializedLedger, txSet, txOrder) =
            loadLedgerAndTransactionsFromJSON (*app, j);

        if (!parentLedger)
        {
            if (getConfig ().START_LEDGER.empty ())
            {
                require (deserializedLedger->getLedgerSeq () == 3,
                         "Initial ledger isn't seq #3");

                // On first iteration, restart the app's view of the ledger
                // history at the same instant as the parent close time of the
                // first ledger (ledger #3).
                app->startNewLedger (deserializedLedger->getParentCloseTimeNC ());
                parentLedger = lm.getClosedLedger ();
                require (parentLedger->getLedgerSeq () == 2,
                         "Initial ledger parent isn't seq #2");
            }
            else
            {
                // We're being invoked with --ledger, which is where we
                // will start replay from.
                require (app->loadOldLedger (getConfig ().START_LEDGER, false),
                         "Reloading old ledger failed.");
                parentLedger = lm.getClosedLedger ();
            }

            auto const parentSeq = parentLedger->getLedgerSeq ();
            auto seq = j["seq"].asUInt ();
            while (parentSeq + 1 > seq)
            {
                // Fast-scan JSON records until we hit the right one.
                WriteLog (lsINFO, LedgerDump) << "scanning past ledger: "
                                              << seq;
                j = loadJsonRecord (in);
                seq = j["seq"].asUInt ();
                if (parentSeq + 1 <= seq)
                {
                    require (parentSeq + 1 == seq,
                             "Missing ledgers between loaded and replay-start");
                    std::tie (deserializedLedger, txSet, txOrder) =
                        loadLedgerAndTransactionsFromJSON (*app, j);
                }
            }
            gLedgerSeq = parentSeq;
            require(parentLedger->getLedgerSeq () + 1 ==
                    deserializedLedger->getLedgerSeq (),
                    "Mismatched ledger-sequence prefix.");
        }

        Ledger::pointer currentLedger =
            boost::make_shared<Ledger> (true, *parentLedger);
        currentLedger->setCloseTime (deserializedLedger->getCloseTimeNC ());
        currentLedger->setCloseFlags (deserializedLedger->getCloseFlags ());
        currentLedger->setParentHash (deserializedLedger->getParentHash ());

        WriteLog (lsINFO, LedgerDump) << "loading ledger: "
                                      << currentLedger->getLedgerSeq();

        if (ShouldLog (lsTRACE, LedgerDump))
        {
            WriteLog (lsTRACE, LedgerDump) << "expecting next ledger:";
            WriteLog (lsTRACE, LedgerDump) << deserializedLedger->getJson (0);
            WriteLog (lsTRACE, LedgerDump) << "synthetic next ledger:";
            WriteLog (lsTRACE, LedgerDump) << currentLedger->getJson (0);
        }

        gLedgerSeq++;

        // Apply transactions, transitioning from one ledger state to next.
        WriteLog (lsDEBUG, LedgerDump)
            << "Applying set of " << txOrder.size() << " transactions";
        CanonicalTXSet retriableTransactions (txSet->getHash ());
        std::set<uint256> failedTransactions;
        LedgerConsensus::applyTransactions (txSet, currentLedger, currentLedger,
                                            retriableTransactions, failedTransactions,
                                            false, txOrder);

        require (retriableTransactions.empty (), "failed retriable tx set is not empty");
        require (failedTransactions.empty (), "failed tx set is not empty");

        currentLedger->updateSkipList ();
        currentLedger->setClosed ();
        currentLedger->setCloseTime (deserializedLedger->getCloseTimeNC ());

        int asf = currentLedger->peekAccountStateMap ()->flushDirty (
            hotACCOUNT_NODE, currentLedger->getLedgerSeq());
        int tmf = currentLedger->peekTransactionMap ()->flushDirty (
            hotTRANSACTION_NODE, currentLedger->getLedgerSeq());
        nTxs += tmf;

        WriteLog (lsDEBUG, LedgerDump) << "Flushed " << asf << " account "
                                  << "and " << tmf << "transaction nodes";

        // Finalize with the LedgerMaster.
        currentLedger->setAccepted ();
        bool alreadyHadLedger = lm.storeLedger (currentLedger);
        assert (! alreadyHadLedger);
        lm.pushLedger (currentLedger);

        WriteLog (lsTRACE, LedgerDump) << "parent ledger:";
        traceLedgerContents (*parentLedger);
        WriteLog (lsTRACE, LedgerDump) << "current ledger:";
        traceLedgerContents (*currentLedger);

        try
        {
            checkLedgersEqual (*deserializedLedger, *currentLedger);
        }
        catch (...)
        {
            WriteLog (lsINFO, LedgerDump) << "bad ledger:";
            std::cerr << currentLedger->getJson (LEDGER_JSON_FULL);
            throw;
        }
        parentLedger = currentLedger;
    }

    WriteLog (lsINFO, LedgerDump) << "Loaded "
                             << gLedgerSeq << "ledgers, "
                             << nTxs << " transactions from "
                             << filename;
    exit (0);
}