ConsensusState checkConsensus ( int previousProposers, int currentProposers, int currentAgree, int currentFinished, std::chrono::milliseconds previousAgreeTime, std::chrono::milliseconds currentAgreeTime, bool proposing, beast::Journal j) { JLOG (j.trace()) << "checkConsensus: prop=" << currentProposers << "/" << previousProposers << " agree=" << currentAgree << " validated=" << currentFinished << " time=" << currentAgreeTime.count() << "/" << previousAgreeTime.count(); if (currentAgreeTime <= LEDGER_MIN_CONSENSUS) return ConsensusState::No; if (currentProposers < (previousProposers * 3 / 4)) { // Less than 3/4 of the last ledger's proposers are present; don't // rush: we may need more time. if (currentAgreeTime < (previousAgreeTime + LEDGER_MIN_CONSENSUS)) { JLOG (j.trace()) << "too fast, not enough proposers"; return ConsensusState::No; } } // Have we, together with the nodes on our UNL list, reached the threshold // to declare consensus? if (checkConsensusReached (currentAgree, currentProposers, proposing)) { JLOG (j.debug()) << "normal consensus"; return ConsensusState::Yes; } // Have sufficient nodes on our UNL list moved on and reached the threshold // to declare consensus? if (checkConsensusReached (currentFinished, currentProposers, false)) { JLOG (j.warn()) << "We see no consensus, but 80% of nodes have moved on"; return ConsensusState::MovedOn; } // no consensus yet JLOG (j.trace()) << "no consensus"; return ConsensusState::No; }
bool shouldCloseLedger ( bool anyTransactions, int previousProposers, int proposersClosed, int proposersValidated, std::chrono::milliseconds previousTime, std::chrono::milliseconds currentTime, // Time since last ledger's close time std::chrono::milliseconds openTime, // Time waiting to close this ledger std::chrono::seconds idleInterval, beast::Journal j) { using namespace std::chrono_literals; if ((previousTime < -1s) || (previousTime > 10min) || (currentTime > 10min)) { // These are unexpected cases, we just close the ledger JLOG (j.warn()) << "shouldCloseLedger Trans=" << (anyTransactions ? "yes" : "no") << " Prop: " << previousProposers << "/" << proposersClosed << " Secs: " << currentTime.count() << " (last: " << previousTime.count() << ")"; return true; } if ((proposersClosed + proposersValidated) > (previousProposers / 2)) { // If more than half of the network has closed, we close JLOG (j.trace()) << "Others have closed"; return true; } if (!anyTransactions) { // Only close at the end of the idle interval return currentTime >= idleInterval; // normal idle } // Preserve minimum ledger open time if (openTime < LEDGER_MIN_CLOSE) { JLOG (j.debug()) << "Must wait minimum time before closing"; return false; } // Don't let this ledger close more than twice as fast as the previous // ledger reached consensus so that slower validators can slow down // the network if (openTime < (previousTime / 2)) { JLOG (j.debug()) << "Ledger has not been open long enough"; return false; } // Close the ledger return true; }
std::pair<std::vector<SignerEntries::SignerEntry>, TER> SignerEntries::deserialize ( STObject const& obj, beast::Journal journal, std::string const& annotation) { std::pair<std::vector<SignerEntry>, TER> s; if (!obj.isFieldPresent (sfSignerEntries)) { JLOG(journal.trace()) << "Malformed " << annotation << ": Need signer entry array."; s.second = temMALFORMED; return s; } auto& accountVec = s.first; accountVec.reserve (STTx::maxMultiSigners); STArray const& sEntries (obj.getFieldArray (sfSignerEntries)); for (STObject const& sEntry : sEntries) { // Validate the SignerEntry. if (sEntry.getFName () != sfSignerEntry) { JLOG(journal.trace()) << "Malformed " << annotation << ": Expected SignerEntry."; s.second = temMALFORMED; return s; } // Extract SignerEntry fields. AccountID const account = sEntry.getAccountID (sfAccount); std::uint16_t const weight = sEntry.getFieldU16 (sfSignerWeight); accountVec.emplace_back (account, weight); } s.second = tesSUCCESS; return s; }
/** We received a TMLedgerData from a peer. */ bool gotLedgerData (LedgerHash const& hash, std::shared_ptr<Peer> peer, std::shared_ptr<protocol::TMLedgerData> packet_ptr) override { protocol::TMLedgerData& packet = *packet_ptr; JLOG (j_.trace()) << "Got data (" << packet.nodes ().size () << ") for acquiring ledger: " << hash; auto ledger = find (hash); if (!ledger) { JLOG (j_.trace()) << "Got data for ledger we're no longer acquiring"; // If it's state node data, stash it because it still might be // useful. if (packet.type () == protocol::liAS_NODE) { app_.getJobQueue().addJob( jtLEDGER_DATA, "gotStaleData", [this, packet_ptr] (Job&) { gotStaleData(packet_ptr); }); } return false; } // Stash the data for later processing and see if we need to dispatch if (ledger->gotData(std::weak_ptr<Peer>(peer), packet_ptr)) app_.getJobQueue().addJob ( jtLEDGER_DATA, "processLedgerData", [this, hash] (Job&) { doLedgerData(hash); }); return true; }
void HTTPReply ( int nStatus, std::string const& content, Json::Output const& output, beast::Journal j) { JLOG (j.trace()) << "HTTP Reply " << nStatus << " " << content; if (nStatus == 401) { output ("HTTP/1.0 401 Authorization Required\r\n"); output (getHTTPHeaderTimestamp ()); // CHECKME this returns a different version than the replies below. Is // this by design or an accident or should it be using // BuildInfo::getFullVersionString () as well? output ("Server: " + systemName () + "-json-rpc/v1"); output ("\r\n"); // Be careful in modifying this! If you change the contents you MUST // update the Content-Length header as well to indicate the correct // size of the data. output ("WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n" "Content-Type: text/html\r\n" "Content-Length: 296\r\n" "\r\n" "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 " "Transitional//EN\"\r\n" "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd" "\">\r\n" "<HTML>\r\n" "<HEAD>\r\n" "<TITLE>Error</TITLE>\r\n" "<META HTTP-EQUIV='Content-Type' " "CONTENT='text/html; charset=ISO-8859-1'>\r\n" "</HEAD>\r\n" "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"); return; } switch (nStatus) { case 200: output ("HTTP/1.1 200 OK\r\n"); break; case 400: output ("HTTP/1.1 400 Bad Request\r\n"); break; case 403: output ("HTTP/1.1 403 Forbidden\r\n"); break; case 404: output ("HTTP/1.1 404 Not Found\r\n"); break; case 500: output ("HTTP/1.1 500 Internal Server Error\r\n"); break; case 503: output ("HTTP/1.1 503 Server is overloaded\r\n"); break; } output (getHTTPHeaderTimestamp ()); output ("Connection: Keep-Alive\r\n" "Content-Length: "); // VFALCO TODO Determine if/when this header should be added //if (context.app.config().RPC_ALLOW_REMOTE) // output ("Access-Control-Allow-Origin: *\r\n"); output (std::to_string(content.size () + 2)); output ("\r\n" "Content-Type: application/json; charset=UTF-8\r\n"); output ("Server: " + systemName () + "-json-rpc/"); output (BuildInfo::getFullVersionString ()); output ("\r\n" "\r\n"); output (content); output ("\r\n"); }
path::RippleCalc::Output flow ( PaymentSandbox& sb, STAmount const& deliver, AccountID const& src, AccountID const& dst, STPathSet const& paths, bool defaultPaths, bool partialPayment, bool ownerPaysTransferFee, boost::optional<Quality> const& limitQuality, boost::optional<STAmount> const& sendMax, beast::Journal j, path::detail::FlowDebugInfo* flowDebugInfo) { Issue const srcIssue = [&] { if (sendMax) return sendMax->issue (); if (!isXRP (deliver.issue ().currency)) return Issue (deliver.issue ().currency, src); return xrpIssue (); }(); Issue const dstIssue = deliver.issue (); boost::optional<Issue> sendMaxIssue; if (sendMax) sendMaxIssue = sendMax->issue (); // convert the paths to a collection of strands. Each strand is the collection // of account->account steps and book steps that may be used in this payment. auto sr = toStrands (sb, src, dst, dstIssue, sendMaxIssue, paths, defaultPaths, ownerPaysTransferFee, j); if (sr.first != tesSUCCESS) { path::RippleCalc::Output result; result.setResult (sr.first); return result; } auto& strands = sr.second; if (j.trace()) { j.trace() << "\nsrc: " << src << "\ndst: " << dst << "\nsrcIssue: " << srcIssue << "\ndstIssue: " << dstIssue; j.trace() << "\nNumStrands: " << strands.size (); for (auto const& curStrand : strands) { j.trace() << "NumSteps: " << curStrand.size (); for (auto const& step : curStrand) { j.trace() << '\n' << *step << '\n'; } } } const bool srcIsXRP = isXRP (srcIssue.currency); const bool dstIsXRP = isXRP (dstIssue.currency); auto const asDeliver = toAmountSpec (deliver); // The src account may send either xrp or iou. The dst account may receive // either xrp or iou. Since XRP and IOU amounts are represented by different // types, use templates to tell `flow` about the amount types. if (srcIsXRP && dstIsXRP) { return finishFlow (sb, srcIssue, dstIssue, flow<XRPAmount, XRPAmount> ( sb, strands, asDeliver.xrp, defaultPaths, partialPayment, limitQuality, sendMax, j, flowDebugInfo)); } if (srcIsXRP && !dstIsXRP) { return finishFlow (sb, srcIssue, dstIssue, flow<XRPAmount, IOUAmount> ( sb, strands, asDeliver.iou, defaultPaths, partialPayment, limitQuality, sendMax, j, flowDebugInfo)); } if (!srcIsXRP && dstIsXRP) { return finishFlow (sb, srcIssue, dstIssue, flow<IOUAmount, XRPAmount> ( sb, strands, asDeliver.xrp, defaultPaths, partialPayment, limitQuality, sendMax, j, flowDebugInfo)); } assert (!srcIsXRP && !dstIsXRP); return finishFlow (sb, srcIssue, dstIssue, flow<IOUAmount, IOUAmount> ( sb, strands, asDeliver.iou, defaultPaths, partialPayment, limitQuality, sendMax, j, flowDebugInfo)); }