Files
xahaud/src/ripple_app/ledger/LedgerTiming.cpp
2013-11-20 10:16:46 -08:00

170 lines
7.0 KiB
C++

//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
// 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;
}