Skip to content

Commit 40e554c

Browse files
backport: adapt Dash time users to NodeClock
Convert nearby CoinJoin, governance, spork, LLMQ, RPC, and test code to chrono time points and durations. Preserve serialized, signed, hashed, and RPC-facing timestamps as integer Unix seconds with explicit conversions at those boundaries.
1 parent ccb8bce commit 40e554c

20 files changed

Lines changed: 266 additions & 133 deletions

src/Makefile.test.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ BITCOIN_TESTS =\
186186
test/sigopcount_tests.cpp \
187187
test/skiplist_tests.cpp \
188188
test/sock_tests.cpp \
189+
test/spork_tests.cpp \
189190
test/streams_tests.cpp \
190191
test/subsidy_tests.cpp \
191192
test/sync_tests.cpp \

src/coinjoin/coinjoin.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,16 @@ bool CCoinJoinQueue::CheckSignature(const CBLSPublicKey& blsPubKey) const
5555
return true;
5656
}
5757

58-
bool CCoinJoinQueue::IsTimeOutOfBounds(int64_t current_time) const
58+
bool CCoinJoinQueue::IsTimeOutOfBounds(NodeSeconds current_time) const
5959
{
60-
if (current_time < 0 || nTime < 0) return true;
61-
return current_time - nTime > COINJOIN_QUEUE_TIMEOUT ||
62-
nTime - current_time > COINJOIN_QUEUE_TIMEOUT;
60+
const auto queue_time{Time()};
61+
if (current_time < NodeSeconds{} || queue_time < NodeSeconds{}) return true;
62+
return std::chrono::abs(current_time - queue_time) > std::chrono::seconds{COINJOIN_QUEUE_TIMEOUT};
63+
}
64+
65+
bool CCoinJoinQueue::IsTimeOutOfBounds() const
66+
{
67+
return IsTimeOutOfBounds(std::chrono::time_point_cast<std::chrono::seconds>(GetAdjustedTime()));
6368
}
6469

6570
[[nodiscard]] std::string CCoinJoinQueue::ToString() const

src/coinjoin/coinjoin.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -193,15 +193,17 @@ class CCoinJoinQueue
193193

194194
CCoinJoinQueue() = default;
195195

196-
CCoinJoinQueue(int nDenom, const COutPoint& outpoint, const uint256& proTxHash, int64_t nTime, bool fReady) :
196+
CCoinJoinQueue(int nDenom, const COutPoint& outpoint, const uint256& proTxHash, NodeClock::time_point time, bool fReady) :
197197
nDenom(nDenom),
198198
masternodeOutpoint(outpoint),
199199
m_protxHash(proTxHash),
200-
nTime(nTime),
200+
nTime(TicksSinceEpoch<std::chrono::seconds>(time)),
201201
fReady(fReady)
202202
{
203203
}
204204

205+
NodeSeconds Time() const { return NodeSeconds{std::chrono::seconds{nTime}}; }
206+
205207
SERIALIZE_METHODS(CCoinJoinQueue, obj)
206208
{
207209
READWRITE(obj.nDenom, obj.m_protxHash, obj.nTime, obj.fReady);
@@ -217,7 +219,8 @@ class CCoinJoinQueue
217219
[[nodiscard]] bool CheckSignature(const CBLSPublicKey& blsPubKey) const;
218220

219221
/// Check if a queue is too old or too far into the future
220-
[[nodiscard]] bool IsTimeOutOfBounds(int64_t current_time = GetAdjustedTime()) const;
222+
[[nodiscard]] bool IsTimeOutOfBounds(NodeSeconds current_time) const;
223+
[[nodiscard]] bool IsTimeOutOfBounds() const;
221224

222225
[[nodiscard]] std::string ToString() const;
223226

@@ -247,11 +250,11 @@ class CCoinJoinBroadcastTx
247250
{
248251
}
249252

250-
CCoinJoinBroadcastTx(CTransactionRef _tx, const COutPoint& _outpoint, const uint256& proTxHash, int64_t _sigTime) :
253+
CCoinJoinBroadcastTx(CTransactionRef _tx, const COutPoint& _outpoint, const uint256& proTxHash, NodeClock::time_point time) :
251254
tx(std::move(_tx)),
252255
masternodeOutpoint(_outpoint),
253256
m_protxHash(proTxHash),
254-
sigTime(_sigTime)
257+
sigTime(TicksSinceEpoch<std::chrono::seconds>(time))
255258
{
256259
}
257260

src/governance/governance.cpp

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -278,25 +278,25 @@ void CGovernanceManager::CheckOrphanVotes(CGovernanceObject& govobj)
278278
AssertLockNotHeld(cs_relay);
279279

280280
uint256 nHash = govobj.GetHash();
281-
std::vector<vote_time_pair_t> vecVotePairs;
282-
cmmapOrphanVotes.GetAll(nHash, vecVotePairs);
281+
std::vector<governance::OrphanVote> orphan_votes;
282+
cmmapOrphanVotes.GetAll(nHash, orphan_votes);
283283

284284
ScopedLockBool guard(cs_store, fRateChecksEnabled, false);
285285

286-
int64_t nNow = GetAdjustedTime();
286+
const auto now{std::chrono::time_point_cast<std::chrono::seconds>(GetAdjustedTime())};
287287
const auto tip_mn_list = m_dmnman.GetListAtChainTip();
288-
for (const auto& pairVote : vecVotePairs) {
289-
const auto& [vote, time] = pairVote;
288+
for (const auto& orphan_vote : orphan_votes) {
289+
const auto& vote = orphan_vote.vote;
290290
bool fRemove = false;
291291
CGovernanceException e;
292-
if (time < nNow) {
292+
if (orphan_vote.expiration < now) {
293293
fRemove = true;
294294
} else if (govobj.ProcessVote(m_mn_metaman, fRateChecksEnabled, tip_mn_list, vote, e)) {
295295
RelayVote(vote);
296296
fRemove = true;
297297
}
298298
if (fRemove) {
299-
cmmapOrphanVotes.Erase(nHash, pairVote);
299+
cmmapOrphanVotes.Erase(nHash, orphan_vote);
300300
}
301301
}
302302
}
@@ -733,21 +733,21 @@ bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, bo
733733
}
734734

735735
const COutPoint& masternodeOutpoint = govobj.GetMasternodeOutpoint();
736-
int64_t nTimestamp = govobj.GetCreationTime();
737-
int64_t nNow = GetAdjustedTime();
738-
int64_t nSuperblockCycleSeconds = Params().GetConsensus().nSuperblockCycle * Params().GetConsensus().nPowTargetSpacing;
736+
const auto timestamp{govobj.CreationTime()};
737+
const auto now{std::chrono::time_point_cast<std::chrono::seconds>(GetAdjustedTime())};
738+
const auto superblock_cycle{Params().GetConsensus().nSuperblockCycle * Params().GetConsensus().PowTargetSpacing()};
739739

740740
std::string strHash = govobj.GetHash().ToString();
741741

742-
if (nTimestamp < nNow - 2 * nSuperblockCycleSeconds) {
742+
if (timestamp < now - 2 * superblock_cycle) {
743743
LogPrint(BCLog::GOBJECT, "CGovernanceManager::MasternodeRateCheck -- object %s rejected due to too old timestamp, masternode = %s, timestamp = %d, current time = %d\n",
744-
strHash, masternodeOutpoint.ToStringShort(), nTimestamp, nNow);
744+
strHash, masternodeOutpoint.ToStringShort(), govobj.GetCreationTime(), TicksSinceEpoch<std::chrono::seconds>(now));
745745
return false;
746746
}
747747

748-
if (nTimestamp > nNow + count_seconds(MAX_TIME_FUTURE_DEVIATION)) {
748+
if (timestamp > now + MAX_TIME_FUTURE_DEVIATION) {
749749
LogPrint(BCLog::GOBJECT, "CGovernanceManager::MasternodeRateCheck -- object %s rejected due to too new (future) timestamp, masternode = %s, timestamp = %d, current time = %d\n",
750-
strHash, masternodeOutpoint.ToStringShort(), nTimestamp, nNow);
750+
strHash, masternodeOutpoint.ToStringShort(), govobj.GetCreationTime(), TicksSinceEpoch<std::chrono::seconds>(now));
751751
return false;
752752
}
753753

@@ -760,20 +760,20 @@ bool CGovernanceManager::MasternodeRateCheck(const CGovernanceObject& govobj, bo
760760
}
761761

762762
// Allow 1 trigger per mn per cycle, with a small fudge factor
763-
double dMaxRate = 2 * 1.1 / double(nSuperblockCycleSeconds);
763+
double dMaxRate = 2 * 1.1 / static_cast<double>(count_seconds(superblock_cycle));
764764

765765
// Temporary copy to check rate after new timestamp is added
766766
CRateCheckBuffer buffer = it->second.triggerBuffer;
767767

768-
buffer.AddTimestamp(nTimestamp);
768+
buffer.AddTimestamp(govobj.GetCreationTime());
769769
double dRate = buffer.GetRate();
770770

771771
if (dRate < dMaxRate) {
772772
return true;
773773
}
774774

775775
LogPrint(BCLog::GOBJECT, "CGovernanceManager::MasternodeRateCheck -- Rate too high: object hash = %s, masternode = %s, object timestamp = %d, rate = %f, max rate = %f\n",
776-
strHash, masternodeOutpoint.ToStringShort(), nTimestamp, dRate, dMaxRate);
776+
strHash, masternodeOutpoint.ToStringShort(), govobj.GetCreationTime(), dRate, dMaxRate);
777777

778778
if (fUpdateFailStatus) {
779779
it->second.fStatusOK = false;
@@ -823,8 +823,7 @@ bool CGovernanceManager::ProcessVote(const CGovernanceVote& vote, CGovernanceExc
823823
std::string msg{strprintf("CGovernanceManager::%s -- Unknown parent object %s, MN outpoint = %s", __func__,
824824
nHashGovobj.ToString(), vote.GetMasternodeOutpoint().ToStringShort())};
825825
exception = CGovernanceException(msg, GOVERNANCE_EXCEPTION_WARNING);
826-
if (cmmapOrphanVotes.Insert(nHashGovobj, vote_time_pair_t(vote, count_seconds(GetTime<std::chrono::seconds>() +
827-
GOVERNANCE_ORPHAN_EXPIRATION_TIME)))) {
826+
if (cmmapOrphanVotes.Insert(nHashGovobj, governance::OrphanVote{vote, Now<NodeSeconds>() + GOVERNANCE_ORPHAN_EXPIRATION_TIME})) {
828827
hashToRequest = nHashGovobj; // Caller should request this object
829828
}
830829
LogPrint(BCLog::GOBJECT, "%s\n", msg);
@@ -883,20 +882,19 @@ void CGovernanceManager::CheckPostponedObjects()
883882

884883

885884
// Perform additional relays for triggers
886-
int64_t nNow = GetAdjustedTime();
887-
int64_t nSuperblockCycleSeconds = Params().GetConsensus().nSuperblockCycle * Params().GetConsensus().nPowTargetSpacing;
885+
const auto now{std::chrono::time_point_cast<std::chrono::seconds>(GetAdjustedTime())};
886+
const auto superblock_cycle{Params().GetConsensus().nSuperblockCycle * Params().GetConsensus().PowTargetSpacing()};
888887

889888
for (auto it = setAdditionalRelayObjects.begin(); it != setAdditionalRelayObjects.end();) {
890889
auto itObject = mapObjects.find(*it);
891890
if (itObject != mapObjects.end()) {
892891
const auto& govobj = *Assert(itObject->second);
893892

894-
int64_t nTimestamp = govobj.GetCreationTime();
893+
const auto timestamp{govobj.CreationTime()};
895894

896-
bool fValid = (nTimestamp <= nNow + count_seconds(MAX_TIME_FUTURE_DEVIATION)) &&
897-
(nTimestamp >= nNow - 2 * nSuperblockCycleSeconds);
898-
bool fReady = (nTimestamp <=
899-
nNow + count_seconds(MAX_TIME_FUTURE_DEVIATION) - count_seconds(RELIABLE_PROPAGATION_TIME));
895+
const bool fValid{timestamp <= now + MAX_TIME_FUTURE_DEVIATION &&
896+
timestamp >= now - 2 * superblock_cycle};
897+
const bool fReady{timestamp <= now + MAX_TIME_FUTURE_DEVIATION - RELIABLE_PROPAGATION_TIME};
900898

901899
if (fValid) {
902900
if (fReady) {
@@ -1092,15 +1090,14 @@ std::vector<uint256> CGovernanceManager::GetOrphanVoteObjectHashes()
10921090
{
10931091
LOCK(cs_store);
10941092

1095-
int64_t nNow = GetTime<std::chrono::seconds>().count();
1093+
const auto now{Now<NodeSeconds>()};
10961094

10971095
// Clean up expired orphan votes
10981096
const vote_cmm_t::list_t& items = cmmapOrphanVotes.GetItemList();
10991097
for (auto it = items.begin(); it != items.end();) {
11001098
auto prevIt = it;
11011099
++it;
1102-
const auto& [_, time] = prevIt->value;
1103-
if (time < nNow) {
1100+
if (prevIt->value.expiration < now) {
11041101
cmmapOrphanVotes.Erase(prevIt->key, prevIt->value);
11051102
}
11061103
}

src/governance/governance.h

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77

88
#include <cachemap.h>
99
#include <cachemultimap.h>
10+
#include <governance/vote.h>
1011
#include <primitives/transaction.h>
1112
#include <sync.h>
13+
#include <util/time.h>
1214

1315
#include <chrono>
1416
#include <limits>
@@ -29,7 +31,6 @@ template<typename T>
2931
class CFlatDB;
3032
class CGovernanceException;
3133
class CGovernanceObject;
32-
class CGovernanceVote;
3334
class CInv;
3435
class CMasternodeMetaMan;
3536
class CMasternodeSync;
@@ -41,9 +42,26 @@ namespace governance {
4142
class SuperblockManager;
4243
// How long a requested governance inv hash remains in the request cache.
4344
inline constexpr std::chrono::seconds RELIABLE_PROPAGATION_TIME{60};
44-
} // namespace governance
4545

46-
using vote_time_pair_t = std::pair<CGovernanceVote, int64_t>;
46+
struct OrphanVote {
47+
CGovernanceVote vote;
48+
NodeSeconds expiration;
49+
50+
OrphanVote() = default;
51+
OrphanVote(const CGovernanceVote& vote, NodeSeconds expiration) : vote(vote), expiration(expiration) {}
52+
53+
SERIALIZE_METHODS(OrphanVote, obj)
54+
{
55+
// Preserve the historical integer Unix-seconds representation on disk.
56+
READWRITE(obj.vote, Using<ChronoFormatter<int64_t>>(obj.expiration));
57+
}
58+
};
59+
60+
inline bool operator<(const OrphanVote& lhs, const OrphanVote& rhs)
61+
{
62+
return lhs.vote < rhs.vote;
63+
}
64+
} // namespace governance
4765

4866
static constexpr int RATE_BUFFER_SIZE = 5;
4967
static constexpr bool DEFAULT_GOVERNANCE_ENABLE{true};
@@ -160,7 +178,7 @@ class GovernanceStore
160178
};
161179

162180
using txout_m_t = std::map<COutPoint, last_object_rec>;
163-
using vote_cmm_t = CacheMultiMap<uint256, vote_time_pair_t>;
181+
using vote_cmm_t = CacheMultiMap<uint256, governance::OrphanVote>;
164182

165183
protected:
166184
static constexpr int MAX_CACHE_SIZE = 1000000;

src/governance/object.cpp

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ bool ValidateStartEndEpoch(const UniValue& objJSON, bool fCheckExpiration, std::
144144
return false;
145145
}
146146

147-
if (fCheckExpiration && nEndEpoch <= GetAdjustedTime()) {
147+
const auto now{std::chrono::time_point_cast<std::chrono::seconds>(GetAdjustedTime())};
148+
if (fCheckExpiration && NodeSeconds{std::chrono::seconds{nEndEpoch}} <= now) {
148149
strErrorMessages += "expired;";
149150
return false;
150151
}
@@ -346,6 +347,12 @@ CGovernanceObject::CGovernanceObject(const uint256& nHashParentIn, int nRevision
346347
LoadData();
347348
}
348349

350+
CGovernanceObject::CGovernanceObject(const uint256& nHashParentIn, int nRevisionIn, NodeClock::time_point time,
351+
const uint256& nCollateralHashIn, const std::string& strDataHexIn) :
352+
CGovernanceObject{nHashParentIn, nRevisionIn, TicksSinceEpoch<std::chrono::seconds>(time), nCollateralHashIn, strDataHexIn}
353+
{
354+
}
355+
349356
CGovernanceObject::CGovernanceObject(const CGovernanceObject& other) :
350357
cs(),
351358
m_obj{other.m_obj},
@@ -430,19 +437,19 @@ bool CGovernanceObject::ProcessVote(CMasternodeMetaMan& mn_metaman, bool fRateCh
430437
LogPrint(BCLog::GOBJECT, "%s\n", msg);
431438
}
432439

433-
int64_t nNow = GetAdjustedTime();
434-
int64_t nVoteTimeUpdate = voteInstanceRef.nTime;
440+
auto vote_time_update{voteInstanceRef.last_update};
435441
if (fRateChecksEnabled) {
436-
int64_t nTimeDelta = nNow - voteInstanceRef.nTime;
437-
if (nTimeDelta < GOVERNANCE_UPDATE_MIN) {
442+
const auto now{std::chrono::time_point_cast<std::chrono::seconds>(GetAdjustedTime())};
443+
if (voteInstanceRef.last_update > now - GOVERNANCE_UPDATE_MIN) {
438444
std::string msg{strprintf("CGovernanceObject::%s -- Masternode voting too often, MN outpoint = %s, "
439-
"governance object hash = %s, time delta = %d",
440-
__func__, vote.GetMasternodeOutpoint().ToStringShort(), GetHash().ToString(), nTimeDelta)};
445+
"governance object hash = %s, last update = %d, current time = %d",
446+
__func__, vote.GetMasternodeOutpoint().ToStringShort(), GetHash().ToString(),
447+
TicksSinceEpoch<std::chrono::seconds>(voteInstanceRef.last_update), TicksSinceEpoch<std::chrono::seconds>(now))};
441448
LogPrint(BCLog::GOBJECT, "%s\n", msg);
442449
exception = CGovernanceException(msg, GOVERNANCE_EXCEPTION_TEMPORARY_ERROR);
443450
return false;
444451
}
445-
nVoteTimeUpdate = nNow;
452+
vote_time_update = std::chrono::time_point_cast<std::chrono::seconds>(now);
446453
}
447454

448455
bool onlyVotingKeyAllowed = m_obj.type == GovernanceObject::PROPOSAL && vote.GetSignal() == VOTE_SIGNAL_FUNDING;
@@ -459,7 +466,7 @@ bool CGovernanceObject::ProcessVote(CMasternodeMetaMan& mn_metaman, bool fRateCh
459466

460467
mn_metaman.AddGovernanceVote(dmn->proTxHash, vote.GetParentHash());
461468

462-
voteInstanceRef = vote_instance_t(vote.GetOutcome(), nVoteTimeUpdate, vote.GetTimestamp());
469+
voteInstanceRef = vote_instance_t(vote.GetOutcome(), vote_time_update, vote.GetTimestamp());
463470
fileVotes.AddVote(vote);
464471
fDirtyCache = true;
465472
// SEND NOTIFICATION TO SCRIPT/ZMQ

src/governance/object.h

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <governance/vote.h>
1010
#include <governance/votedb.h>
1111
#include <sync.h>
12+
#include <util/time.h>
1213

1314
#include <span.h>
1415

@@ -87,7 +88,7 @@ static constexpr double GOVERNANCE_FILTER_FP_RATE = 0.001;
8788
static constexpr CAmount GOVERNANCE_PROPOSAL_FEE_TX = (1 * COIN);
8889
static constexpr int64_t GOVERNANCE_FEE_CONFIRMATIONS = 6;
8990
static constexpr int64_t GOVERNANCE_MIN_RELAY_FEE_CONFIRMATIONS = 1;
90-
static constexpr int64_t GOVERNANCE_UPDATE_MIN = 60 * 60;
91+
static constexpr std::chrono::hours GOVERNANCE_UPDATE_MIN{1};
9192

9293
// FOR SEEN MAP ARRAYS - GOVERNANCE OBJECTS AND VOTES
9394
enum class SeenObjectStatus {
@@ -97,21 +98,14 @@ enum class SeenObjectStatus {
9798
Unknown
9899
};
99100

100-
using vote_time_pair_t = std::pair<CGovernanceVote, int64_t>;
101-
102-
inline bool operator<(const vote_time_pair_t& p1, const vote_time_pair_t& p2)
103-
{
104-
return (p1.first < p2.first);
105-
}
106-
107101
struct vote_instance_t {
108102
vote_outcome_enum_t eOutcome;
109-
int64_t nTime;
103+
NodeSeconds last_update;
110104
int64_t nCreationTime;
111105

112-
explicit vote_instance_t(vote_outcome_enum_t eOutcomeIn = VOTE_OUTCOME_NONE, int64_t nTimeIn = 0, int64_t nCreationTimeIn = 0) :
106+
explicit vote_instance_t(vote_outcome_enum_t eOutcomeIn = VOTE_OUTCOME_NONE, NodeSeconds last_update_in = {}, int64_t nCreationTimeIn = 0) :
113107
eOutcome(eOutcomeIn),
114-
nTime(nTimeIn),
108+
last_update(last_update_in),
115109
nCreationTime(nCreationTimeIn)
116110
{
117111
}
@@ -120,7 +114,8 @@ struct vote_instance_t {
120114
{
121115
int nOutcome;
122116
SER_WRITE(obj, nOutcome = int(obj.eOutcome));
123-
READWRITE(nOutcome, obj.nTime, obj.nCreationTime);
117+
// Preserve the historical integer Unix-seconds representation on disk.
118+
READWRITE(nOutcome, Using<ChronoFormatter<int64_t>>(obj.last_update), obj.nCreationTime);
124119
SER_READ(obj, obj.eOutcome = vote_outcome_enum_t(nOutcome));
125120
}
126121
};
@@ -192,6 +187,7 @@ class CGovernanceObject
192187
public:
193188
CGovernanceObject();
194189
CGovernanceObject(const uint256& nHashParentIn, int nRevisionIn, int64_t nTime, const uint256& nCollateralHashIn, const std::string& strDataHexIn);
190+
CGovernanceObject(const uint256& nHashParentIn, int nRevisionIn, NodeClock::time_point time, const uint256& nCollateralHashIn, const std::string& strDataHexIn);
195191
CGovernanceObject(const CGovernanceObject& other);
196192
template <typename Stream>
197193
CGovernanceObject(deserialize_type, Stream& s) { s >> *this; }
@@ -207,6 +203,7 @@ class CGovernanceObject
207203
return WITH_LOCK(cs, return fExpired);
208204
}
209205
GovernanceObject GetObjectType() const { return m_obj.type; }
206+
NodeSeconds CreationTime() const { return NodeSeconds{std::chrono::seconds{m_obj.time}}; }
210207
int64_t GetCreationTime() const { return m_obj.time; }
211208
int64_t GetDeletionTime() const EXCLUSIVE_LOCKS_REQUIRED(!cs)
212209
{

0 commit comments

Comments
 (0)