void doapplyvalidation(ledger::ref lastclosedledger, stobject& basevalidation) override
 {
     dividendmaster::pointer dividendmaster = getapp().getops().getdividendmaster();
     if (dividendmaster->trylock())
     {
         if (dividendmaster->isready())
         {
             uint32_t dividendledger = lastclosedledger->getdividendbaseledger();
             if (dividendledger == dividendmaster->getledgerseq())
             {
                 basevalidation.setfieldu32 (sfdividendledger, dividendledger);
                 basevalidation.setfieldh256 (sfdividendresulthash, dividendmaster->getresulthash());
                 
                 if (m_journal.info)
                     m_journal.info << "voting for a dividend apply based " << dividendledger << " with hash "<< dividendmaster->getresulthash() << " in " << lastclosedledger->gethash();
             }
             else
             {
                 if (m_journal.warning)
                     m_journal.warning << "wrong base ledger " << dividendmaster->getledgerseq() << " want "<< dividendledger;
             }
         }
         dividendmaster->unlock();
     }
 }
sttx::pointer transactionmaster::fetch (shamapitem::ref item,
        shamaptreenode::tntype type,
        bool checkdisk, std::uint32_t ucommitledger)
{
    sttx::pointer  txn;
    transaction::pointer            itx = getapp().getmastertransaction ().fetch (item->gettag (), false);

    if (!itx)
    {

        if (type == shamaptreenode::tntransaction_nm)
        {
            serializeriterator sit (item->peekserializer ());
            txn = std::make_shared<sttx> (std::ref (sit));
        }
        else if (type == shamaptreenode::tntransaction_md)
        {
            serializer s;
            int length;
            item->peekserializer ().getvl (s.moddata (), 0, length);
            serializeriterator sit (s);

            txn = std::make_shared<sttx> (std::ref (sit));
        }
    }
    else
    {
        if (ucommitledger)
            itx->setstatus (committed, ucommitledger);

        txn = itx->getstransaction ();
    }

    return txn;
}
예제 #3
0
json::value doblacklist (rpc::context& context)
{
    auto& rm = getapp().getresourcemanager();
    if (context.params.ismember("threshold"))
        return rm.getjson(context.params["threshold"].asint());
    else
        return rm.getjson();
}
예제 #4
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().getledgermaster().findacquireledger(ledgerindex, ledgerhash);
        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().findcreate(ledgerhash, ledgerindex, inboundledger::fcgeneric);
            return false;
        }

        if (dotxns && !nodeledger->pendsavevalidated(true, false))
        {
            m_journal.debug << "failed to save ledger " << ledgerindex;
            return false;
        }

        return true;
    }
예제 #5
0
    /** returns the hash of the specified ledger.
        @param ledgerindex the index of the desired ledger.
        @param referenceledger [out] an optional known good subsequent ledger.
        @return the hash of the ledger. this will be all-bits-zero if not found.
    */
    ledgerhash gethash(
        ledgerindex const& ledgerindex,
        ledger::pointer& referenceledger)
    {
        ledgerhash ledgerhash;

        if (!referenceledger || (referenceledger->getledgerseq() < ledgerindex))
        {
            referenceledger = getapp().getledgermaster().getvalidatedledger();
            if (!referenceledger)
            {
                m_journal.warning << "no validated ledger";
                return ledgerhash; // nothing we can do. no validated ledger.
            }
        }

        if (referenceledger->getledgerseq() >= ledgerindex)
        {
            // see if the hash for the ledger we need is in the reference ledger
            ledgerhash = getledgerhash(referenceledger, ledgerindex);
            if (ledgerhash.iszero())
            {
                // no, try to get another ledger that might have the hash we need
                // compute the index and hash of a ledger that will have the hash we need
                ledgerindex refindex = (ledgerindex + 255) & (~255);
                ledgerhash refhash = getledgerhash (referenceledger, refindex);

                bool const nonzero (refhash.isnonzero ());
                assert (nonzero);
                if (nonzero)
                {
                    // we found the hash and sequence of a better reference ledger
                    referenceledger = getapp().getledgermaster().findacquireledger (refindex, refhash);
                    if (referenceledger)
                        ledgerhash = getledgerhash(referenceledger, ledgerindex);
                }
            }
        }
        else
            m_journal.warning << "validated ledger is prior to target ledger";

        return ledgerhash;
    }
예제 #6
0
 ledgerhash getledgerhash(ledger::pointer ledger, ledgerindex index)
 {
     ledgerhash hash;
     try
     {
         hash = ledger->getledgerhash(index);
     }
     catch (shamapmissingnode &)
     {
         m_journal.warning <<
             "node missing from ledger " << ledger->getledgerseq();
         getapp().getinboundledgers().findcreate (
             ledger->gethash(), ledger->getledgerseq(), inboundledger::fcgeneric);
     }
     return hash;
 }
예제 #7
0
json::value doledgeraccept (rpc::context& context)
{
    auto lock = getapp().masterlock();
    json::value jvresult;

    if (!getconfig ().run_standalone)
    {
        jvresult["error"] = "notstandalone";
    }
    else
    {
        context.netops.acceptledger ();

        jvresult["ledger_current_index"]
                = context.netops.getcurrentledgerid ();
    }

    return jvresult;
}
예제 #8
0
status ledgerhandler::check ()
{
    auto const& params = context_.params;
    bool needsledger = params.ismember (jss::ledger) ||
            params.ismember (jss::ledger_hash) ||
            params.ismember (jss::ledger_index);
    if (!needsledger)
        return status::ok;

    if (auto s = rpc::lookupledger (params, ledger_, context_.netops, result_))
        return s;

    bool bfull = params[jss::full].asbool();
    bool bwithdividend = params["dividend"].asbool ();
    bool btransactions = params[jss::transactions].asbool();
    bool baccounts = params[jss::accounts].asbool();
    bool bexpand = params[jss::expand].asbool();

    options_ = (bfull ? ledger_json_full : 0)
            | (bexpand ? ledger_json_expand : 0)
            | (bwithdividend ? ledger_json_dump_txdiv : 0)
            | (btransactions ? ledger_json_dump_txrp : 0)
            | (baccounts ? ledger_json_dump_state : 0);

    if (bfull || baccounts)
    {
        // until some sane way to get full ledgers has been implemented,
        // disallow retrieving all state nodes.
        if (context_.role != role::admin)
            return rpcno_permission;

        if (getapp().getfeetrack().isloadedlocal() &&
            context_.role != role::admin)
        {
            return rpctoo_busy;
        }
        context_.loadtype = resource::feehighburdenrpc;
    }

    return status::ok;
}
예제 #9
0
// {
//   secret: <string>
// }
json::value dovalidationseed (rpc::context& context)
{
    auto lock = getapp().masterlock();
    json::value obj (json::objectvalue);

    if (!context.params.ismember ("secret"))
    {
        std::cerr << "unset validation seed." << std::endl;

        getconfig ().validation_seed.clear ();
        getconfig ().validation_pub.clear ();
        getconfig ().validation_priv.clear ();
    }
    else if (!getconfig ().validation_seed.setseedgeneric (
                 context.params["secret"].asstring ()))
    {
        getconfig ().validation_pub.clear ();
        getconfig ().validation_priv.clear ();

        return rpcerror (rpcbad_seed);
    }
    else
    {
        auto& seed = getconfig ().validation_seed;
        auto& pub = getconfig ().validation_pub;

        pub = rippleaddress::createnodepublic (seed);
        getconfig ().validation_priv = rippleaddress::createnodeprivate (seed);

        obj["validation_public_key"] = pub.humannodepublic ();
        obj["validation_seed"] = seed.humanseed ();
        obj["validation_key"] = seed.humanseed1751 ();
    }

    return obj;
}
// ---------------------------------------------------------------------------
// 
// -----------
void* bvDefPaletteHisto::ccinit(){	
	return(initializeCocoa(getapp(),this));
}
// ---------------------------------------------------------------------------
// 
// -----------
void* bvDefPaletteQuickRaster::ccinit(){	
	return(initializeCocoa(getapp(),this));
}
    void dostartvoting(ledger::ref lastclosedledger, shamap::ref initialposition) override
    {
        // lcl must be validation ledger
        assert (isstartledger(lastclosedledger));
        
        std::uint32_t dividendledger = lastclosedledger->getledgerseq();
        std::map<std::pair<uint64_t, uint64_t>, int> votemap;
        // get validations for validation ledger
        validationset const set = getapp().getvalidations ().getvalidations (lastclosedledger->gethash ());
        for (auto const& e : set)
        {
            stvalidation const& val = *e.second;
            
            if (val.istrusted ())
            {
                if (val.isfieldpresent (sfdividendledger)
                    && val.isfieldpresent (sfdividendcoins)
                    && val.isfieldpresent (sfdividendcoinsvbc))
                {
                    uint32_t ledgerseq = val.getfieldu32 (sfdividendledger);
                    if (ledgerseq != dividendledger) {
                        m_journal.warning << "mismatch ledger seq " << ledgerseq << " from validator " << val.getnodeid() << " ours: " << dividendledger << " in " << lastclosedledger->gethash();
                        continue;
                    }
                    ++votemap[std::make_pair(val.getfieldu64 (sfdividendcoins), val.getfieldu64 (sfdividendcoinsvbc))];
                }
            }
        }
        
        std::pair<uint64_t, uint64_t> ourvote = std::make_pair(0, 0);
        int weight = 0;
        
        for (auto const& e : votemap)
        {
            // take most voted value
            if (e.second > weight)
            {
                ourvote = e.first;
                weight = e.second;
            }
        }
        if (weight < getapp().getledgermaster().getminvalidations()) {
            m_journal.warning << weight << " votes are not enough to start dividend for " << dividendledger;
            return;
        }
        
        if (ourvote.first==0 && ourvote.second==0) {
            if (m_journal.warning)
                m_journal.warning << "not voting for a dividend start because both vrp and vbc voted are 0";
            return;
        }
        
        if (ourvote.first + lastclosedledger->gettotalcoins() > vrp_increase_max &&
            ourvote.second + lastclosedledger->gettotalcoinsvbc() > vbc_increase_max) {
            if (m_journal.error)
                m_journal.error << "not voting for a dividend start because both vrp and vbc will exceed max.";
            return;
        }
        
        if (m_journal.warning)
            m_journal.warning << "we are voting for a dividend start based " << dividendledger << " with vrp " << ourvote.first << " vbc " << ourvote.second << " with " << weight << " same votes in " << lastclosedledger->gethash();

        sttx trans(ttdividend);
        trans.setfieldu8(sfdividendtype, dividendmaster::divtype_start);
        trans.setfieldaccount(sfaccount, account());
        trans.setfieldu32(sfdividendledger, dividendledger);
        trans.setfieldu64(sfdividendcoins, ourvote.first);
		trans.setfieldu64(sfdividendcoinsvbc, ourvote.second);

        uint256 txid = trans.gettransactionid();

        if (m_journal.warning)
            m_journal.warning << "vote: " << txid;

        serializer s;
        trans.add (s, true);

        shamapitem::pointer titem = std::make_shared<shamapitem> (txid, s.peekdata ());

        if (!initialposition->addgiveitem (titem, true, false))
        {
            if (m_journal.warning)
                m_journal.warning << "ledger already had dividend start";
        }
    }
    bool doapplyvoting(ledger::ref lastclosedledger, shamap::ref initialposition) override
    {
        uint32_t dividendledger = lastclosedledger->getdividendbaseledger();
        
        int weight = 0;
        std::map<uint256, int> votes;
        
        // get validations for validation ledger
        validationset const set = getapp().getvalidations ().getvalidations (lastclosedledger->gethash ());
        for (auto const& e : set)
        {
            stvalidation const& val = *e.second;
            
            if (val.istrusted ())
            {
                if (val.isfieldpresent (sfdividendledger) &&
                    val.isfieldpresent (sfdividendresulthash))
                {
                    uint32_t ledgerseq = val.getfieldu32 (sfdividendledger);
                    if (ledgerseq != dividendledger)
                        continue;
                    const uint256 & dividendhash = val.getfieldh256 (sfdividendresulthash);
                    ++votes[dividendhash];
//                    if (ledgerseq != dividendledger || dividendhash != dividendresulthash) {
                    if (m_journal.debug)
                        m_journal.debug << "recv dividend apply vote based " << ledgerseq << " hash " << dividendhash << " from validator " << val.getnodeid() << " in " << lastclosedledger->gethash();
//                        continue;
//                    }
//                    ++weight;
                }
            }
        }
        
        uint256 dividendresulthash;
        for (auto const& v : votes)
        {
            if (v.second > weight)
            {
                dividendresulthash = v.first;
                weight = v.second;
            }
        }
        
        dividendmaster::pointer dividendmaster = getapp().getops().getdividendmaster();
        if (!dividendmaster->trylock())
        {
            if (weight >=getapp().getledgermaster().getminvalidations())
                return false;
            else
                return true;
        }
        
        if (!dividendmaster->isready() ||
            dividendledger != dividendmaster->getledgerseq() ||
            dividendresulthash != dividendmaster->getresulthash())
        {
            if (dividendmaster->isready())
                m_journal.warning << "we got mismatch dividend apply based " << dividendledger << " hash " << dividendresulthash << " ours " << dividendmaster->getresulthash() << " based " << dividendmaster->getledgerseq() << " in " << lastclosedledger->gethash();
            dividendmaster->unlock();
            if (weight >=getapp().getledgermaster().getminvalidations())
                return false;
            else
                return true;
        }
        
        if (weight >= getapp().getledgermaster().getminvalidations())
        {
            m_journal.warning << "we are voting for a dividend apply based " << dividendledger << " hash " << dividendresulthash << " with " << weight << " same votes in " << lastclosedledger->gethash();
            dividendmaster->filldivresult(initialposition);
            dividendmaster->filldivready(initialposition);
            dividendmaster->setready(false);
        }
        else
        {
            m_journal.warning << "we are cancelling a dividend apply with only " << weight << " same votes in " << lastclosedledger->gethash();
            dividendmaster->settotaldividend(0);
            dividendmaster->settotaldividendvbc(0);
            dividendmaster->setsumvrank(0);
            dividendmaster->setsumvspd(0);
            dividendmaster->setresulthash(uint256());
            dividendmaster->filldivready(initialposition);
            dividendmaster->setready(false);
        }
        
        dividendmaster->unlock();
        
        return true;
    }
예제 #14
0
    /** run the ledger cleaner. */
    void doledgercleaner()
    {
        ledger::pointer goodledger;

        while (! this->threadshouldexit())
        {
            ledgerindex ledgerindex;
            ledgerhash ledgerhash;
            bool donodes;
            bool dotxns;

            while (getapp().getfeetrack().isloadedlocal())
            {
                m_journal.debug << "waiting for load to subside";
                std::this_thread::sleep_for(std::chrono::seconds(5));
                if (this->threadshouldexit ())
                    return;
            }

            {
                sharedstate::access state (m_state);
                if ((state->minrange > state->maxrange) ||
                    (state->maxrange == 0) || (state->minrange == 0))
                {
                    state->minrange = state->maxrange = 0;
                    return;
                }
                ledgerindex = state->maxrange;
                donodes = state->checknodes;
                dotxns = state->fixtxns;
            }

            ledgerhash = gethash(ledgerindex, goodledger);

            bool fail = false;
            if (ledgerhash.iszero())
            {
                m_journal.info << "unable to get hash for ledger " << ledgerindex;
                fail = true;
            }
            else if (!doledger(ledgerindex, ledgerhash, donodes, dotxns))
            {
                m_journal.info << "failed to process ledger " << ledgerindex;
                fail = true;
            }

            if (fail)
            {
                {
                    sharedstate::access state (m_state);
                    ++state->failures;
                }
                // wait for acquiring to catch up to us
                std::this_thread::sleep_for(std::chrono::seconds(2));
            }
            else
            {
                {
                    sharedstate::access state (m_state);
                    if (ledgerindex == state->minrange)
                        ++state->minrange;
                    if (ledgerindex == state->maxrange)
                        --state->maxrange;
                    state->failures = 0;
                }
                // reduce i/o pressure and wait for acquiring to catch up to us
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
            }

        }
    }
예제 #15
0
    void doclean (json::value const& params)
    {
        ledgerindex minrange;
        ledgerindex maxrange;
        getapp().getledgermaster().getfullvalidatedrange (minrange, maxrange);

        {
            sharedstate::access state (m_state);

            state->maxrange = maxrange;
            state->minrange = minrange;
            state->checknodes = false;
            state->fixtxns = false;
            state->failures = 0;

            /*
            json parameters:

                all parameters are optional. by default the cleaner cleans
                things it thinks are necessary. this behavior can be modified
                using the following options supplied via json rpc:

                "ledger"
                    a single unsigned integer representing an individual
                    ledger to clean.

                "min_ledger", "max_ledger"
                    unsigned integers representing the starting and ending
                    ledger numbers to clean. if unspecified, clean all ledgers.

                "full"
                    a boolean. when set to true, means clean everything possible.

                "fix_txns"
                    a boolean value indicating whether or not to fix the
                    transactions in the database as well.

                "check_nodes"
                    a boolean, when set to true means check the nodes.

                "stop"
                    a boolean, when set to true informs the cleaner to gracefully
                    stop its current activities if any cleaning is taking place.
            */

            // quick way to fix a single ledger
            if (params.ismember("ledger"))
            {
                state->maxrange = params["ledger"].asuint();
                state->minrange = params["ledger"].asuint();
                state->fixtxns = true;
                state->checknodes = true;
            }

            if (params.ismember("max_ledger"))
                 state->maxrange = params["max_ledger"].asuint();

            if (params.ismember("min_ledger"))
                state->minrange = params["min_ledger"].asuint();

            if (params.ismember("full"))
                state->fixtxns = state->checknodes = params["full"].asbool();

            if (params.ismember("fix_txns"))
                state->fixtxns = params["fix_txns"].asbool();

            if (params.ismember("check_nodes"))
                state->checknodes = params["check_nodes"].asbool();

            if (params.ismember("stop") && params["stop"].asbool())
                state->minrange = state->maxrange = 0;
        }

        notify();
    }