Add a clock for testing with an offset from the system clock.
This change improves clock management for zcashd by ensuring that all clock methods (obtaining seconds, milliseconds, and microseconds since the epoch) agree under testing conditions using `-mocktime`, and also adds a feature that allows tests to specify an offset to the system clock; this is useful to allow comprehensive testing of the "timejacking attack mitigation" consensus rules.
This commit is contained in:
parent
bb64e895c2
commit
88401bc25e
|
@ -20,7 +20,7 @@ const uint256 TX_ID3 = ArithToUint256(3);
|
|||
TEST(MempoolLimitTests, RecentlyEvictedListAddWrapsAfterMaxSize)
|
||||
{
|
||||
RecentlyEvictedList recentlyEvicted(2, 100);
|
||||
SetMockTime(1);
|
||||
FixedClock::SetGlobal(1);
|
||||
recentlyEvicted.add(TX_ID1);
|
||||
recentlyEvicted.add(TX_ID2);
|
||||
recentlyEvicted.add(TX_ID3);
|
||||
|
@ -28,56 +28,59 @@ TEST(MempoolLimitTests, RecentlyEvictedListAddWrapsAfterMaxSize)
|
|||
EXPECT_FALSE(recentlyEvicted.contains(TX_ID1));
|
||||
EXPECT_TRUE(recentlyEvicted.contains(TX_ID2));
|
||||
EXPECT_TRUE(recentlyEvicted.contains(TX_ID3));
|
||||
SystemClock::SetGlobal();
|
||||
}
|
||||
|
||||
TEST(MempoolLimitTests, RecentlyEvictedListDoesNotContainAfterExpiry)
|
||||
{
|
||||
SetMockTime(1);
|
||||
FixedClock::SetGlobal(1);
|
||||
// maxSize=3, timeToKeep=1
|
||||
RecentlyEvictedList recentlyEvicted(3, 1);
|
||||
recentlyEvicted.add(TX_ID1);
|
||||
SetMockTime(2);
|
||||
FixedClock::SetGlobal(2);
|
||||
recentlyEvicted.add(TX_ID2);
|
||||
recentlyEvicted.add(TX_ID3);
|
||||
// After 1 second the txId will still be there
|
||||
EXPECT_TRUE(recentlyEvicted.contains(TX_ID1));
|
||||
EXPECT_TRUE(recentlyEvicted.contains(TX_ID2));
|
||||
EXPECT_TRUE(recentlyEvicted.contains(TX_ID3));
|
||||
SetMockTime(3);
|
||||
FixedClock::SetGlobal(3);
|
||||
// After 2 seconds it is gone
|
||||
EXPECT_FALSE(recentlyEvicted.contains(TX_ID1));
|
||||
EXPECT_TRUE(recentlyEvicted.contains(TX_ID2));
|
||||
EXPECT_TRUE(recentlyEvicted.contains(TX_ID3));
|
||||
SetMockTime(4);
|
||||
FixedClock::SetGlobal(4);
|
||||
EXPECT_FALSE(recentlyEvicted.contains(TX_ID1));
|
||||
EXPECT_FALSE(recentlyEvicted.contains(TX_ID2));
|
||||
EXPECT_FALSE(recentlyEvicted.contains(TX_ID3));
|
||||
SystemClock::SetGlobal();
|
||||
}
|
||||
|
||||
TEST(MempoolLimitTests, RecentlyEvictedDropOneAtATime)
|
||||
{
|
||||
SetMockTime(1);
|
||||
FixedClock::SetGlobal(1);
|
||||
RecentlyEvictedList recentlyEvicted(3, 2);
|
||||
recentlyEvicted.add(TX_ID1);
|
||||
SetMockTime(2);
|
||||
FixedClock::SetGlobal(2);
|
||||
recentlyEvicted.add(TX_ID2);
|
||||
SetMockTime(3);
|
||||
FixedClock::SetGlobal(3);
|
||||
recentlyEvicted.add(TX_ID3);
|
||||
EXPECT_TRUE(recentlyEvicted.contains(TX_ID1));
|
||||
EXPECT_TRUE(recentlyEvicted.contains(TX_ID2));
|
||||
EXPECT_TRUE(recentlyEvicted.contains(TX_ID3));
|
||||
SetMockTime(4);
|
||||
FixedClock::SetGlobal(4);
|
||||
EXPECT_FALSE(recentlyEvicted.contains(TX_ID1));
|
||||
EXPECT_TRUE(recentlyEvicted.contains(TX_ID2));
|
||||
EXPECT_TRUE(recentlyEvicted.contains(TX_ID3));
|
||||
SetMockTime(5);
|
||||
FixedClock::SetGlobal(5);
|
||||
EXPECT_FALSE(recentlyEvicted.contains(TX_ID1));
|
||||
EXPECT_FALSE(recentlyEvicted.contains(TX_ID2));
|
||||
EXPECT_TRUE(recentlyEvicted.contains(TX_ID3));
|
||||
SetMockTime(6);
|
||||
FixedClock::SetGlobal(6);
|
||||
EXPECT_FALSE(recentlyEvicted.contains(TX_ID1));
|
||||
EXPECT_FALSE(recentlyEvicted.contains(TX_ID2));
|
||||
EXPECT_FALSE(recentlyEvicted.contains(TX_ID3));
|
||||
SystemClock::SetGlobal();
|
||||
}
|
||||
|
||||
TEST(MempoolLimitTests, WeightedTxTreeCheckSizeAfterDropping)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
TEST(Metrics, AtomicTimer) {
|
||||
AtomicTimer t;
|
||||
SetMockTime(100);
|
||||
FixedClock::SetGlobal(100);
|
||||
|
||||
EXPECT_FALSE(t.running());
|
||||
|
||||
|
@ -36,13 +36,13 @@ TEST(Metrics, AtomicTimer) {
|
|||
c.increment();
|
||||
EXPECT_EQ(0, t.rate(c));
|
||||
|
||||
SetMockTime(101);
|
||||
FixedClock::SetGlobal(101);
|
||||
EXPECT_EQ(1, t.rate(c));
|
||||
|
||||
c.decrement();
|
||||
EXPECT_EQ(0, t.rate(c));
|
||||
|
||||
SetMockTime(102);
|
||||
FixedClock::SetGlobal(102);
|
||||
EXPECT_EQ(0, t.rate(c));
|
||||
|
||||
c.increment();
|
||||
|
@ -51,17 +51,19 @@ TEST(Metrics, AtomicTimer) {
|
|||
t.stop();
|
||||
EXPECT_FALSE(t.running());
|
||||
EXPECT_EQ(0.5, t.rate(c));
|
||||
|
||||
SystemClock::SetGlobal();
|
||||
}
|
||||
|
||||
TEST(Metrics, GetLocalSolPS) {
|
||||
SetMockTime(100);
|
||||
FixedClock::SetGlobal(100);
|
||||
miningTimer.start();
|
||||
|
||||
// No time has passed
|
||||
EXPECT_EQ(0, GetLocalSolPS());
|
||||
|
||||
// Increment time
|
||||
SetMockTime(101);
|
||||
FixedClock::SetGlobal(101);
|
||||
EXPECT_EQ(0, GetLocalSolPS());
|
||||
|
||||
// Increment solutions
|
||||
|
@ -69,7 +71,7 @@ TEST(Metrics, GetLocalSolPS) {
|
|||
EXPECT_EQ(1, GetLocalSolPS());
|
||||
|
||||
// Increment time
|
||||
SetMockTime(102);
|
||||
FixedClock::SetGlobal(102);
|
||||
EXPECT_EQ(0.5, GetLocalSolPS());
|
||||
|
||||
// Increment solutions
|
||||
|
@ -82,7 +84,7 @@ TEST(Metrics, GetLocalSolPS) {
|
|||
EXPECT_EQ(1.5, GetLocalSolPS());
|
||||
|
||||
// Increment time
|
||||
SetMockTime(103);
|
||||
FixedClock::SetGlobal(103);
|
||||
EXPECT_EQ(1.5, GetLocalSolPS());
|
||||
|
||||
// Start timing again
|
||||
|
@ -90,7 +92,7 @@ TEST(Metrics, GetLocalSolPS) {
|
|||
EXPECT_EQ(1.5, GetLocalSolPS());
|
||||
|
||||
// Increment time
|
||||
SetMockTime(104);
|
||||
FixedClock::SetGlobal(104);
|
||||
EXPECT_EQ(1, GetLocalSolPS());
|
||||
|
||||
miningTimer.stop();
|
||||
|
@ -98,6 +100,8 @@ TEST(Metrics, GetLocalSolPS) {
|
|||
solutionTargetChecks.decrement();
|
||||
solutionTargetChecks.decrement();
|
||||
solutionTargetChecks.decrement();
|
||||
|
||||
SystemClock::SetGlobal();
|
||||
}
|
||||
|
||||
TEST(Metrics, EstimateNetHeight) {
|
||||
|
@ -106,11 +110,12 @@ TEST(Metrics, EstimateNetHeight) {
|
|||
for (int i = 0; i < 400; i++) {
|
||||
blockTimes[i] = i ? blockTimes[i - 1] + params.PoWTargetSpacing(i) : 0;
|
||||
}
|
||||
SetMockTime(blockTimes[399]);
|
||||
FixedClock::SetGlobal(blockTimes[399]);
|
||||
for (int i = 0; i < 400; i++) {
|
||||
// Check that we are within 1 of the correct height
|
||||
EXPECT_LT(std::abs(399 - EstimateNetHeight(params, i, blockTimes[i])), 2);
|
||||
}
|
||||
SystemClock::SetGlobal();
|
||||
RegtestDeactivateBlossom();
|
||||
}
|
||||
|
||||
|
|
13
src/init.cpp
13
src/init.cpp
|
@ -1240,8 +1240,17 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||
|
||||
fAlerts = GetBoolArg("-alerts", DEFAULT_ALERTS);
|
||||
|
||||
// Option to startup with mocktime set (used for regression testing):
|
||||
SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op
|
||||
// Option to startup with mocktime set (used for regression testing);
|
||||
// an mocktime of 0 (the default) selects the system clock.
|
||||
int64_t nMockTime = GetArg("-mocktime", 0);
|
||||
if (nMockTime != 0) {
|
||||
FixedClock::SetGlobal(nMockTime);
|
||||
} else {
|
||||
// Option to start a node with the system clock offset by a constant
|
||||
// value throughout the life of the node (used for regression testing):
|
||||
int64_t nOffsetTime = GetArg("-clockoffset", 0);
|
||||
OffsetClock::SetGlobal(nOffsetTime);
|
||||
}
|
||||
|
||||
if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
|
||||
nLocalServices |= NODE_BLOOM;
|
||||
|
|
|
@ -513,7 +513,12 @@ UniValue setmocktime(const UniValue& params, bool fHelp)
|
|||
LOCK2(cs_main, cs_vNodes);
|
||||
|
||||
RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
|
||||
SetMockTime(params[0].get_int64());
|
||||
int64_t nMockTime = params[0].get_int64();
|
||||
if (nMockTime == 0) {
|
||||
SystemClock::SetGlobal();
|
||||
} else {
|
||||
FixedClock::SetGlobal(nMockTime);
|
||||
}
|
||||
|
||||
uint64_t t = GetTime();
|
||||
for (CNode* pnode : vNodes) {
|
||||
|
|
|
@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
|
|||
const Consensus::Params& params = Params().GetConsensus();
|
||||
CNode::ClearBanned();
|
||||
int64_t nStartTime = GetTime();
|
||||
SetMockTime(nStartTime); // Overrides future calls to GetTime()
|
||||
FixedClock::SetGlobal(nStartTime); // Overrides future calls to GetTime()
|
||||
|
||||
CAddress addr(ip(0xa0b0c001));
|
||||
CNode dummyNode(INVALID_SOCKET, addr, "", true);
|
||||
|
@ -106,11 +106,13 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
|
|||
SendMessages(params, &dummyNode);
|
||||
BOOST_CHECK(CNode::IsBanned(addr));
|
||||
|
||||
SetMockTime(nStartTime+60*60);
|
||||
FixedClock::SetGlobal(nStartTime+60*60);
|
||||
BOOST_CHECK(CNode::IsBanned(addr));
|
||||
|
||||
SetMockTime(nStartTime+60*60*24+1);
|
||||
FixedClock::SetGlobal(nStartTime+60*60*24+1);
|
||||
BOOST_CHECK(!CNode::IsBanned(addr));
|
||||
|
||||
SystemClock::SetGlobal();
|
||||
}
|
||||
|
||||
CTransaction RandomOrphan()
|
||||
|
|
|
@ -289,7 +289,7 @@ BOOST_FIXTURE_TEST_SUITE(Alert_tests, ReadAlerts)
|
|||
|
||||
BOOST_AUTO_TEST_CASE(AlertApplies)
|
||||
{
|
||||
SetMockTime(11);
|
||||
FixedClock::SetGlobal(11);
|
||||
const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
|
||||
|
||||
for (const CAlert& alert : alerts)
|
||||
|
@ -342,13 +342,13 @@ BOOST_AUTO_TEST_CASE(AlertApplies)
|
|||
// SubVer without comment doesn't match SubVer pattern with
|
||||
BOOST_CHECK(!alerts[3].AppliesTo(1, "/MagicBean:0.2.1/"));
|
||||
|
||||
SetMockTime(0);
|
||||
SystemClock::SetGlobal();
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(AlertNotify)
|
||||
{
|
||||
SetMockTime(11);
|
||||
FixedClock::SetGlobal(11);
|
||||
const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
|
||||
|
||||
fs::path temp = fs::temp_directory_path() /
|
||||
|
@ -382,13 +382,13 @@ BOOST_AUTO_TEST_CASE(AlertNotify)
|
|||
#endif
|
||||
fs::remove(temp);
|
||||
|
||||
SetMockTime(0);
|
||||
SystemClock::SetGlobal();
|
||||
mapAlerts.clear();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(AlertDisablesRPC)
|
||||
{
|
||||
SetMockTime(11);
|
||||
FixedClock::SetGlobal(11);
|
||||
const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
|
||||
|
||||
// Command should work before alerts
|
||||
|
@ -404,7 +404,7 @@ BOOST_AUTO_TEST_CASE(AlertDisablesRPC)
|
|||
BOOST_CHECK_EQUAL(alerts[8].strRPCError, "");
|
||||
BOOST_CHECK_EQUAL(GetWarnings("rpc").first, "");
|
||||
|
||||
SetMockTime(0);
|
||||
SystemClock::SetGlobal();
|
||||
mapAlerts.clear();
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ BOOST_AUTO_TEST_CASE(May15)
|
|||
// test/data/Mar12Fork.dat from
|
||||
// http://sourceforge.net/projects/bitcoin/files/Bitcoin/blockchain/Mar12Fork.dat/download
|
||||
unsigned int tMay15 = 1368576000;
|
||||
SetMockTime(tMay15); // Test as if it was right at May 15
|
||||
FixedClock::SetGlobal(tMay15); // Test as if it was right at May 15
|
||||
|
||||
CBlock forkingBlock;
|
||||
if (read_block("Mar12Fork.dat", forkingBlock))
|
||||
|
@ -61,7 +61,7 @@ BOOST_AUTO_TEST_CASE(May15)
|
|||
BOOST_CHECK(CheckBlock(forkingBlock, state, Params(), verifier, false, false, true));
|
||||
}
|
||||
|
||||
SetMockTime(0);
|
||||
SystemClock::SetGlobal();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
|
@ -253,7 +253,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||
pblock->nSolution = soln;
|
||||
|
||||
CValidationState state;
|
||||
|
||||
|
||||
if (ProcessNewBlock(state, NULL, pblock, true, NULL) && state.IsValid()) {
|
||||
goto foundit;
|
||||
}
|
||||
|
@ -408,7 +408,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||
chainActive.Tip()->nHeight = nHeight;
|
||||
|
||||
// non-final txs in mempool
|
||||
SetMockTime(chainActive.Tip()->GetMedianTimePast()+1);
|
||||
FixedClock::SetGlobal(chainActive.Tip()->GetMedianTimePast()+1);
|
||||
|
||||
// height locked
|
||||
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
|
||||
|
@ -443,7 +443,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||
|
||||
// However if we advance height and time by one, both will.
|
||||
chainActive.Tip()->nHeight++;
|
||||
SetMockTime(chainActive.Tip()->GetMedianTimePast()+2);
|
||||
FixedClock::SetGlobal(chainActive.Tip()->GetMedianTimePast()+2);
|
||||
|
||||
// FIXME: we should *actually* create a new block so the following test
|
||||
// works; CheckFinalTx() isn't fooled by monkey-patching nHeight.
|
||||
|
@ -455,7 +455,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||
delete pblocktemplate;
|
||||
|
||||
chainActive.Tip()->nHeight--;
|
||||
SetMockTime(0);
|
||||
SystemClock::SetGlobal();
|
||||
mempool.clear();
|
||||
|
||||
for (CTransaction *tx : txFirst)
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#endif
|
||||
|
||||
#include "utiltime.h"
|
||||
#include "sync.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
@ -16,32 +17,85 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
static int64_t nMockTime = 0; //!< For unit testing
|
||||
RecursiveMutex clock_lock;
|
||||
static CClock* zcashdClock = SystemClock::Instance();
|
||||
|
||||
int64_t GetTime()
|
||||
{
|
||||
if (nMockTime) return nMockTime;
|
||||
|
||||
return time(NULL);
|
||||
void SystemClock::SetGlobal() {
|
||||
LOCK(clock_lock);
|
||||
zcashdClock = SystemClock::Instance();
|
||||
}
|
||||
|
||||
void SetMockTime(int64_t nMockTimeIn)
|
||||
{
|
||||
nMockTime = nMockTimeIn;
|
||||
int64_t SystemClock::GetTime() const {
|
||||
return std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
int64_t GetTimeMillis()
|
||||
{
|
||||
int64_t SystemClock::GetTimeMillis() const {
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
int64_t GetTimeMicros()
|
||||
{
|
||||
int64_t SystemClock::GetTimeMicros() const {
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
void FixedClock::SetGlobal(int64_t nFixedTime) {
|
||||
LOCK(clock_lock);
|
||||
FixedClock::Instance()->Set(nFixedTime);
|
||||
zcashdClock = FixedClock::Instance();
|
||||
}
|
||||
|
||||
int64_t FixedClock::GetTime() const {
|
||||
return nFixedTime;
|
||||
}
|
||||
|
||||
int64_t FixedClock::GetTimeMillis() const {
|
||||
return nFixedTime * 1000;
|
||||
}
|
||||
|
||||
int64_t FixedClock::GetTimeMicros() const {
|
||||
return nFixedTime * 1000000;
|
||||
}
|
||||
|
||||
OffsetClock OffsetClock::instance;
|
||||
|
||||
void OffsetClock::SetGlobal(int64_t nOffsetSeconds) {
|
||||
LOCK(clock_lock);
|
||||
OffsetClock::Instance()->Set(nOffsetSeconds);
|
||||
zcashdClock = OffsetClock::Instance();
|
||||
}
|
||||
|
||||
int64_t OffsetClock::GetTime() const {
|
||||
return std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).count()
|
||||
+ nOffsetSeconds;
|
||||
}
|
||||
|
||||
int64_t OffsetClock::GetTimeMillis() const {
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).count()
|
||||
+ (nOffsetSeconds * 1000);
|
||||
}
|
||||
|
||||
int64_t OffsetClock::GetTimeMicros() const {
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).count()
|
||||
+ (nOffsetSeconds * 1000000);
|
||||
}
|
||||
|
||||
int64_t GetTime() {
|
||||
return zcashdClock->GetTime();
|
||||
}
|
||||
|
||||
int64_t GetTimeMillis() {
|
||||
return zcashdClock->GetTimeMillis();
|
||||
}
|
||||
|
||||
int64_t GetTimeMicros() {
|
||||
return zcashdClock->GetTimeMicros();
|
||||
}
|
||||
|
||||
void MilliSleep(int64_t n)
|
||||
{
|
||||
// This is defined to be an interruption point.
|
||||
|
|
|
@ -10,10 +10,102 @@
|
|||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
class CClock {
|
||||
public:
|
||||
/** Returns the current time in seconds since the POSIX epoch. */
|
||||
virtual int64_t GetTime() const = 0;
|
||||
/** Returns the current time in milliseconds since the POSIX epoch. */
|
||||
virtual int64_t GetTimeMillis() const = 0;
|
||||
/** Returns the current time in microseconds since the POSIX epoch. */
|
||||
virtual int64_t GetTimeMicros() const = 0;
|
||||
};
|
||||
|
||||
class SystemClock: public CClock {
|
||||
private:
|
||||
SystemClock() {}
|
||||
~SystemClock() {}
|
||||
SystemClock(SystemClock const&) = delete;
|
||||
SystemClock& operator=(const SystemClock&)= delete;
|
||||
public:
|
||||
static SystemClock* Instance() {
|
||||
static SystemClock instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
/** Sets the clock used by zcashd to the system clock. */
|
||||
static void SetGlobal();
|
||||
|
||||
int64_t GetTime() const;
|
||||
int64_t GetTimeMillis() const;
|
||||
int64_t GetTimeMicros() const;
|
||||
};
|
||||
|
||||
class FixedClock: public CClock {
|
||||
private:
|
||||
static FixedClock instance;
|
||||
int64_t nFixedTime;
|
||||
|
||||
FixedClock(): nFixedTime(0) {}
|
||||
~FixedClock() {}
|
||||
FixedClock(FixedClock const&) = delete;
|
||||
FixedClock& operator=(const FixedClock&)= delete;
|
||||
|
||||
void Set(int64_t nFixedTime) {
|
||||
this->nFixedTime = nFixedTime;
|
||||
}
|
||||
public:
|
||||
static FixedClock* Instance() {
|
||||
static FixedClock instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the clock used by zcashd to a fixed clock that always
|
||||
* returns the specified timestamp.
|
||||
*/
|
||||
static void SetGlobal(int64_t nFixedTime);
|
||||
|
||||
int64_t GetTime() const;
|
||||
int64_t GetTimeMillis() const;
|
||||
int64_t GetTimeMicros() const;
|
||||
};
|
||||
|
||||
class OffsetClock: public CClock {
|
||||
private:
|
||||
static OffsetClock instance;
|
||||
int64_t nOffsetSeconds;
|
||||
|
||||
OffsetClock(): nOffsetSeconds(0) {}
|
||||
~OffsetClock() {}
|
||||
OffsetClock(OffsetClock const&) = delete;
|
||||
OffsetClock& operator=(const OffsetClock&)= delete;
|
||||
|
||||
void Set(int64_t nOffsetSeconds) {
|
||||
this->nOffsetSeconds = nOffsetSeconds;
|
||||
}
|
||||
public:
|
||||
static OffsetClock* Instance() {
|
||||
static OffsetClock instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the clock used by zcashd to a clock that returns the current
|
||||
* system time modified by the specified offset.
|
||||
*/
|
||||
static void SetGlobal(int64_t nOffsetSeconds);
|
||||
|
||||
int64_t GetTime() const;
|
||||
int64_t GetTimeMillis() const;
|
||||
int64_t GetTimeMicros() const;
|
||||
};
|
||||
|
||||
const CClock& GetClock();
|
||||
|
||||
int64_t GetTime();
|
||||
int64_t GetTimeMillis();
|
||||
int64_t GetTimeMicros();
|
||||
void SetMockTime(int64_t nMockTimeIn);
|
||||
|
||||
void MilliSleep(int64_t n);
|
||||
|
||||
std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime);
|
||||
|
|
Loading…
Reference in New Issue