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; }
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(); }
/** 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; }
/** 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; }
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; }
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; }
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; }
// { // 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; }
/** 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)); } } }
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(); }