Files
rippled/modules/ripple_app/ledger/LedgerTiming.cpp
2013-07-15 09:37:41 -07:00

157 lines
6.2 KiB
C++

//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
// VFALCO Should rename ContinuousLedgerTiming to LedgerTiming
struct LedgerTiming; // for Log
SETUP_LOG (LedgerTiming)
// NOTE: First and last times must be repeated
int ContinuousLedgerTiming::LedgerTimeResolution[] = { 10, 10, 20, 30, 60, 90, 120, 120 };
// Called when a ledger is open and no close is in progress -- when a transaction is received and no close
// is in process, or when a close completes. Returns the number of seconds the ledger should be be open.
bool ContinuousLedgerTiming::shouldClose (
bool anyTransactions,
int previousProposers, // proposers in the last closing
int proposersClosed, // proposers who have currently closed this ledgers
int proposersValidated, // proposers who have validated the last closed ledger
int previousMSeconds, // milliseconds the previous ledger took to reach consensus
int currentMSeconds, // milliseconds since the previous ledger closed
int openMSeconds, // milliseconds since the previous LCL was computed
int idleInterval) // network's desired idle interval
{
if ((previousMSeconds < -1000) || (previousMSeconds > 600000) ||
(currentMSeconds < -1000) || (currentMSeconds > 600000))
{
WriteLog (lsWARNING, LedgerTiming) <<
boost::str (boost::format ("CLC::shouldClose range Trans=%s, Prop: %d/%d, Secs: %d (last:%d)")
% (anyTransactions ? "yes" : "no") % previousProposers % proposersClosed
% currentMSeconds % previousMSeconds);
return true;
}
if (!anyTransactions)
{
// no transactions so far this interval
if (proposersClosed > (previousProposers / 4)) // did we miss a transaction?
{
WriteLog (lsTRACE, LedgerTiming) << "no transactions, many proposers: now (" << proposersClosed << " closed, "
<< previousProposers << " before)";
return true;
}
#if 0 // This false triggers on the genesis ledger
if (previousMSeconds > (1000 * (LEDGER_IDLE_INTERVAL + 2))) // the last ledger was very slow to close
{
WriteLog (lsTRACE, LedgerTiming) << "was slow to converge (p=" << (previousMSeconds) << ")";
if (previousMSeconds < 2000)
return previousMSeconds;
return previousMSeconds - 1000;
}
#endif
return currentMSeconds >= (idleInterval * 1000); // normal idle
}
if ((openMSeconds < LEDGER_MIN_CLOSE) && ((proposersClosed + proposersValidated) < (previousProposers / 2 )))
{
WriteLog (lsDEBUG, LedgerTiming) << "Must wait minimum time before closing";
return false;
}
if ((currentMSeconds < previousMSeconds) && ((proposersClosed + proposersValidated) < previousProposers))
{
WriteLog (lsDEBUG, LedgerTiming) << "We are waiting for more closes/validations";
return false;
}
return true; // this ledger should close now
}
// Returns whether we have a consensus or not. If so, we expect all honest nodes
// to already have everything they need to accept a consensus. Our vote is 'locked in'.
bool ContinuousLedgerTiming::haveConsensus (
int previousProposers, // proposers in the last closing (not including us)
int currentProposers, // proposers in this closing so far (not including us)
int currentAgree, // proposers who agree with us
int currentFinished, // proposers who have validated a ledger after this one
int previousAgreeTime, // how long it took to agree on the last ledger
int currentAgreeTime, // how long we've been trying to agree
bool forReal, // deciding whether to stop consensus process
bool& failed) // we can't reach a consensus
{
WriteLog (lsTRACE, LedgerTiming) << boost::str (boost::format ("CLC::haveConsensus: prop=%d/%d agree=%d validated=%d time=%d/%d%s") %
currentProposers % previousProposers % currentAgree % currentFinished % currentAgreeTime % previousAgreeTime %
(forReal ? "" : "X"));
if (currentAgreeTime <= LEDGER_MIN_CONSENSUS)
return false;
if (currentProposers < (previousProposers * 3 / 4))
{
// Less than 3/4 of the last ledger's proposers are present, we may need more time
if (currentAgreeTime < (previousAgreeTime + LEDGER_MIN_CONSENSUS))
{
CondLog (forReal, lsTRACE, LedgerTiming) << "too fast, not enough proposers";
return false;
}
}
// If 80% of current proposers (plus us) agree on a set, we have consensus
if (((currentAgree * 100 + 100) / (currentProposers + 1)) > 80)
{
CondLog (forReal, lsINFO, LedgerTiming) << "normal consensus";
failed = false;
return true;
}
// If 80% of the nodes on your UNL have moved on, you should declare consensus
if (((currentFinished * 100) / (currentProposers + 1)) > 80)
{
CondLog (forReal, lsWARNING, LedgerTiming) << "We see no consensus, but 80% of nodes have moved on";
failed = true;
return true;
}
// no consensus yet
CondLog (forReal, lsTRACE, LedgerTiming) << "no consensus";
return false;
}
int ContinuousLedgerTiming::getNextLedgerTimeResolution (int previousResolution, bool previousAgree, int ledgerSeq)
{
assert (ledgerSeq);
if ((!previousAgree) && ((ledgerSeq % LEDGER_RES_DECREASE) == 0))
{
// reduce resolution
int i = 1;
while (LedgerTimeResolution[i] != previousResolution)
++i;
return LedgerTimeResolution[i + 1];
}
if ((previousAgree) && ((ledgerSeq % LEDGER_RES_INCREASE) == 0))
{
// increase resolution
int i = 1;
while (LedgerTimeResolution[i] != previousResolution)
++i;
return LedgerTimeResolution[i - 1];
}
return previousResolution;
}