Skip to content

Commit

Permalink
Introduce block time protocol V2 (15 second windows)
Browse files Browse the repository at this point in the history
- Port and adapt PIVX commits on time protocol V2 (PR dashpay#1002)
- Port PIVX commits on nTime offset warnings (PR dashpay#1138)
- Adjust chain parameters
- Add several copyright notices
  • Loading branch information
ckti committed Apr 3, 2022
1 parent 788ce99 commit 682c853
Show file tree
Hide file tree
Showing 19 changed files with 260 additions and 95 deletions.
32 changes: 32 additions & 0 deletions src/chain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,38 @@ unsigned int CBlockIndex::GetStakeEntropyBit() const
return ((UintToArith256(GetBlockHash()).GetLow64()) & 1);
}

int CBlockIndex::FutureBlockTimeDrift(const int nHeight, const Consensus::Params& params) const
{
if (params.IsTimeProtocolV2(nHeight))
// PoS (TimeV2): 14 seconds
return params.nTimeSlotLength - 1;

// PoS (TimeV1): 3 minutes
// PoW: 2 hours
return (nHeight >= params.nPosStartHeight) ? MAX_FUTURE_BLOCK_TIME_POS : MAX_FUTURE_BLOCK_TIME_POW;
}

int64_t CBlockIndex::MaxFutureBlockTime(int64_t nAdjustedTime, const Consensus::Params& params) const
{
return nAdjustedTime + FutureBlockTimeDrift(nHeight+1, params);
}

int64_t CBlockIndex::MinPastBlockTime(const Consensus::Params& params) const
{
// Time Protocol v1: pindexPrev->MedianTimePast + 1
if (!params.IsTimeProtocolV2(nHeight+1))
return GetMedianTimePast();

// on the transition from Time Protocol v1 to v2
// pindexPrev->nTime might be in the future (up to the allowed drift)
// so we allow the nBlockTimeProtocolV2 to be at most (180-14) seconds earlier than previous block
if (nHeight + 1 == params.nBlockTimeProtocolV2)
return GetBlockTime() - FutureBlockTimeDrift(nHeight, params) + FutureBlockTimeDrift(nHeight + 1, params);

// Time Protocol v2: pindexPrev->nTime
return GetBlockTime();
}

arith_uint256 GetBlockProof(const CBlockIndex& block)
{
arith_uint256 bnTarget;
Expand Down
17 changes: 14 additions & 3 deletions src/chain.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Copyright (c) 2011-2013 The PPCoin developers
// Copyright (c) 2013-2014 The NovaCoin Developers
// Copyright (c) 2014-2018 The BlackCoin Developers
// Copyright (c) 2015-2019 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

Expand All @@ -18,15 +22,16 @@
* Maximum amount of time that a block timestamp is allowed to exceed the
* current network-adjusted time before the block will be accepted.
*/
static const int64_t MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60;
static const int64_t MAX_FUTURE_BLOCK_TIME_POW = 2 * 60 * 60;
static const int64_t MAX_FUTURE_BLOCK_TIME_POS = 3 * 60;

/**
* Timestamp window used as a grace period by code that compares external
* timestamps (such as timestamps passed to RPCs, or wallet key creation times)
* to block timestamps. This should be set at least as high as
* MAX_FUTURE_BLOCK_TIME.
* MAX_FUTURE_BLOCK_TIME_POW.
*/
static const int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME;
static const int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME_POW;

class CBlockFileInfo
{
Expand Down Expand Up @@ -362,6 +367,12 @@ class CBlockIndex
return pbegin[(pend - pbegin)/2];
}

int FutureBlockTimeDrift(const int nHeight, const Consensus::Params& params) const;

int64_t MaxFutureBlockTime(int64_t nAdjustedTime, const Consensus::Params& params) const;

int64_t MinPastBlockTime(const Consensus::Params& params) const;

bool IsProofOfWork() const
{
return !(nFlags & BLOCK_PROOF_OF_STAKE);
Expand Down
37 changes: 29 additions & 8 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ class CMainParams : public CChainParams {
consensus.nGovernanceMinQuorum = 10;
consensus.nGovernanceFilterElements = 20000;
consensus.nMasternodeMinimumConfirmations = 15;
consensus.V16DeploymentHeight = std::numeric_limits<int64_t>::max();
consensus.BIP34Height = 1;
consensus.BIP34Hash = uint256S("000001364c4ed20f1b240810b5aa91fee23ae9b64b6e746b594b611cf6d8c87b");
consensus.BIP65Height = consensus.V16DeploymentHeight;
Expand All @@ -378,12 +379,17 @@ class CMainParams : public CChainParams {
// Wagerr specific parameters
// Proof of Stake parameters
consensus.nPosStartHeight = 201;
consensus.nPivxProtocolV2StartHeight = std::numeric_limits<int>::max();
consensus.nBlockTimeProtocolV2 = consensus.V16DeploymentHeight;
consensus.posLimit = uint256S("000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 24
consensus.posLimit_V2 = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 20
consensus.nTimeSlotLength = 15;
consensus.nPosTargetSpacing = 1 * 60; // 1 minute
consensus.nPosTargetTimespan = 40 * 60; // 40 minutes
consensus.nPosTargetTimespan_V2 = 2 * consensus.nTimeSlotLength * 60; // 30 minutes
consensus.nStakeMinDepth = 600;
consensus.nStakeMinAge = 60 * 60; // 1 hour
consensus.nBlockStakeModifierV1A = 1000;
consensus.nBlockStakeModifierV2 = std::numeric_limits<int>::max();
consensus.nBlockStakeModifierV2 = consensus.V16DeploymentHeight;
// ATP parameters
consensus.ATPStartHeight = std::numeric_limits<int64_t>::max();
consensus.WgrAddrPrefix = "wgr";
Expand Down Expand Up @@ -547,7 +553,7 @@ class CTestNetParams : public CChainParams {
consensus.nGovernanceMinQuorum = 1;
consensus.nGovernanceFilterElements = 500;
consensus.nMasternodeMinimumConfirmations = 1;
consensus.V16DeploymentHeight = 1600000;
consensus.V16DeploymentHeight = std::numeric_limits<int>::max();
consensus.BIP34Height = 1;
consensus.BIP34Hash = uint256S("0000065432f43b3efb23bd0f63fe33d00d02a5f36233fe1b982c08274d58ef12");
consensus.BIP65Height = consensus.V16DeploymentHeight;
Expand All @@ -566,10 +572,15 @@ class CTestNetParams : public CChainParams {
// Wagerr specific parameters
// Proof of Stake parameters
consensus.nPosStartHeight = 201;
consensus.nPivxProtocolV2StartHeight = std::numeric_limits<int>::max();
consensus.nBlockTimeProtocolV2 = consensus.V16DeploymentHeight;
consensus.posLimit = uint256S("000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 24
consensus.posLimit_V2 = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 20
consensus.nTimeSlotLength = 15;
consensus.nPosTargetSpacing = 1 * 60; // 1 minute
consensus.nPosTargetTimespan = 40 * 60; // 40 minutes
consensus.nPosTargetTimespan_V2 = 2 * consensus.nTimeSlotLength * 60; // 30 minutes
consensus.nStakeMinDepth = 100;
consensus.nStakeMinAge = 60 * 60; // 1 hour
consensus.nBlockStakeModifierV1A = 51197;
consensus.nBlockStakeModifierV2 = std::numeric_limits<int>::max();
// ATP parameters
Expand Down Expand Up @@ -737,12 +748,17 @@ class CDevNetParams : public CChainParams {
// Wagerr specific parameters
// Proof of Stake parameters
consensus.nPosStartHeight = 201;
consensus.nPivxProtocolV2StartHeight = 2000;
consensus.nBlockTimeProtocolV2 = consensus.V16DeploymentHeight;
consensus.posLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 1
consensus.posLimit_V2 = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 1
consensus.nTimeSlotLength = 15;
consensus.nPosTargetSpacing = 1 * 60; // 1 minute
consensus.nPosTargetTimespan = 40 * 60; // 40 minutes
consensus.nPosTargetTimespan_V2 = 2 * consensus.nTimeSlotLength * 60; // 30 minutes
consensus.nStakeMinDepth = 100;
consensus.nStakeMinAge = 60 * 60; // 1 hour
consensus.nBlockStakeModifierV1A = 1000;
consensus.nBlockStakeModifierV2 = consensus.nPivxProtocolV2StartHeight;
consensus.nBlockStakeModifierV2 = consensus.V16DeploymentHeight;
// ATP parameters
consensus.ATPStartHeight = std::numeric_limits<int64_t>::max();
consensus.WgrAddrPrefix = "wgrtest";
Expand Down Expand Up @@ -887,6 +903,7 @@ class CRegTestParams : public CChainParams {
consensus.nGovernanceMinQuorum = 1;
consensus.nGovernanceFilterElements = 100;
consensus.nMasternodeMinimumConfirmations = 1;
consensus.V16DeploymentHeight = 300;
consensus.BIP34Height = 100000000; // BIP34 has not activated on regtest (far in the future so block v1 are not rejected in tests)
consensus.BIP34Hash = uint256();
consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in rpc activation tests)
Expand All @@ -905,12 +922,16 @@ class CRegTestParams : public CChainParams {
// Wagerr specific parameters
// Proof of Stake parameters
consensus.nPosStartHeight = 201;
consensus.nPivxProtocolV2StartHeight = 2000;
consensus.nBlockTimeProtocolV2 = consensus.V16DeploymentHeight;
consensus.posLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 1
consensus.posLimit_V2 = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 1
consensus.nTimeSlotLength = 15;
consensus.nPosTargetSpacing = 1 * 60; // 1 minute
consensus.nPosTargetTimespan = 40 * 60; // 40 minutes
consensus.nPosTargetTimespan_V2 = 2 * consensus.nTimeSlotLength * 60; // 30 minutes
consensus.nStakeMinDepth = 100;
consensus.nBlockStakeModifierV1A = 1000;
consensus.nBlockStakeModifierV2 = consensus.nPivxProtocolV2StartHeight;
consensus.nBlockStakeModifierV2 = consensus.V16DeploymentHeight;
// ATP parameters
consensus.ATPStartHeight = std::numeric_limits<int64_t>::max();
consensus.WgrAddrPrefix = "wgrreg";
Expand Down
10 changes: 9 additions & 1 deletion src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,13 +190,21 @@ struct Params {

/** Proof of stake parameters */
int64_t nPosStartHeight;
int64_t nPivxProtocolV2StartHeight;
uint256 posLimit;
uint256 posLimit_V2;
int64_t nPosTargetSpacing;
int64_t nPosTargetTimespan;
int64_t nPosTargetTimespan_V2;
int32_t nStakeMinDepth;
int32_t nStakeMinAge;
int64_t nBlockStakeModifierV1A;
int64_t nBlockStakeModifierV2;

/** Time Protocol V2 **/
int nBlockTimeProtocolV2;
bool IsTimeProtocolV2(const int nHeight) const { return nHeight >= nBlockTimeProtocolV2; }
int nTimeSlotLength;

/** ATP parameters */
int64_t ATPStartHeight;
std::string WgrAddrPrefix;
Expand Down
13 changes: 11 additions & 2 deletions src/miner.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Copyright (c) 2011-2013 The PPCoin developers
// Copyright (c) 2013-2014 The NovaCoin Developers
// Copyright (c) 2014-2018 The BlackCoin Developers
// Copyright (c) 2015-2019 The PIVX developers
// Copyright (c) 2014-2021 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
Expand Down Expand Up @@ -61,7 +65,12 @@ uint64_t nLastBlockSize = 0;
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
{
int64_t nOldTime = pblock->nTime;
int64_t nNewTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
int64_t nNewTime;
if (consensusParams.IsTimeProtocolV2(pindexPrev->nHeight + 1)) {
nNewTime = GetTimeSlot(GetAdjustedTime());
} else {
nNewTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
}

if (nOldTime < nNewTime)
pblock->nTime = nNewTime;
Expand Down Expand Up @@ -139,7 +148,7 @@ bool BlockAssembler::SplitCoinstakeVouts(std::shared_ptr<CMutableTransaction> co
}

std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn,
std::shared_ptr<CMutableTransaction> pCoinstakeTx, std::shared_ptr<CStakeInput> coinstakeInput, unsigned int nTxNewTime)
std::shared_ptr<CMutableTransaction> pCoinstakeTx, std::shared_ptr<CStakeInput> coinstakeInput, uint64_t nTxNewTime)
{
CBasicKeyStore tempKeystore;
#ifdef ENABLE_WALLET
Expand Down
2 changes: 1 addition & 1 deletion src/miner.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ class BlockAssembler

/** Construct a new block template with coinbase to scriptPubKeyIn */
std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn,
std::shared_ptr<CMutableTransaction> pCoinstakeTx = nullptr, std::shared_ptr<CStakeInput> coinstakeInput = nullptr, unsigned int nTxNewTime = 0);
std::shared_ptr<CMutableTransaction> pCoinstakeTx = nullptr, std::shared_ptr<CStakeInput> coinstakeInput = nullptr, uint64_t nTxNewTime = 0);

private:
// utility functions
Expand Down
26 changes: 26 additions & 0 deletions src/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2338,6 +2338,32 @@ int CConnman::GetExtraOutboundCount()
return std::max(nOutbound - nMaxOutbound, 0);
}

void CConnman::CheckOffsetDisconnectedPeers(const CNetAddr& ip)
{
int nConnections = 0;
{
LOCK(cs_vNodes);
for (CNode* pnode : vNodes) {
if (pnode->fSuccessfullyConnected)
nConnections++;
if (nConnections == 2)
return;
}
}

// Not enough connections. Insert peer.
static std::set<CNetAddr> setOffsetDisconnectedPeers;
setOffsetDisconnectedPeers.insert(ip);
if (setOffsetDisconnectedPeers.size() >= 16) {
// clear the set
setOffsetDisconnectedPeers.clear();
// Trigger the warning
std::string strMessage = _("Warning: Peers are being disconnected due time differences. Please check that your computer's date and time are correct! If your clock is wrong Wagerr Core will not work properly.");
LogPrintf("*** %s\n", strMessage);
uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_ERROR);
}
}

void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
{
// Connect to specific addresses
Expand Down
2 changes: 2 additions & 0 deletions src/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,8 @@ friend class CNode;
// not yet fully disconnected.
int GetExtraOutboundCount();

void CheckOffsetDisconnectedPeers(const CNetAddr& ip);

bool AddNode(const std::string& node);
bool RemoveAddedNode(const std::string& node);
std::vector<AddedNodeInfo> GetAddedNodeInfo();
Expand Down
7 changes: 7 additions & 0 deletions src/net_processing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2319,6 +2319,13 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr

int64_t nTimeOffset = nTime - GetTime();
pfrom->nTimeOffset = nTimeOffset;
const int nTimeSlotLength = Params().GetConsensus().nTimeSlotLength;
if (abs64(nTimeOffset) > 2 * nTimeSlotLength) {
LogPrintf("timeOffset (%d seconds) too large. Disconnecting node %s\n",
nTimeOffset, pfrom->addr.ToString().c_str());
pfrom->fDisconnect = true;
connman->CheckOffsetDisconnectedPeers(pfrom->addr);
}
AddTimeData(pfrom->addr, nTimeOffset);

// Feeler connections exist only to verify if address is online.
Expand Down
28 changes: 15 additions & 13 deletions src/pos/kernel.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Copyright (c) 2012-2013 The PPCoin developers
// Copyright (c) 2015-2018 The PIVX developers
// Copyright (c) 2011-2013 The PPCoin developers
// Copyright (c) 2013-2014 The NovaCoin Developers
// Copyright (c) 2014-2018 The BlackCoin Developers
// Copyright (c) 2015-2019 The PIVX developers
// Copyright (c) 2018-2019 The Ion developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
Expand Down Expand Up @@ -229,7 +231,7 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64_t& nStakeMod

// The stake modifier used to hash for a stake kernel is chosen as the stake
// modifier about a selection interval later than the coin generating the kernel
bool GetKernelStakeModifier(uint256 hashBlockFrom, uint64_t& nStakeModifier, int& nStakeModifierHeight, int64_t& nStakeModifierTime, bool fPrintProofOfStake)
bool GetKernelStakeModifier(const uint256& hashBlockFrom, uint64_t& nStakeModifier, int& nStakeModifierHeight, int64_t& nStakeModifierTime, bool fPrintProofOfStake)
{
nStakeModifier = 0;
if (!mapBlockIndex.count(hashBlockFrom))
Expand Down Expand Up @@ -316,7 +318,7 @@ bool HasStakeMinAgeOrDepth(const int contextHeight, const uint32_t contextTime,
{
// before stake modifier V2, the age required was 60 * 60 (1 hour) / not required on regtest
if (contextHeight < Params().GetConsensus().nBlockStakeModifierV2)
return (Params().NetworkIDString() == CBaseChainParams::REGTEST || (utxoFromBlockTime + 3600 <= contextTime));
return (Params().NetworkIDString() == CBaseChainParams::REGTEST || (utxoFromBlockTime + Params().GetConsensus().nStakeMinAge <= contextTime));

// after stake modifier V2, we require the utxo to be nStakeMinDepth deep in the chain
return (contextHeight - utxoFromBlockHeight >= Params().GetConsensus().nStakeMinDepth);
Expand Down Expand Up @@ -349,7 +351,7 @@ bool ContextualCheckZerocoinStake(int nPreviousBlockHeight, CStakeInput* stake)
}

// Check kernel hash target and coinstake signature
bool initStakeInput(const CBlock block, std::unique_ptr<CStake>& ionStake, std::unique_ptr<CZStake>& zStake, int nPreviousBlockHeight) {
bool initStakeInput(const CBlock& block, std::unique_ptr<CStake>& ionStake, std::unique_ptr<CZStake>& zStake, int nPreviousBlockHeight) {
const CTransaction tx = *block.vtx[1];
if (!tx.IsCoinStake())
return error("%s : called on non-coinstake %s", __func__, tx.GetHash().GetHex());
Expand Down Expand Up @@ -390,7 +392,7 @@ bool initStakeInput(const CBlock block, std::unique_ptr<CStake>& ionStake, std::
}

// Check kernel hash target and coinstake signature
bool CheckProofOfStake(const CBlock block, uint256& hashProofOfStake, const CBlockIndex* pindex)
bool CheckProofOfStake(const CBlock& block, uint256& hashProofOfStake, const CBlockIndex* pindex)
{
std::unique_ptr<CStake> ionStake;
std::unique_ptr<CZStake> zStake;
Expand Down Expand Up @@ -432,13 +434,6 @@ bool CheckProofOfStake(const CBlock block, uint256& hashProofOfStake, const CBlo
return true;
}

// Check whether the coinstake timestamp meets protocol
bool CheckCoinStakeTimestamp(int64_t nTimeBlock, int64_t nTimeTx)
{
// v0.3 protocol
return (nTimeBlock == nTimeTx);
}

// Get stake modifier checksum
unsigned int GetStakeModifierChecksum(const CBlockIndex* pindex)
{
Expand All @@ -465,6 +460,13 @@ bool CheckStakeModifierCheckpoints(int nHeight, unsigned int nStakeModifierCheck
return true;
}

// Timestamp for time protocol V2: slot duration 15 seconds
int64_t GetTimeSlot(const int64_t nTime)
{
const int slotLen = Params().GetConsensus().nTimeSlotLength;
return (nTime / slotLen) * slotLen;
}

bool SetPOSParameters(const CBlock& block, CValidationState& state, CBlockIndex* pindexNew) {
AssertLockHeld(cs_main);

Expand Down
Loading

0 comments on commit 682c853

Please sign in to comment.