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:
Kris Nuttycombe 2022-06-28 17:18:36 -06:00
parent a423c2af8c
commit e7922af588
17 changed files with 299 additions and 90 deletions

View File

@ -122,12 +122,18 @@ class MaxUploadTest(BitcoinTestFramework):
initialize_chain_clean(self.options.tmpdir, 2)
def setup_network(self):
# We will start the node mocking the time otherwise things break
# because the CNode time counters can't be reset backward after
# initialization
old_time = int(time.time() - 60*60*24*9)
# Start a node with maxuploadtarget of 200 MB (/24h)
self.nodes = []
self.nodes.append(start_node(0, self.options.tmpdir, [
"-debug",
'-nuparams=2bb40e60:1', # Blossom
"-maxuploadtarget=2200"]))
"-maxuploadtarget=2200",
"-mocktime=%d" % old_time ]))
def mine_full_block(self, node, address):
# Want to create a full block
@ -155,12 +161,6 @@ class MaxUploadTest(BitcoinTestFramework):
node.generate(1)
def run_test(self):
# Before we connect anything, we first set the time on the node
# to be in the past, otherwise things break because the CNode
# time counters can't be reset backward after initialization
old_time = int(time.time() - 60*60*24*9)
self.nodes[0].setmocktime(old_time)
# Generate some old blocks
self.nodes[0].generate(260)

View File

@ -262,12 +262,14 @@ def initialize_chain(test_dir, num_nodes, cachedir):
shutil.rmtree(os.path.join(cachedir,"node"+str(i)))
# Create cache directories, run bitcoinds:
block_time = int(time.time()) - (200 * PRE_BLOSSOM_BLOCK_TARGET_SPACING)
for i in range(MAX_NODES):
datadir=initialize_datadir(cachedir, i)
args = [ os.getenv("ZCASHD", ZCASHD_BINARY), "-keypool=1", "-datadir="+datadir, "-discover=0" ]
args.extend([
'-nuparams=5ba81b19:1', # Overwinter
'-nuparams=76b809bb:1', # Sapling
'-mocktime=%d' % block_time
])
if i > 0:
args.append("-connect=127.0.0.1:"+str(p2p_port(0)))
@ -294,7 +296,6 @@ def initialize_chain(test_dir, num_nodes, cachedir):
# Blocks are created with timestamps 2.5 minutes apart (matching the
# chain defaulting above to Sapling active), starting 200 * 2.5 minutes
# before the current time.
block_time = int(time.time()) - (200 * PRE_BLOSSOM_BLOCK_TARGET_SPACING)
for i in range(2):
for peer in range(4):
for j in range(25):

View File

@ -23,28 +23,37 @@ class Wallet1941RegressionTest (BitcoinTestFramework):
# Start nodes with -regtestshieldcoinbase to set fCoinbaseMustBeShielded to true.
def setup_network(self, split=False):
self.nodes = start_nodes(1, self.options.tmpdir, extra_args=[['-regtestshieldcoinbase','-debug=zrpc']] )
self.nodes = start_nodes(1, self.options.tmpdir, extra_args=[[
'-regtestshieldcoinbase',
'-debug=zrpc',
'-mocktime=%d' % starttime
]] )
self.is_network_split=False
def add_second_node(self):
initialize_datadir(self.options.tmpdir, 1)
self.nodes.append(start_node(1, self.options.tmpdir, extra_args=['-regtestshieldcoinbase','-debug=zrpc']))
self.nodes[1].setmocktime(starttime + 9000)
self.nodes.append(start_node(1, self.options.tmpdir, extra_args=[
'-regtestshieldcoinbase',
'-debug=zrpc',
'-mocktime=%d' % (starttime + 9000)
]))
connect_nodes_bi(self.nodes,0,1)
self.sync_all()
def restart_second_node(self, extra_args=[]):
self.nodes[1].stop()
bitcoind_processes[1].wait()
self.nodes[1] = start_node(1, self.options.tmpdir, extra_args=['-regtestshieldcoinbase','-debug=zrpc'] + extra_args)
self.nodes[1].setmocktime(starttime + 9000)
self.nodes[1] = start_node(1, self.options.tmpdir, extra_args=[
'-regtestshieldcoinbase',
'-debug=zrpc',
'-mocktime=%d' % (starttime + 9000)
] + extra_args)
connect_nodes_bi(self.nodes, 0, 1)
self.sync_all()
def run_test (self):
print("Mining blocks...")
self.nodes[0].setmocktime(starttime)
self.nodes[0].generate(101)
self.sync_all()

View File

@ -19,8 +19,8 @@ const uint256 TX_ID3 = ArithToUint256(3);
TEST(MempoolLimitTests, RecentlyEvictedListAddWrapsAfterMaxSize)
{
RecentlyEvictedList recentlyEvicted(2, 100);
SetMockTime(1);
FixedClock clock(std::chrono::seconds(1));
RecentlyEvictedList recentlyEvicted(&clock, 2, 100);
recentlyEvicted.add(TX_ID1);
recentlyEvicted.add(TX_ID2);
recentlyEvicted.add(TX_ID3);
@ -32,23 +32,23 @@ TEST(MempoolLimitTests, RecentlyEvictedListAddWrapsAfterMaxSize)
TEST(MempoolLimitTests, RecentlyEvictedListDoesNotContainAfterExpiry)
{
SetMockTime(1);
FixedClock clock(std::chrono::seconds(1));
// maxSize=3, timeToKeep=1
RecentlyEvictedList recentlyEvicted(3, 1);
RecentlyEvictedList recentlyEvicted(&clock, 3, 1);
recentlyEvicted.add(TX_ID1);
SetMockTime(2);
clock.Set(std::chrono::seconds(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);
clock.Set(std::chrono::seconds(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);
clock.Set(std::chrono::seconds(4));
EXPECT_FALSE(recentlyEvicted.contains(TX_ID1));
EXPECT_FALSE(recentlyEvicted.contains(TX_ID2));
EXPECT_FALSE(recentlyEvicted.contains(TX_ID3));
@ -56,25 +56,25 @@ TEST(MempoolLimitTests, RecentlyEvictedListDoesNotContainAfterExpiry)
TEST(MempoolLimitTests, RecentlyEvictedDropOneAtATime)
{
SetMockTime(1);
RecentlyEvictedList recentlyEvicted(3, 2);
FixedClock clock(std::chrono::seconds(1));
RecentlyEvictedList recentlyEvicted(&clock, 3, 2);
recentlyEvicted.add(TX_ID1);
SetMockTime(2);
clock.Set(std::chrono::seconds(2));
recentlyEvicted.add(TX_ID2);
SetMockTime(3);
clock.Set(std::chrono::seconds(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);
clock.Set(std::chrono::seconds(4));
EXPECT_FALSE(recentlyEvicted.contains(TX_ID1));
EXPECT_TRUE(recentlyEvicted.contains(TX_ID2));
EXPECT_TRUE(recentlyEvicted.contains(TX_ID3));
SetMockTime(5);
clock.Set(std::chrono::seconds(5));
EXPECT_FALSE(recentlyEvicted.contains(TX_ID1));
EXPECT_FALSE(recentlyEvicted.contains(TX_ID2));
EXPECT_TRUE(recentlyEvicted.contains(TX_ID3));
SetMockTime(6);
clock.Set(std::chrono::seconds(6));
EXPECT_FALSE(recentlyEvicted.contains(TX_ID1));
EXPECT_FALSE(recentlyEvicted.contains(TX_ID2));
EXPECT_FALSE(recentlyEvicted.contains(TX_ID3));

View File

@ -4,10 +4,12 @@
#include "util/test.h"
#include "util/time.h"
#include <chrono>
TEST(Metrics, AtomicTimer) {
FixedClock::SetGlobal();
AtomicTimer t;
SetMockTime(100);
FixedClock::Instance()->Set(std::chrono::seconds(100));
EXPECT_FALSE(t.running());
@ -36,13 +38,13 @@ TEST(Metrics, AtomicTimer) {
c.increment();
EXPECT_EQ(0, t.rate(c));
SetMockTime(101);
FixedClock::Instance()->Set(std::chrono::seconds(101));
EXPECT_EQ(1, t.rate(c));
c.decrement();
EXPECT_EQ(0, t.rate(c));
SetMockTime(102);
FixedClock::Instance()->Set(std::chrono::seconds(102));
EXPECT_EQ(0, t.rate(c));
c.increment();
@ -51,17 +53,20 @@ 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();
FixedClock::Instance()->Set(std::chrono::seconds(100));
miningTimer.start();
// No time has passed
EXPECT_EQ(0, GetLocalSolPS());
// Increment time
SetMockTime(101);
FixedClock::Instance()->Set(std::chrono::seconds(101));
EXPECT_EQ(0, GetLocalSolPS());
// Increment solutions
@ -69,7 +74,7 @@ TEST(Metrics, GetLocalSolPS) {
EXPECT_EQ(1, GetLocalSolPS());
// Increment time
SetMockTime(102);
FixedClock::Instance()->Set(std::chrono::seconds(102));
EXPECT_EQ(0.5, GetLocalSolPS());
// Increment solutions
@ -82,7 +87,7 @@ TEST(Metrics, GetLocalSolPS) {
EXPECT_EQ(1.5, GetLocalSolPS());
// Increment time
SetMockTime(103);
FixedClock::Instance()->Set(std::chrono::seconds(103));
EXPECT_EQ(1.5, GetLocalSolPS());
// Start timing again
@ -90,7 +95,7 @@ TEST(Metrics, GetLocalSolPS) {
EXPECT_EQ(1.5, GetLocalSolPS());
// Increment time
SetMockTime(104);
FixedClock::Instance()->Set(std::chrono::seconds(104));
EXPECT_EQ(1, GetLocalSolPS());
miningTimer.stop();
@ -98,20 +103,24 @@ TEST(Metrics, GetLocalSolPS) {
solutionTargetChecks.decrement();
solutionTargetChecks.decrement();
solutionTargetChecks.decrement();
SystemClock::SetGlobal();
}
TEST(Metrics, EstimateNetHeight) {
FixedClock::SetGlobal();
auto params = RegtestActivateBlossom(false, 200).GetConsensus();
int64_t blockTimes[400];
for (int i = 0; i < 400; i++) {
blockTimes[i] = i ? blockTimes[i - 1] + params.PoWTargetSpacing(i) : 0;
}
SetMockTime(blockTimes[399]);
FixedClock::Instance()->Set(std::chrono::seconds(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);
}
RegtestDeactivateBlossom();
SystemClock::SetGlobal();
}
TEST(Metrics, NextUpgrade) {

View File

@ -46,6 +46,7 @@
#include "wallet/walletdb.h"
#endif
#include "warnings.h"
#include <chrono>
#include <stdint.h>
#include <stdio.h>
@ -1244,8 +1245,21 @@ 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);
// a mocktime of 0 (the default) selects the system clock.
int64_t nMockTime = GetArg("-mocktime", 0);
int64_t nOffsetTime = GetArg("-clockoffset", 0);
if (nMockTime != 0 && nOffsetTime != 0) {
return InitError(_("-mocktime and -clockoffset cannot be used together"));
} else if (nMockTime != 0) {
FixedClock::SetGlobal();
FixedClock::Instance()->Set(std::chrono::seconds(nMockTime));
} else if (nOffsetTime != 0) {
// Option to start a node with the system clock offset by a constant
// value throughout the life of the node (used for regression testing):
OffsetClock::SetGlobal();
OffsetClock::Instance()->Set(std::chrono::seconds(nOffsetTime));
}
if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
nLocalServices |= NODE_BLOOM;

View File

@ -19,7 +19,7 @@ void RecentlyEvictedList::pruneList()
if (txIdSet.empty()) {
return;
}
int64_t now = GetTime();
int64_t now = clock->GetTime();
while (txIdsAndTimes.size() > 0 && now - txIdsAndTimes.front().second > timeToKeep) {
txIdSet.erase(txIdsAndTimes.front().first);
txIdsAndTimes.pop_front();
@ -33,7 +33,7 @@ void RecentlyEvictedList::add(const uint256& txId)
txIdSet.erase(txIdsAndTimes.front().first);
txIdsAndTimes.pop_front();
}
txIdsAndTimes.push_back(std::make_pair(txId, GetTime()));
txIdsAndTimes.push_back(std::make_pair(txId, clock->GetTime()));
txIdSet.insert(txId);
}

View File

@ -14,6 +14,7 @@
#include "primitives/transaction.h"
#include "policy/fees.h"
#include "uint256.h"
#include "util/time.h"
const size_t DEFAULT_MEMPOOL_TOTAL_COST_LIMIT = 80000000;
const int64_t DEFAULT_MEMPOOL_EVICTION_MEMORY_MINUTES = 60;
@ -27,6 +28,8 @@ const uint64_t LOW_FEE_PENALTY = 16000;
// in order to prevent them from being re-accepted for a given amount of time.
class RecentlyEvictedList
{
const CClock* const clock;
const size_t capacity;
const int64_t timeToKeep;
@ -39,11 +42,13 @@ class RecentlyEvictedList
void pruneList();
public:
RecentlyEvictedList(size_t capacity_, int64_t timeToKeep_) : capacity(capacity_), timeToKeep(timeToKeep_)
RecentlyEvictedList(const CClock* clock_, size_t capacity_, int64_t timeToKeep_) :
clock(clock_), capacity(capacity_), timeToKeep(timeToKeep_)
{
assert(capacity <= EVICTION_MEMORY_ENTRIES);
}
RecentlyEvictedList(int64_t timeToKeep_) : RecentlyEvictedList(EVICTION_MEMORY_ENTRIES, timeToKeep_) {}
RecentlyEvictedList(const CClock* clock_, int64_t timeToKeep_) :
RecentlyEvictedList(clock_, EVICTION_MEMORY_ENTRIES, timeToKeep_) {}
void add(const uint256& txId);
bool contains(const uint256& txId);

View File

@ -497,14 +497,18 @@ UniValue setmocktime(const UniValue& params, bool fHelp)
if (fHelp || params.size() != 1)
throw runtime_error(
"setmocktime timestamp\n"
"\nSet the local time to given timestamp (-regtest only)\n"
"\nSet the local time to given timestamp (-regtest only).\n"
"The node must be started with `-mocktime` in order to use this API.\n"
"\nArguments:\n"
"1. timestamp (integer, required) Unix seconds-since-epoch timestamp\n"
" Pass 0 to go back to using the system time."
);
if (!Params().MineBlocksOnDemand())
throw runtime_error("setmocktime for regression testing (-regtest mode) only");
throw runtime_error("setmocktime: for regression testing (-regtest mode) only");
if (GetNodeClock() != FixedClock::Instance())
throw runtime_error("setmocktime: the node must be started with `-mocktime` in order to use this API");
// cs_vNodes is locked and node send/receive times are updated
// atomically with the time change to prevent peers from being
@ -513,7 +517,9 @@ 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());
std::chrono::seconds nMockTime(params[0].get_int64());
FixedClock::Instance()->Set(nMockTime);
uint64_t t = GetTime();
for (CNode* pnode : vNodes) {

View File

@ -93,10 +93,12 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
BOOST_AUTO_TEST_CASE(DoS_bantime)
{
FixedClock::SetGlobal();
const Consensus::Params& params = Params().GetConsensus();
CNode::ClearBanned();
int64_t nStartTime = GetTime();
SetMockTime(nStartTime); // Overrides future calls to GetTime()
std::chrono::seconds nStartTime(GetTime());
FixedClock::Instance()->Set(nStartTime); // Overrides future calls to GetTime()
CAddress addr(ip(0xa0b0c001));
CNode dummyNode(INVALID_SOCKET, addr, "", true);
@ -106,11 +108,13 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
SendMessages(params, &dummyNode);
BOOST_CHECK(CNode::IsBanned(addr));
SetMockTime(nStartTime+60*60);
FixedClock::Instance()->Set(nStartTime + std::chrono::seconds(60*60));
BOOST_CHECK(CNode::IsBanned(addr));
SetMockTime(nStartTime+60*60*24+1);
FixedClock::Instance()->Set(nStartTime + std::chrono::seconds(60*60*24+1));
BOOST_CHECK(!CNode::IsBanned(addr));
SystemClock::SetGlobal();
}
CTransaction RandomOrphan()

View File

@ -289,7 +289,8 @@ BOOST_FIXTURE_TEST_SUITE(Alert_tests, ReadAlerts)
BOOST_AUTO_TEST_CASE(AlertApplies)
{
SetMockTime(11);
FixedClock::SetGlobal();
FixedClock::Instance()->Set(std::chrono::seconds(11));
const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
for (const CAlert& alert : alerts)
@ -342,13 +343,14 @@ 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();
FixedClock::Instance()->Set(std::chrono::seconds(11));
const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
fs::path temp = fs::temp_directory_path() /
@ -382,13 +384,14 @@ BOOST_AUTO_TEST_CASE(AlertNotify)
#endif
fs::remove(temp);
SetMockTime(0);
SystemClock::SetGlobal();
mapAlerts.clear();
}
BOOST_AUTO_TEST_CASE(AlertDisablesRPC)
{
SetMockTime(11);
FixedClock::SetGlobal();
FixedClock::Instance()->Set(std::chrono::seconds(11));
const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
// Command should work before alerts
@ -404,7 +407,7 @@ BOOST_AUTO_TEST_CASE(AlertDisablesRPC)
BOOST_CHECK_EQUAL(alerts[8].strRPCError, "");
BOOST_CHECK_EQUAL(GetWarnings("rpc").first, "");
SetMockTime(0);
SystemClock::SetGlobal();
mapAlerts.clear();
}

View File

@ -47,8 +47,11 @@ BOOST_AUTO_TEST_CASE(May15)
// idea, so this test is only run if you manually download
// 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();
// Test as if the time is exactly 2013-05-15 00:00:00Z
int64_t tMay15 = 1368576000;
FixedClock::Instance()->Set(std::chrono::seconds(tMay15));
CBlock forkingBlock;
if (read_block("Mar12Fork.dat", forkingBlock))
@ -61,7 +64,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()

View File

@ -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;
}
@ -407,8 +407,11 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
delete pblocktemplate;
chainActive.Tip()->nHeight = nHeight;
// Change to the fixed clock.
FixedClock::SetGlobal();
// non-final txs in mempool
SetMockTime(chainActive.Tip()->GetMedianTimePast()+1);
FixedClock::Instance()->Set(std::chrono::seconds(chainActive.Tip()->GetMedianTimePast()+1));
// height locked
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
@ -443,7 +446,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::Instance()->Set(std::chrono::seconds(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.
@ -454,8 +457,9 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 2);
delete pblocktemplate;
// Restore the original system state
chainActive.Tip()->nHeight--;
SetMockTime(0);
SystemClock::SetGlobal();
mempool.clear();
for (CTransaction *tx : txFirst)

View File

@ -938,7 +938,7 @@ void CTxMemPool::SetMempoolCostLimit(int64_t totalCostLimit, int64_t evictionMem
LogPrint("mempool", "Setting mempool cost limit: (limit=%d, time=%d)\n", totalCostLimit, evictionMemorySeconds);
delete recentlyEvicted;
delete weightedTxTree;
recentlyEvicted = new RecentlyEvictedList(evictionMemorySeconds);
recentlyEvicted = new RecentlyEvictedList(GetNodeClock(), evictionMemorySeconds);
weightedTxTree = new WeightedTxTree(totalCostLimit);
}

View File

@ -18,6 +18,7 @@
#include "random.h"
#include "addressindex.h"
#include "spentindex.h"
#include "util/time.h"
#undef foreach
#include "boost/multi_index_container.hpp"
@ -209,7 +210,7 @@ private:
std::map<uint256, const CTransaction*> mapSproutNullifiers;
std::map<uint256, const CTransaction*> mapSaplingNullifiers;
std::map<uint256, const CTransaction*> mapOrchardNullifiers;
RecentlyEvictedList* recentlyEvicted = new RecentlyEvictedList(DEFAULT_MEMPOOL_EVICTION_MEMORY_MINUTES * 60);
RecentlyEvictedList* recentlyEvicted = new RecentlyEvictedList(GetNodeClock(), DEFAULT_MEMPOOL_EVICTION_MEMORY_MINUTES * 60);
WeightedTxTree* weightedTxTree = new WeightedTxTree(DEFAULT_MEMPOOL_TOTAL_COST_LIMIT);
void checkNullifiers(ShieldedType type) const;

View File

@ -9,20 +9,105 @@
#endif
#include "util/time.h"
#include "sync.h"
#include <chrono>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread.hpp>
using namespace std;
RecursiveMutex cs_clock;
static CClock* zcashdClock = SystemClock::Instance();
static int64_t nMockTime = 0; //!< For unit testing
const CClock* GetNodeClock() {
return zcashdClock;
}
int64_t GetTime()
{
if (nMockTime) return nMockTime;
int64_t GetTime() {
return zcashdClock->GetTime();
}
return time(NULL);
int64_t GetTimeMillis() {
return zcashdClock->GetTimeMillis();
}
int64_t GetTimeMicros() {
return zcashdClock->GetTimeMicros();
}
void SystemClock::SetGlobal() {
zcashdClock = SystemClock::Instance();
}
int64_t SystemClock::GetTime() const {
return std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch()).count();
}
int64_t SystemClock::GetTimeMillis() const {
return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count();
}
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() {
zcashdClock = FixedClock::Instance();
}
void FixedClock::Set(std::chrono::seconds fixedSeconds) {
LOCK(cs_clock);
this->fixedSeconds = fixedSeconds;
}
int64_t FixedClock::GetTime() const {
LOCK(cs_clock);
return fixedSeconds.count();
}
int64_t FixedClock::GetTimeMillis() const {
LOCK(cs_clock);
return std::chrono::duration_cast<std::chrono::milliseconds>(fixedSeconds).count();
}
int64_t FixedClock::GetTimeMicros() const {
LOCK(cs_clock);
return std::chrono::duration_cast<std::chrono::microseconds>(fixedSeconds).count();
}
void OffsetClock::SetGlobal() {
zcashdClock = OffsetClock::Instance();
}
void OffsetClock::Set(std::chrono::seconds offsetSeconds) {
LOCK(cs_clock);
this->offsetSeconds = offsetSeconds;
}
int64_t OffsetClock::GetTime() const {
LOCK(cs_clock);
return std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch()
+ offsetSeconds
).count();
}
int64_t OffsetClock::GetTimeMillis() const {
LOCK(cs_clock);
return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()
+ offsetSeconds
).count();
}
int64_t OffsetClock::GetTimeMicros() const {
LOCK(cs_clock);
return std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::system_clock::now().time_since_epoch()
+ offsetSeconds
).count();
}
bool ChronoSanityCheck()
@ -68,24 +153,6 @@ bool ChronoSanityCheck()
return true;
}
void SetMockTime(int64_t nMockTimeIn)
{
nMockTime = nMockTimeIn;
}
int64_t GetTimeMillis()
{
return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count();
}
int64_t GetTimeMicros()
{
return std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::system_clock::now().time_since_epoch()).count();
}
void MilliSleep(int64_t n)
{
// This is defined to be an interruption point.

View File

@ -10,10 +10,93 @@
#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. This must only be
* called by `init()`, or in tests.
*/
static void SetGlobal();
int64_t GetTime() const;
int64_t GetTimeMillis() const;
int64_t GetTimeMicros() const;
};
class FixedClock: public CClock {
private:
std::chrono::seconds fixedSeconds;
public:
FixedClock(std::chrono::seconds fixedSeconds): fixedSeconds(fixedSeconds) {}
static FixedClock* Instance() {
static FixedClock instance(std::chrono::seconds(0));
return &instance;
}
/**
* Sets the clock used by zcashd to a fixed clock. This must only be used
* by `init()`, or in tests.
*/
static void SetGlobal();
void Set(std::chrono::seconds fixedSeconds);
int64_t GetTime() const;
int64_t GetTimeMillis() const;
int64_t GetTimeMicros() const;
};
class OffsetClock: public CClock {
private:
std::chrono::seconds offsetSeconds;
public:
OffsetClock(std::chrono::seconds offsetSeconds): offsetSeconds(offsetSeconds) {}
static OffsetClock* Instance() {
static OffsetClock instance(std::chrono::seconds(0));
return &instance;
}
/**
* Sets the clock used by zcashd to a clock that returns the current system
* time modified by the specified offset. This must only be called by
* `init()`, or in tests.
*/
static void SetGlobal();
void Set(std::chrono::seconds offsetSeconds);
int64_t GetTime() const;
int64_t GetTimeMillis() const;
int64_t GetTimeMicros() const;
};
const CClock* GetNodeClock();
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);