6b3bb3d9ba
This changes the logging categories to boolean flags instead of strings. This simplifies the acceptance testing by avoiding accessing a scoped static thread local pointer to a thread local set of strings. It eliminates the only use of boost::thread_specific_ptr outside of lockorder debugging. This change allows log entries to be directed to multiple categories and makes it easy to change the logging flags at runtime (e.g. via an RPC, though that isn't done by this commit.) It also eliminates the fDebug global. Configuration of unknown logging categories now produces a warning.
121 lines
3.9 KiB
C++
121 lines
3.9 KiB
C++
// Copyright (c) 2014-2016 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#if defined(HAVE_CONFIG_H)
|
|
#include "config/bitcoin-config.h"
|
|
#endif
|
|
|
|
#include "timedata.h"
|
|
|
|
#include "netaddress.h"
|
|
#include "sync.h"
|
|
#include "ui_interface.h"
|
|
#include "util.h"
|
|
#include "utilstrencodings.h"
|
|
#include "warnings.h"
|
|
|
|
#include <boost/foreach.hpp>
|
|
|
|
static CCriticalSection cs_nTimeOffset;
|
|
static int64_t nTimeOffset = 0;
|
|
|
|
/**
|
|
* "Never go to sea with two chronometers; take one or three."
|
|
* Our three time sources are:
|
|
* - System clock
|
|
* - Median of other nodes clocks
|
|
* - The user (asking the user to fix the system clock if the first two disagree)
|
|
*/
|
|
int64_t GetTimeOffset()
|
|
{
|
|
LOCK(cs_nTimeOffset);
|
|
return nTimeOffset;
|
|
}
|
|
|
|
int64_t GetAdjustedTime()
|
|
{
|
|
return GetTime() + GetTimeOffset();
|
|
}
|
|
|
|
static int64_t abs64(int64_t n)
|
|
{
|
|
return (n >= 0 ? n : -n);
|
|
}
|
|
|
|
#define BITCOIN_TIMEDATA_MAX_SAMPLES 200
|
|
|
|
void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample)
|
|
{
|
|
LOCK(cs_nTimeOffset);
|
|
// Ignore duplicates
|
|
static std::set<CNetAddr> setKnown;
|
|
if (setKnown.size() == BITCOIN_TIMEDATA_MAX_SAMPLES)
|
|
return;
|
|
if (!setKnown.insert(ip).second)
|
|
return;
|
|
|
|
// Add data
|
|
static CMedianFilter<int64_t> vTimeOffsets(BITCOIN_TIMEDATA_MAX_SAMPLES, 0);
|
|
vTimeOffsets.input(nOffsetSample);
|
|
LogPrint(BCLog::NET,"added time data, samples %d, offset %+d (%+d minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60);
|
|
|
|
// There is a known issue here (see issue #4521):
|
|
//
|
|
// - The structure vTimeOffsets contains up to 200 elements, after which
|
|
// any new element added to it will not increase its size, replacing the
|
|
// oldest element.
|
|
//
|
|
// - The condition to update nTimeOffset includes checking whether the
|
|
// number of elements in vTimeOffsets is odd, which will never happen after
|
|
// there are 200 elements.
|
|
//
|
|
// But in this case the 'bug' is protective against some attacks, and may
|
|
// actually explain why we've never seen attacks which manipulate the
|
|
// clock offset.
|
|
//
|
|
// So we should hold off on fixing this and clean it up as part of
|
|
// a timing cleanup that strengthens it in a number of other ways.
|
|
//
|
|
if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1)
|
|
{
|
|
int64_t nMedian = vTimeOffsets.median();
|
|
std::vector<int64_t> vSorted = vTimeOffsets.sorted();
|
|
// Only let other nodes change our time by so much
|
|
if (abs64(nMedian) <= std::max<int64_t>(0, GetArg("-maxtimeadjustment", DEFAULT_MAX_TIME_ADJUSTMENT)))
|
|
{
|
|
nTimeOffset = nMedian;
|
|
}
|
|
else
|
|
{
|
|
nTimeOffset = 0;
|
|
|
|
static bool fDone;
|
|
if (!fDone)
|
|
{
|
|
// If nobody has a time different than ours but within 5 minutes of ours, give a warning
|
|
bool fMatch = false;
|
|
BOOST_FOREACH(int64_t nOffset, vSorted)
|
|
if (nOffset != 0 && abs64(nOffset) < 5 * 60)
|
|
fMatch = true;
|
|
|
|
if (!fMatch)
|
|
{
|
|
fDone = true;
|
|
std::string strMessage = strprintf(_("Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly."), _(PACKAGE_NAME));
|
|
SetMiscWarning(strMessage);
|
|
uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (LogAcceptCategory(BCLog::NET)) {
|
|
BOOST_FOREACH(int64_t n, vSorted) {
|
|
LogPrint(BCLog::NET, "%+d ", n);
|
|
}
|
|
LogPrint(BCLog::NET, "| ");
|
|
|
|
LogPrint(BCLog::NET, "nTimeOffset = %+d (%+d minutes)\n", nTimeOffset, nTimeOffset/60);
|
|
}
|
|
}
|
|
}
|