Skip to content

Commit

Permalink
New diff algo (#147)
Browse files Browse the repository at this point in the history
* Added new difficulty algorithm based on exponential difficulty retargeting

* Added hardfork conditions. Fixed issue with signmessage and tposcontract cleanup

* Reverted difficulty changes. Implementing PoSV3 stake modifiers

* Fixes to hardfork transition

* Reverted testing changes. Changed where pos block is checked

* Changed upgrage height. Reverted some old changes

* Updated hf details

* Updated version

* Changed hf payments

* Changed hardfork date
  • Loading branch information
durkmurder authored Nov 18, 2019
1 parent 43ed8dd commit 7fe0dae
Show file tree
Hide file tree
Showing 15 changed files with 227 additions and 91 deletions.
4 changes: 2 additions & 2 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 1)
define(_CLIENT_VERSION_MINOR, 0)
define(_CLIENT_VERSION_REVISION, 20)
define(_CLIENT_VERSION_REVISION, 21)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2018)
define(_COPYRIGHT_YEAR, 2019)
define(_COPYRIGHT_HOLDERS,[The %s developers])
define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[XSN Core]])
AC_INIT([XSN Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[https://github.com/xsn/xsn/issues],[xsn],[https://xsncore.org/])
Expand Down
2 changes: 1 addition & 1 deletion src/chain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ arith_uint256 CBlockIndex::GetBlockTrust() const
if (bnTarget <= 0)
return 0;

if (IsProofOfStake()) {
if (IsProofOfStake(false)) {
// Return trust score as usual
return (arith_uint256(1) << 256) / (bnTarget + 1);
} else {
Expand Down
24 changes: 20 additions & 4 deletions src/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,12 @@ class CBlockIndex
BLOCK_PROOF_OF_STAKE = (1 << 0), // is proof-of-stake block
BLOCK_STAKE_ENTROPY = (1 << 1), // entropy bit for stake modifier
BLOCK_STAKE_MODIFIER = (1 << 2), // regenerated stake modifier
BLOCK_PROOF_OF_STAKE_V3 = (1 << 3),
};

// proof-of-stake specific fields
arith_uint256 GetBlockTrust() const;
uint256 hashStakeModifierV3; // hash modifier for PoS v3.
uint64_t nStakeModifier; // hash modifier for proof-of-stake
unsigned int nStakeModifierChecksum; // checksum of index; in-memeory only
COutPoint prevoutStake;
Expand Down Expand Up @@ -259,6 +261,7 @@ class CBlockIndex
nMint = 0;
nMoneySupply = 0;
nFlags = 0;
hashStakeModifierV3.SetNull();
nStakeModifier = 0;
nStakeModifierChecksum = 0;
prevoutStake.SetNull();
Expand Down Expand Up @@ -296,7 +299,7 @@ class CBlockIndex
hashProofOfStake = uint256();

if (block.IsProofOfStake()) {
SetProofOfStake();
SetProofOfStake(false);
prevoutStake = block.vtx[1]->vin[0].prevout;
nStakeTime = block.nTime;
} else {
Expand Down Expand Up @@ -372,14 +375,22 @@ class CBlockIndex
return !(nFlags & BLOCK_PROOF_OF_STAKE);
}

bool IsProofOfStake() const
bool IsProofOfStake(bool isProofOfStakeV3) const
{
if(isProofOfStakeV3) {
return (nFlags & BLOCK_PROOF_OF_STAKE_V3);
}

return (nFlags & BLOCK_PROOF_OF_STAKE);
}

void SetProofOfStake()
void SetProofOfStake(bool isProofOfStakeV3)
{
nFlags |= BLOCK_PROOF_OF_STAKE;
if(isProofOfStakeV3)
{
nFlags |= BLOCK_PROOF_OF_STAKE_V3;
}
}

unsigned int GetStakeEntropyBit() const;
Expand Down Expand Up @@ -484,10 +495,15 @@ class CDiskBlockIndex : public CBlockIndex
READWRITE(nMoneySupply);
READWRITE(nFlags);
READWRITE(nStakeModifier);
if (IsProofOfStake()) {
if (IsProofOfStake(false)) {
READWRITE(prevoutStake);
READWRITE(nStakeTime);
READWRITE(hashProofOfStake);

if(IsProofOfStake(true)) {
READWRITE(hashStakeModifierV3);
}

} else {
const_cast<CDiskBlockIndex*>(this)->prevoutStake.SetNull();
const_cast<CDiskBlockIndex*>(this)->nStakeTime = 0;
Expand Down
1 change: 1 addition & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class CMainParams : public CChainParams {
consensus.nPowTargetSpacing = 1 * 60; // XSN: 1 minutes
consensus.nPosTargetSpacing = 1 * 60; // XSN: 1 minutes
consensus.nPosTargetTimespan = 60 * 40;
consensus.nPoSUpdgradeHFHeight = 898488; // 1st of January 2019
consensus.nMerchantnodeMinimumConfirmations = 1;
consensus.nMasternodeMinimumConfirmations = 15;
consensus.nStakeMinAge = 60 * 60;
Expand Down
1 change: 1 addition & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ struct Params {
int nCoinbaseMaturity;
int nTPoSContractSignatureDeploymentTime;
int nMaxBlockSpacingFixDeploymentHeight;
int nPoSUpdgradeHFHeight;
};
} // namespace Consensus

Expand Down
74 changes: 50 additions & 24 deletions src/kernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,14 @@ static bool SelectBlockFromCandidates(
continue;
// compute the selection hash by hashing its proof-hash and the
// previous proof-of-stake modifier
uint256 hashProof = pindex->IsProofOfStake()? pindex->hashProofOfStake : pindex->GetBlockHash();
uint256 hashProof = pindex->IsProofOfStake(false) ? pindex->hashProofOfStake : pindex->GetBlockHash();
CDataStream ss(SER_GETHASH, 0);
ss << hashProof << nStakeModifierPrev;
arith_uint256 hashSelection = UintToArith256(Hash(ss.begin(), ss.end()));
// the selection hash is divided by 2**32 so that proof-of-stake block
// is always favored over proof-of-work block. this is to preserve
// the energy efficiency property
if (pindex->IsProofOfStake())
if (pindex->IsProofOfStake(false))
hashSelection >>= 32;
if (fSelected && hashSelection < hashBest)
{
Expand All @@ -127,6 +127,22 @@ static bool SelectBlockFromCandidates(
return fSelected;
}

// Stake Modifier (hash modifier of proof-of-stake):
// The purpose of stake modifier is to prevent a txout (coin) owner from
// computing future proof-of-stake generated by this txout at the time
// of transaction confirmation. To meet kernel protocol, the txout
// must hash with a future stake modifier to generate the proof.
uint256 ComputeStakeModifierV3(const CBlockIndex* pindexPrev, const uint256& kernel)
{
if (!pindexPrev)
return uint256(); // genesis block's modifier is 0

CDataStream ss(SER_GETHASH, 0);
ss << kernel << pindexPrev->hashStakeModifierV3;
return Hash(ss.begin(), ss.end());
}


// Stake Modifier (hash modifier of proof-of-stake):
// The purpose of stake modifier is to prevent a txout (coin) owner from
// computing future proof-of-stake generated by this txout at the time
Expand Down Expand Up @@ -217,15 +233,15 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexCurrent, uint64_t& nStake
while (pindex && pindex->nHeight >= nHeightFirstCandidate)
{
// '=' indicates proof-of-stake blocks not selected
if (pindex->IsProofOfStake())
if (pindex->IsProofOfStake(false))
strSelectionMap.replace(pindex->nHeight - nHeightFirstCandidate, 1, "=");
pindex = pindex->pprev;
}
for(const auto& item : mapSelectedBlocks)
{
// 'S' indicates selected proof-of-stake blocks
// 'W' indicates selected proof-of-work blocks
strSelectionMap.replace(item.second->nHeight - nHeightFirstCandidate, 1, item.second->IsProofOfStake()? "S" : "W");
strSelectionMap.replace(item.second->nHeight - nHeightFirstCandidate, 1, item.second->IsProofOfStake(false) ? "S" : "W");
}
LogPrint(BCLog::KERNEL, "%s : selection height [%d, %d] map %s\n", __func__, nHeightFirstCandidate, pindexPrev->nHeight, strSelectionMap.c_str());
}
Expand Down Expand Up @@ -368,16 +384,18 @@ uint256 stakeHash(unsigned int nTimeTx, CDataStream ss, unsigned int prevoutInde
// quantities so as to generate blocks faster, degrading the system back into
// a proof-of-work situation.
//
bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned int nTxPrevOffset, const CTransactionRef& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, bool fPrintProofOfStake)
bool CheckStakeKernelHash(const CBlockIndex* pindexPrev, unsigned int nBits, uint256 hashBlockFrom, int64_t blockFromTime,
const CTransactionRef& txPrev, const COutPoint& prevout, unsigned int nTimeTx,
uint256& hashProofOfStake, bool fPoSV3, bool fPrintProofOfStake)
{
nTxPrevOffset = 336;
auto txPrevTime = blockFrom.GetBlockTime();
auto nTxPrevOffset = 336;
auto txPrevTime = blockFromTime;
unsigned int nTimeBlockFrom = blockFromTime;
if (nTimeTx < txPrevTime) // Transaction timestamp violation
return error("CheckStakeKernelHash() : nTime violation");

auto nStakeMinAge = Params().GetConsensus().nStakeMinAge;
auto nStakeMaxAge = Params().GetConsensus().nStakeMaxAge;
unsigned int nTimeBlockFrom = blockFrom.GetBlockTime();
if (nTimeBlockFrom + nStakeMinAge > nTimeTx) // Min age requirement
return error("CheckStakeKernelHash() : min age violation");

Expand All @@ -396,10 +414,16 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned
int nStakeModifierHeight = 0;
int64_t nStakeModifierTime = 0;

if (!GetKernelStakeModifier(blockFrom.GetHash(), nTimeTx, nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake))
return error("Failed to get kernel stake modifier");
if(fPoSV3) {
ss << pindexPrev->hashStakeModifierV3;
}
else {

if (!GetKernelStakeModifier(hashBlockFrom, nTimeTx, nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake))
return error("Failed to get kernel stake modifier");

ss << nStakeModifier;
ss << nStakeModifier;
}

ss << nTimeBlockFrom << nTxPrevOffset << txPrevTime << prevout.n << nTimeTx;
hashProofOfStake = Hash(ss.begin(), ss.end());
Expand All @@ -409,14 +433,14 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned
__func__,
nStakeModifier, nStakeModifierHeight,
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nStakeModifierTime).c_str(),
mapBlockIndex[blockFrom.GetHash()]->nHeight,
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", blockFrom.GetBlockTime()).c_str());
mapBlockIndex[hashBlockFrom]->nHeight,
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", blockFromTime).c_str());

LogPrint(BCLog::KERNEL, "%s : check protocol=%s modifier=0x%016" PRI64x" nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n",
__func__,
"0.5",
nStakeModifier,
nTimeBlockFrom, nTxPrevOffset,
blockFromTime, nTxPrevOffset,
txPrevTime, prevout.n, nTimeTx,
hashProofOfStake.ToString().c_str());
}
Expand All @@ -431,13 +455,14 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned
__func__,
nStakeModifier, nStakeModifierHeight,
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nStakeModifierTime).c_str(),
mapBlockIndex[blockFrom.GetHash()]->nHeight,
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", blockFrom.GetBlockTime()).c_str());
mapBlockIndex[hashBlockFrom]->nHeight,
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", blockFromTime).c_str());

LogPrint(BCLog::KERNEL, "%s : Generated pass protocol=%s modifier=0x%016" PRI64x" nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n",
__func__,
"0.5",
nStakeModifier,
nTimeBlockFrom, nTxPrevOffset, txPrevTime, prevout.n, nTimeTx,
blockFromTime, nTxPrevOffset, txPrevTime, prevout.n, nTimeTx,
hashProofOfStake.ToString().c_str());
}
return true;
Expand Down Expand Up @@ -470,7 +495,7 @@ bool CheckKernelScript(CScript scriptVin, CScript scriptVout)
}

// Check kernel hash target and coinstake signature
bool CheckProofOfStake(const CBlock &block, uint256& hashProofOfStake)
bool CheckProofOfStake(const CBlockIndex *pindexPrev, const CBlock &block, uint256& hashProofOfStake, const Consensus::Params &params)
{
const CTransactionRef &tx = block.vtx[1];
if (!tx->IsCoinStake())
Expand All @@ -483,9 +508,7 @@ bool CheckProofOfStake(const CBlock &block, uint256& hashProofOfStake)
uint256 hashBlock;
CTransactionRef txPrev;

const auto &cons = Params().GetConsensus();

if (!GetTransaction(txin.prevout.hash, txPrev, cons, hashBlock, true))
if (!GetTransaction(txin.prevout.hash, txPrev, params, hashBlock, true))
return error("CheckProofOfStake() : INFO: read txPrev failed");

CTxOut prevTxOut = txPrev->vout[txin.prevout.n];
Expand All @@ -498,7 +521,7 @@ bool CheckProofOfStake(const CBlock &block, uint256& hashProofOfStake)
return error("CheckProofOfStake() : VerifySignature failed on coinstake %s", tx->GetHash().ToString().c_str());
}

CBlockIndex* pindex = NULL;
CBlockIndex* pindex = nullptr;
BlockMap::iterator it = mapBlockIndex.find(hashBlock);
if (it != mapBlockIndex.end())
pindex = it->second;
Expand All @@ -507,14 +530,16 @@ bool CheckProofOfStake(const CBlock &block, uint256& hashProofOfStake)

// Read block header
CBlock blockprev;
if (!ReadBlockFromDisk(blockprev, pindex->GetBlockPos(), cons))
if (!ReadBlockFromDisk(blockprev, pindex->GetBlockPos(), params))
return error("CheckProofOfStake(): INFO: failed to find block");

if(!CheckKernelScript(prevTxOut.scriptPubKey, tx->vout[1].scriptPubKey))
return error("CheckProofOfStake() : INFO: check kernel script failed on coinstake %s, hashProof=%s \n", tx->GetHash().ToString().c_str(), hashProofOfStake.ToString().c_str());

bool isProofOfStakeV3 = params.nPoSUpdgradeHFHeight < pindexPrev->nHeight;

unsigned int nTime = block.nTime;
if (!CheckStakeKernelHash(block.nBits, blockprev, /*postx->nTxOffset + */sizeof(CBlock), txPrev, txin.prevout, nTime, hashProofOfStake, true))
if (!CheckStakeKernelHash(pindexPrev, block.nBits, blockprev.GetHash(), blockprev.GetBlockTime(), txPrev, txin.prevout, nTime, hashProofOfStake, isProofOfStakeV3, true))
return error("CheckProofOfStake() : INFO: check kernel failed on coinstake %s, hashProof=%s \n", tx->GetHash().ToString().c_str(), hashProofOfStake.ToString().c_str()); // may occur during initial download or if behind on block chain sync

return true;
Expand Down Expand Up @@ -547,3 +572,4 @@ bool CheckStakeModifierCheckpoints(int nHeight, unsigned int nStakeModifierCheck
return nStakeModifierChecksum == mapStakeModifierCheckpoints[nHeight];
return true;
}

16 changes: 10 additions & 6 deletions src/kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
#include <arith_uint256.h>
#include <primitives/transaction.h>

namespace Consensus {
struct Params;
}

class CBlock;
class CWallet;
class COutPoint;
Expand All @@ -24,18 +28,18 @@ extern unsigned int getIntervalVersion(bool fTestNet);
// ratio of group interval length between the last group and the first group
static const int MODIFIER_INTERVAL_RATIO = 3;

// Compute the hash modifier for proof-of-stake
bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64_t& nStakeModifier, bool& fGeneratedStakeModifier);
uint256 ComputeStakeModifierV3(const CBlockIndex* pindexPrev, const uint256& kernel);
bool ComputeNextStakeModifier(const CBlockIndex* pindexCurrent, uint64_t& nStakeModifier, bool& fGeneratedStakeModifier);

// Check whether stake kernel meets hash target
// Sets hashProofOfStake on success return
bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned int nTxPrevOffset,
const CTransactionRef& txPrev, const COutPoint& prevout, unsigned int nTimeTx,
uint256& hashProofOfStake, bool fPrintProofOfStake = false);
bool CheckStakeKernelHash(const CBlockIndex *pindexPrev, unsigned int nBits, uint256 hashBlockFrom, int64_t blockFromTime, const CTransactionRef& txPrev,
const COutPoint& prevout, unsigned int nTimeTx,
uint256& hashProofOfStake, bool fPoSV3, bool fPrintProofOfStake);

// Check kernel hash target and coinstake signature
// Sets hashProofOfStake on success return
bool CheckProofOfStake(const CBlock &block, uint256& hashProofOfStake);
bool CheckProofOfStake(const CBlockIndex *pindexPrev, const CBlock &block, uint256& hashProofOfStake, const Consensus::Params &params);

// Check whether the coinstake timestamp meets protocol
bool CheckCoinStakeTimestamp(int64_t nTimeBlock, int64_t nTimeTx);
Expand Down
Loading

0 comments on commit 7fe0dae

Please sign in to comment.