From d1923d42e5f3402c95909ecacfb0916049541632 Mon Sep 17 00:00:00 2001 From: barrystyle Date: Sat, 21 Oct 2023 22:29:02 +0800 Subject: [PATCH] consensus: update main consensus/hashing rules --- src/chain.cpp | 2 +- src/chain.h | 20 +-- src/chainparamsseeds.h | 28 ++-- src/consensus/amount.h | 9 +- src/consensus/tx_check.cpp | 7 +- src/consensus/tx_verify.cpp | 16 +-- src/kernel.cpp | 250 ++++++------------------------------ src/kernel.h | 4 - src/kernel/chainparams.cpp | 16 +-- src/net.cpp | 8 +- src/net_processing.cpp | 2 +- src/node/blockstorage.cpp | 9 -- src/pow.cpp | 47 +++---- src/pow.h | 2 + src/primitives/block.cpp | 6 +- src/primitives/block.h | 13 +- src/protocol.cpp | 4 +- src/uint256.h | 6 + src/validation.cpp | 229 ++++++++++++++++++--------------- src/validation.h | 6 +- src/version.h | 6 +- src/wallet/wallet.cpp | 9 +- 22 files changed, 262 insertions(+), 437 deletions(-) diff --git a/src/chain.cpp b/src/chain.cpp index ea8be4affe..3492af59c4 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -182,7 +182,7 @@ const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex* // peercoin: find last block index up to pindex const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake) { - while (pindex && pindex->pprev && (pindex->IsProofOfStake() != fProofOfStake)) + while (pindex && pindex->pprev && ((pindex->nNonce == 0) != fProofOfStake)) pindex = pindex->pprev; return pindex; } diff --git a/src/chain.h b/src/chain.h index 9e830c48f8..a13f201838 100644 --- a/src/chain.h +++ b/src/chain.h @@ -236,22 +236,17 @@ class CBlockIndex bool IsProofOfWork() const { - return !(nFlags & BLOCK_PROOF_OF_STAKE); + return !IsProofOfStake(); } bool IsProofOfStake() const { - return (nFlags & BLOCK_PROOF_OF_STAKE); - } - - void SetProofOfStake() - { - nFlags |= BLOCK_PROOF_OF_STAKE; + return nNonce == 0; } unsigned int GetStakeEntropyBit() const { - return ((nFlags & BLOCK_STAKE_ENTROPY) >> 1); + return ((GetBlockHash().GetLow64()) & 1llu); } bool SetStakeEntropyBit(unsigned int nEntropyBit) @@ -517,12 +512,9 @@ class CDiskBlockIndex : public CBlockIndex READWRITE(obj.nMoneySupply); READWRITE(obj.nFlags); READWRITE(obj.nStakeModifier); - if (obj.nFlags & BLOCK_PROOF_OF_STAKE) - { - READWRITE(obj.prevoutStake); - READWRITE(obj.nStakeTime); - READWRITE(obj.hashProofOfStake); - } + READWRITE(obj.prevoutStake); + READWRITE(obj.nStakeTime); + READWRITE(obj.hashProofOfStake); // block header READWRITE(obj.nVersion); diff --git a/src/chainparamsseeds.h b/src/chainparamsseeds.h index 17d38e8c9b..0e4f26dbb3 100644 --- a/src/chainparamsseeds.h +++ b/src/chainparamsseeds.h @@ -7,19 +7,21 @@ * Each line contains a BIP155 serialized (networkID, addr, port) tuple. */ static const uint8_t chainparams_seed_main[] = { - 0x01,0x04,0x87,0xb5,0xa4,0xbd,0x26,0xad, - 0x01,0x04,0x57,0x62,0xb9,0xf4,0x26,0xad, - 0x01,0x04,0x8b,0x3b,0x81,0xb3,0x26,0xad, - 0x01,0x04,0x2f,0xce,0x58,0x12,0x26,0xad, - 0x01,0x04,0x05,0x80,0x57,0x7e,0x26,0xad, - 0x01,0x04,0xd5,0x9f,0x51,0xe5,0x26,0xad, - 0x01,0x04,0x2e,0x65,0x4b,0x98,0x26,0xad, - 0x01,0x04,0xb2,0x72,0xe9,0x28,0x26,0xad, - 0x01,0x04,0x80,0xc7,0x28,0x23,0x26,0xad, - 0x01,0x04,0x44,0xb7,0xcf,0xaf,0x26,0xad, - 0x01,0x04,0xbc,0xa6,0x0c,0x61,0x26,0xad, - 0x01,0x04,0x9f,0x45,0x25,0x11,0x26,0xad, - 0x01,0x04,0x4a,0x2c,0xcf,0xa3,0x26,0xad, + 0x01,0x04,0x89,0xb8,0x2d,0x9b,0x42,0x76, + 0x01,0x04,0x8f,0xf4,0xd1,0xa2,0x42,0x76, + 0x01,0x04,0xb9,0x06,0x7b,0x84,0x42,0x76, + 0x01,0x04,0xd9,0xf1,0x37,0xfb,0x42,0x76, + 0x01,0x04,0x29,0x81,0x06,0x1d,0x42,0x76, + 0x01,0x04,0x2d,0xf3,0xb7,0xf9,0x42,0x76, + 0x01,0x04,0x2d,0xf3,0xbb,0x64,0x42,0x76, + 0x01,0x04,0x2d,0xf3,0xc8,0xca,0x42,0x76, + 0x01,0x04,0x2d,0xf3,0x3e,0xad,0x42,0x76, + 0x01,0x04,0x05,0xb4,0x19,0x56,0x42,0x76, + 0x01,0x04,0x05,0xb4,0x19,0x57,0x42,0x76, + 0x01,0x04,0x42,0x81,0x9c,0xb3,0x42,0x76, + 0x01,0x04,0x46,0x10,0x2a,0x69,0x42,0x76, + 0x01,0x04,0x47,0x54,0x17,0x84,0x42,0x76, + 0x01,0x04,0x55,0xa6,0x3c,0xdb,0x42,0x76, }; static const uint8_t chainparams_seed_test[] = { diff --git a/src/consensus/amount.h b/src/consensus/amount.h index 9e2b03df8a..f6f260b5f5 100644 --- a/src/consensus/amount.h +++ b/src/consensus/amount.h @@ -7,13 +7,14 @@ #define BITCOIN_CONSENSUS_AMOUNT_H #include +#include #include /** Amount in satoshis (Can be negative) */ typedef int64_t CAmount; -static constexpr CAmount COIN = 1000000; -static constexpr CAmount CENT = 10000; +static constexpr CAmount COIN = 100000000; +static constexpr CAmount CENT = 1000000; static const CAmount MIN_TX_FEE_PREV7 = CENT; static const CAmount MIN_TX_FEE = CENT / 10; @@ -21,7 +22,7 @@ static const CAmount PERKB_TX_FEE = CENT; static const CAmount MIN_TXOUT_AMOUNT = CENT; static const CAmount MAX_MINT_PROOF_OF_WORK = 9999 * COIN; static const CAmount MAX_MINT_PROOF_OF_WORK_V10 = 50 * COIN; -static const std::string CURRENCY_UNIT = "PPC"; +static const std::string CURRENCY_UNIT = "LDOGE"; static const std::string CURRENCY_ATOM = "sat"; // One indivisible minimum value unit /** No amount larger than this (in satoshi) is valid. @@ -33,7 +34,7 @@ static const std::string CURRENCY_ATOM = "sat"; // One indivisible minimum value * critical; in unusual circumstances like a(nother) overflow bug that allowed * for the creation of coins out of thin air modification could lead to a fork. * */ -static constexpr CAmount MAX_MONEY = 21000000 * COIN; +static constexpr CAmount MAX_MONEY = std::numeric_limits::max(); inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } #endif // BITCOIN_CONSENSUS_AMOUNT_H diff --git a/src/consensus/tx_check.cpp b/src/consensus/tx_check.cpp index 833089c36a..3a5bb7b0aa 100644 --- a/src/consensus/tx_check.cpp +++ b/src/consensus/tx_check.cpp @@ -36,10 +36,11 @@ bool CheckTransaction(const CTransaction& tx, TxValidationState& state) nValueOut += txout.nValue; if (!MoneyRange(nValueOut)) return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-txouttotal-toolarge"); + // peercoin: enforce minimum output amount - if ((!txout.IsEmpty()) && txout.nValue < MIN_TXOUT_AMOUNT && - (tx.nVersion < 3 && !(IsZeroAllowed(tx.nTime) && (txout.nValue == 0)))) - return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-txoutvalue-belowminimum"); + //if ((!txout.IsEmpty()) && txout.nValue < MIN_TXOUT_AMOUNT && + // (tx.nVersion < 3 && !(IsZeroAllowed(tx.nTime) && (txout.nValue == 0)))) + // return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-txoutvalue-belowminimum"); } // Check for duplicate inputs (see CVE-2018-17144) diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp index 2c363ea209..b5f3a8eda7 100644 --- a/src/consensus/tx_verify.cpp +++ b/src/consensus/tx_verify.cpp @@ -198,18 +198,10 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, } } - if (tx.IsCoinStake()) - { - // peercoin: coin stake tx earns reward instead of paying fee - uint64_t nCoinAge; - if (!GetCoinAge(tx, inputs, nCoinAge, nTimeTx)) - return state.Invalid(TxValidationResult::TX_CONSENSUS, "unable to get coin age for coinstake"); - CAmount nStakeReward = tx.GetValueOut() - nValueIn; - CAmount nCoinstakeCost = (GetMinFee(tx, nTimeTx) < PERKB_TX_FEE) ? 0 : (GetMinFee(tx, nTimeTx) - PERKB_TX_FEE); - if (nMoneySupply && nStakeReward > GetProofOfStakeReward(nCoinAge, nTimeTx, nMoneySupply) - nCoinstakeCost) - return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-coinstake-too-large"); - } - else + // stake amount validation has been moved to validation.cpp/ConnectBlock as LiteDoge's + // functions arent purely contextual (height) + + if (!tx.IsCoinStake()) { const CAmount value_out = tx.GetValueOut(); if (nValueIn < value_out) { diff --git a/src/kernel.cpp b/src/kernel.cpp index 62656142fa..d73b708463 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -22,24 +23,24 @@ using namespace std; // Protocol switch time of v0.3 kernel protocol -unsigned int nProtocolV03SwitchTime = 1363800000; -unsigned int nProtocolV03TestSwitchTime = 1359781000; +unsigned int nProtocolV03SwitchTime = 4000000000; +unsigned int nProtocolV03TestSwitchTime = 4000000000; // Protocol switch time of v0.4 kernel protocol -unsigned int nProtocolV04SwitchTime = 1399300000; -unsigned int nProtocolV04TestSwitchTime = 1395700000; +unsigned int nProtocolV04SwitchTime = 4000000000; +unsigned int nProtocolV04TestSwitchTime = 4000000000; // Protocol switch time of v0.5 kernel protocol -unsigned int nProtocolV05SwitchTime = 1461700000; -unsigned int nProtocolV05TestSwitchTime = 1447700000; +unsigned int nProtocolV05SwitchTime = 4000000000; +unsigned int nProtocolV05TestSwitchTime = 4000000000; // Protocol switch time of v0.6 kernel protocol // supermajority hardfork: actual fork will happen later than switch time -const unsigned int nProtocolV06SwitchTime = 1513050000; // Tue 12 Dec 03:40:00 UTC 2017 -const unsigned int nProtocolV06TestSwitchTime = 1508198400; // Tue 17 Oct 00:00:00 UTC 2017 +const unsigned int nProtocolV06SwitchTime = 4000000000; // Tue 12 Dec 03:40:00 UTC 2017 +const unsigned int nProtocolV06TestSwitchTime = 4000000000; // Tue 17 Oct 00:00:00 UTC 2017 // Protocol switch time for 0.7 kernel protocol -const unsigned int nProtocolV07SwitchTime = 1552392000; // Tue 12 Mar 12:00:00 UTC 2019 -const unsigned int nProtocolV07TestSwitchTime = 1541505600; // Tue 06 Nov 12:00:00 UTC 2018 +const unsigned int nProtocolV07SwitchTime = 4000000000; // Tue 12 Mar 12:00:00 UTC 2019 +const unsigned int nProtocolV07TestSwitchTime = 4000000000; // Tue 06 Nov 12:00:00 UTC 2018 // Switch time for new BIPs from bitcoin 0.16.x -const uint32_t nBTC16BIPsSwitchTime = 1569931200; // Tue 01 Oct 12:00:00 UTC 2019 -const uint32_t nBTC16BIPsTestSwitchTime = 1554811200; // Tue 09 Apr 12:00:00 UTC 2019 +const uint32_t nBTC16BIPsSwitchTime = 4000000000; // Tue 01 Oct 12:00:00 UTC 2019 +const uint32_t nBTC16BIPsTestSwitchTime = 4000000000; // Tue 09 Apr 12:00:00 UTC 2019 // Protocol switch time for v0.9 kernel protocol const unsigned int nProtocolV09SwitchTime = 1591617600; // Mon 8 Jun 12:00:00 UTC 2020 const unsigned int nProtocolV09TestSwitchTime = 1581940800; // Mon 17 Feb 12:00:00 UTC 2020 @@ -50,40 +51,6 @@ const unsigned int nProtocolV10TestSwitchTime = 1625140800; // Thu 1 Jul 12:00: const unsigned int nProtocolV12SwitchTime = 1681732800; // Mon 17 Apr 12:00:00 UTC 2023 const unsigned int nProtocolV12TestSwitchTime = 1669636800; // Mon 28 Nov 12:00:00 UTC 2022 -// Hard checkpoints of stake modifiers to ensure they are deterministic -static std::map mapStakeModifierCheckpoints = - boost::assign::map_list_of - ( 0, 0x0e00670bu ) - ( 19080, 0xad4e4d29u ) - ( 30583, 0xdc7bf136u ) - ( 99999, 0xf555cfd2u ) - (219999, 0x91b7444du ) - (336000, 0x6c3c8048u ) - (371850, 0x9b850bdfu ) - (407813, 0x46fe50b5u ) - (443561, 0x114a6e38u ) - (455470, 0x9b7af181u ) - (479189, 0xe04fb8e0u ) - (504051, 0x459f5a16u ) - (589659, 0xbd02492au ) - ; - -static std::map mapStakeModifierTestnetCheckpoints = - boost::assign::map_list_of - ( 0, 0x0e00670bu ) - ( 19080, 0x3711dc3au ) - ( 30583, 0xb480fadeu ) - ( 99999, 0x9a62eaecu ) - (219999, 0xeafe96c3u ) - (336000, 0x8330dc09u ) - (372751, 0xafb94e2fu ) - (382019, 0x7f5cf5ebu ) - (408500, 0x68cadee2u ) - (412691, 0x93138e67u ) - (441299, 0x03e195cbu ) - (442735, 0xe42d94feu ) - ; - // Whether the given coinstake is subject to new v0.3 protocol bool IsProtocolV03(unsigned int nTimeCoinStake) { @@ -203,24 +170,17 @@ static bool SelectBlockFromCandidates( *pindexSelected = (const CBlockIndex*) 0; for (const auto& item : vSortedByTimestamp) { -/* - if (!chainstate.BlockIndex().count(item.second)) - return error("SelectBlockFromCandidates: failed to find block index for candidate block %s", item.second.ToString()); - const CBlockIndex* pindex = pindexSelected.BlockIndex()[item.second]; -*/ const CBlockIndex* pindex = chainstate.m_blockman.LookupBlockIndex(item.second); if (!pindex) return error("SelectBlockFromCandidates: failed to find block index for candidate block %s", item.second.ToString()); - if (fSelected && pindex->GetBlockTime() > nSelectionIntervalStop) break; if (mapSelectedBlocks.count(pindex->GetBlockHash()) > 0) 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(); CDataStream ss(SER_GETHASH, 0); - ss << hashProof << nStakeModifierPrev; + ss << pindex->hashProofOfStake << nStakeModifierPrev; arith_uint256 hashSelection = UintToArith256(Hash(ss)); // 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 @@ -281,25 +241,10 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexCurrent, uint64_t &nStake LogPrintf("ComputeNextStakeModifier: no new interval keep current modifier: pindexPrev nHeight=%d nTime=%u\n", pindexPrev->nHeight, (unsigned int)pindexPrev->GetBlockTime()); return true; } - if (nModifierTime / params.nModifierInterval >= pindexCurrent->GetBlockTime() / params.nModifierInterval) - { - // v0.4+ requires current block timestamp also be in a different modifier interval - if (IsProtocolV04(pindexCurrent->nTime)) - { - if (gArgs.GetBoolArg("-debug", false)) - LogPrintf("ComputeNextStakeModifier: (v0.4+) no new interval keep current modifier: pindexCurrent nHeight=%d nTime=%u\n", pindexCurrent->nHeight, (unsigned int)pindexCurrent->GetBlockTime()); - return true; - } - else - { - if (gArgs.GetBoolArg("-debug", false)) - LogPrintf("ComputeNextStakeModifier: v0.3 modifier at block %s not meeting v0.4+ protocol: pindexCurrent nHeight=%d nTime=%u\n", pindexCurrent->GetBlockHash().ToString(), pindexCurrent->nHeight, (unsigned int)pindexCurrent->GetBlockTime()); - } - } // Sort candidate blocks by timestamp vector > vSortedByTimestamp; - vSortedByTimestamp.reserve(64 * params.nModifierInterval / params.nStakeTargetSpacing); + vSortedByTimestamp.reserve(64 * params.nModifierInterval / GetTargetSpacing(pindexPrev->nHeight)); int64_t nSelectionInterval = GetStakeModifierSelectionInterval(); int64_t nSelectionIntervalStart = (pindexPrev->GetBlockTime() / params.nModifierInterval) * params.nModifierInterval - nSelectionInterval; const CBlockIndex* pindex = pindexPrev; @@ -309,29 +254,8 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexCurrent, uint64_t &nStake pindex = pindex->pprev; } int nHeightFirstCandidate = pindex ? (pindex->nHeight + 1) : 0; - - // Shuffle before sort - for(int i = vSortedByTimestamp.size() - 1; i > 1; --i) - std::swap(vSortedByTimestamp[i], vSortedByTimestamp[GetRand(i)]); - - sort(vSortedByTimestamp.begin(), vSortedByTimestamp.end(), [] (const pair &a, const pair &b) - { - if (a.first != b.first) - return a.first < b.first; -// return b.second < a.second; - - // Timestamp equals - compare block hashes - const uint32_t *pa = (const uint32_t *)a.second.data(); - const uint32_t *pb = (const uint32_t *)b.second.data(); - int cnt = 256 / 32; - do { - --cnt; - if (pa[cnt] != pb[cnt]) - return pa[cnt] < pb[cnt]; - } while(cnt); - return false; // Elements are equal - - }); + std::reverse(vSortedByTimestamp.begin(), vSortedByTimestamp.end()); + std::sort(vSortedByTimestamp.begin(), vSortedByTimestamp.end()); // Select 64 blocks from candidate blocks to generate stake modifier uint64_t nStakeModifierNew = 0; @@ -383,47 +307,6 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexCurrent, uint64_t &nStake return true; } -// V0.5: Stake modifier used to hash for a stake kernel is chosen as the stake -// modifier that is (nStakeMinAge minus a selection interval) earlier than the -// stake, thus at least a selection interval later than the coin generating the -// kernel, as the generating coin is from at least nStakeMinAge ago. -static bool GetKernelStakeModifierV05(CBlockIndex* pindexPrev, unsigned int nTimeTx, uint64_t& nStakeModifier, int& nStakeModifierHeight, int64_t& nStakeModifierTime, bool fPrintProofOfStake) -{ - const Consensus::Params& params = Params().GetConsensus(); - const CBlockIndex* pindex = pindexPrev; - nStakeModifierHeight = pindex->nHeight; - nStakeModifierTime = pindex->GetBlockTime(); - int64_t nStakeModifierSelectionInterval = GetStakeModifierSelectionInterval(); - - if (nStakeModifierTime + params.nStakeMinAge - nStakeModifierSelectionInterval <= (int64_t) nTimeTx) - { - // Best block is still more than - // (nStakeMinAge minus a selection interval) older than kernel timestamp - if (fPrintProofOfStake) - return error("GetKernelStakeModifier() : best block %s at height %d too old for stake", - pindex->GetBlockHash().ToString(), pindex->nHeight); - else - return false; - } - // loop to find the stake modifier earlier by - // (nStakeMinAge minus a selection interval) - while (nStakeModifierTime + params.nStakeMinAge - nStakeModifierSelectionInterval >(int64_t) nTimeTx) - { - if (!pindex->pprev) - { // reached genesis block; should not happen - return error("GetKernelStakeModifier() : reached genesis block"); - } - pindex = pindex->pprev; - if (pindex->GeneratedStakeModifier()) - { - nStakeModifierHeight = pindex->nHeight; - nStakeModifierTime = pindex->GetBlockTime(); - } - } - nStakeModifier = pindex->nStakeModifier; - return true; -} - // V0.3: 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 static bool GetKernelStakeModifierV03(CBlockIndex* pindexPrev, uint256 hashBlockFrom, uint64_t& nStakeModifier, int& nStakeModifierHeight, int64_t& nStakeModifierTime, bool fPrintProofOfStake, Chainstate& chainstate) @@ -483,10 +366,7 @@ static bool GetKernelStakeModifierV03(CBlockIndex* pindexPrev, uint256 hashBlock // Get the stake modifier specified by the protocol to hash for a stake kernel static bool GetKernelStakeModifier(CBlockIndex* pindexPrev, uint256 hashBlockFrom, unsigned int nTimeTx, uint64_t& nStakeModifier, int& nStakeModifierHeight, int64_t& nStakeModifierTime, bool fPrintProofOfStake, Chainstate& chainstate) { - if (IsProtocolV05(nTimeTx)) - return GetKernelStakeModifierV05(pindexPrev, nTimeTx, nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake); - else - return GetKernelStakeModifierV03(pindexPrev, hashBlockFrom, nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake, chainstate); + return GetKernelStakeModifierV03(pindexPrev, hashBlockFrom, nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake, chainstate); } // peercoin kernel protocol @@ -520,68 +400,44 @@ bool CheckStakeKernelHash(unsigned int nBits, CBlockIndex* pindexPrev, const CBl const Consensus::Params& params = Params().GetConsensus(); unsigned int nTimeBlockFrom = blockFrom.GetBlockTime(); - if (nTimeTx < (txPrev->nTime? txPrev->nTime : nTimeBlockFrom)) // Transaction timestamp violation + if (nTimeTx < txPrev->nTime) // Transaction timestamp violation return error("CheckStakeKernelHash() : nTime violation"); if (nTimeBlockFrom + params.nStakeMinAge > nTimeTx) // Min age requirement return error("CheckStakeKernelHash() : min age violation"); - CBigNum bnTargetPerCoinDay; - bnTargetPerCoinDay.SetCompact(nBits); + CBigNum bnTarget; + bnTarget.SetCompact(nBits); + int64_t nValueIn = txPrev->vout[prevout.n].nValue; - // v0.3 protocol kernel hash weight starts from 0 at the 30-day min age - // this change increases active coins participating the hash and helps - // to secure the network when proof-of-stake difficulty is low - int64_t nTimeWeight = min((int64_t)nTimeTx - (txPrev->nTime? txPrev->nTime : nTimeBlockFrom), params.nStakeMaxAge) - (IsProtocolV03(nTimeTx)? params.nStakeMinAge : 0); - CBigNum bnCoinDayWeight = CBigNum(nValueIn) * nTimeWeight / COIN / (24 * 60 * 60); + CBigNum bnWeight = CBigNum(nValueIn); + bnTarget *= bnWeight; + + uint256 targetProofOfStake = bnTarget.getuint256(); + + uint64_t nStakeModifier = pindexPrev->nStakeModifier; + int nStakeModifierHeight = pindexPrev->nHeight; + int64_t nStakeModifierTime = pindexPrev->nTime; + // Calculate hash CDataStream ss(SER_GETHASH, 0); - uint64_t nStakeModifier = 0; - int nStakeModifierHeight = 0; - int64_t nStakeModifierTime = 0; - if (IsProtocolV03(nTimeTx)) // v0.3 protocol - { - if (!GetKernelStakeModifier(pindexPrev, blockFrom.GetHash(), nTimeTx, nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake, chainstate)) - return false; - ss << nStakeModifier; - } - else // v0.2 protocol - { - ss << nBits; - } - - ss << nTimeBlockFrom << nTxPrevOffset << (txPrev->nTime? txPrev->nTime : nTimeBlockFrom) << prevout.n << nTimeTx; + ss << nStakeModifier << nTimeBlockFrom << txPrev->nTime << prevout.hash << prevout.n << nTimeTx; hashProofOfStake = Hash(ss); + if (fPrintProofOfStake) { - if (IsProtocolV03(nTimeTx)) { - const CBlockIndex* pindexTmp = chainstate.m_blockman.LookupBlockIndex(blockFrom.GetHash()); - LogPrintf("CheckStakeKernelHash() : using modifier 0x%016x at height=%d timestamp=%s for block from height=%d timestamp=%s\n", - nStakeModifier, nStakeModifierHeight, - FormatISO8601DateTime(nStakeModifierTime), - pindexTmp->nHeight, - FormatISO8601DateTime(blockFrom.GetBlockTime())); - } - LogPrintf("CheckStakeKernelHash() : check protocol=%s modifier=0x%016x nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n", - IsProtocolV05(nTimeTx)? "0.5" : (IsProtocolV03(nTimeTx)? "0.3" : "0.2"), - IsProtocolV03(nTimeTx)? nStakeModifier : (uint64_t) nBits, + LogPrintf("CheckStakeKernelHash() : using modifier 0x%016x nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n", + nStakeModifier, nTimeBlockFrom, nTxPrevOffset, (txPrev->nTime? txPrev->nTime : nTimeBlockFrom), prevout.n, nTimeTx, hashProofOfStake.ToString()); } // Now check if proof-of-stake hash meets target protocol - if (CBigNum(hashProofOfStake) > bnCoinDayWeight * bnTargetPerCoinDay) + if (CBigNum(hashProofOfStake) > bnTarget) return false; + if (gArgs.GetBoolArg("-debug", false) && !fPrintProofOfStake) { - if (IsProtocolV03(nTimeTx)) { - const CBlockIndex* pindexTmp = chainstate.m_blockman.LookupBlockIndex(blockFrom.GetHash()); - LogPrintf("CheckStakeKernelHash() : using modifier 0x%016x at height=%d timestamp=%s for block from height=%d timestamp=%s\n", - nStakeModifier, nStakeModifierHeight, - FormatISO8601DateTime(nStakeModifierTime), - pindexTmp->nHeight, - FormatISO8601DateTime(blockFrom.GetBlockTime())); - } LogPrintf("CheckStakeKernelHash() : pass protocol=%s modifier=0x%016x nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n", IsProtocolV03(nTimeTx)? "0.3" : "0.2", IsProtocolV03(nTimeTx)? nStakeModifier : (uint64_t) nBits, @@ -670,19 +526,6 @@ unsigned int GetStakeModifierChecksum(const CBlockIndex* pindex) return hashChecksum.GetLow64(); } -// Check stake modifier hard checkpoints -bool CheckStakeModifierCheckpoints(int nHeight, unsigned int nStakeModifierChecksum) -{ - bool fTestNet = Params().NetworkIDString() == CBaseChainParams::TESTNET; - if (fTestNet && mapStakeModifierTestnetCheckpoints.count(nHeight)) - return nStakeModifierChecksum == mapStakeModifierTestnetCheckpoints[nHeight]; - - if (!fTestNet && mapStakeModifierCheckpoints.count(nHeight)) - return nStakeModifierChecksum == mapStakeModifierCheckpoints[nHeight]; - - return true; -} - bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck) { return (HowSuperMajority(minVersion, pstart, nRequired, nToCheck) >= nRequired); @@ -708,22 +551,9 @@ unsigned int HowSuperMajority(int minVersion, const CBlockIndex* pstart, unsigne unsigned int GetStakeEntropyBit(const CBlock& block) { unsigned int nEntropyBit = 0; - if (IsProtocolV04(block.nTime)) - { - nEntropyBit = UintToArith256(block.GetHash()).GetLow64() & 1llu;// last bit of block hash - if (gArgs.GetBoolArg("-printstakemodifier", false)) - LogPrintf("GetStakeEntropyBit(v0.4+): nTime=%u hashBlock=%s entropybit=%d\n", block.nTime, block.GetHash().ToString(), nEntropyBit); - } - else - { - // old protocol for entropy bit pre v0.4 - uint160 hashSig = Hash160(block.vchBlockSig); - if (gArgs.GetBoolArg("-printstakemodifier", false)) - LogPrintf("GetStakeEntropyBit(v0.3): nTime=%u hashSig=%s", block.nTime, hashSig.ToString()); - nEntropyBit = hashSig.data()[19] >> 7; // take the first bit of the hash - if (gArgs.GetBoolArg("-printstakemodifier", false)) - LogPrintf(" entropybit=%d\n", nEntropyBit); - } + nEntropyBit = UintToArith256(block.GetHash()).GetLow64() & 1llu;// last bit of block hash + if (gArgs.GetBoolArg("-printstakemodifier", false)) + LogPrintf("GetStakeEntropyBit(v0.4+): nTime=%u hashBlock=%s entropybit=%d\n", block.nTime, block.GetHash().ToString(), nEntropyBit); return nEntropyBit; } diff --git a/src/kernel.h b/src/kernel.h index 3c488c49e4..239e66db11 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -58,14 +58,10 @@ bool CheckCoinStakeTimestamp(int64_t nTimeBlock, int64_t nTimeTx); // Get stake modifier checksum unsigned int GetStakeModifierChecksum(const CBlockIndex* pindex); -// Check stake modifier hard checkpoints -bool CheckStakeModifierCheckpoints(int nHeight, unsigned int nStakeModifierChecksum); - // peercoin: block version supermajority calculation bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck); unsigned int HowSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck); -// peercoin: entropy bit for stake modifier if chosen by modifier unsigned int GetStakeEntropyBit(const CBlock& block); #endif // PEERCOIN_KERNEL_H diff --git a/src/kernel/chainparams.cpp b/src/kernel/chainparams.cpp index 0c5f9c1e2b..9ff2be89b9 100644 --- a/src/kernel/chainparams.cpp +++ b/src/kernel/chainparams.cpp @@ -79,13 +79,13 @@ class CMainParams : public CChainParams { consensus.powLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.bnInitialHashTarget = uint256S("0000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~arith_uint256(0) >> 40; - consensus.nTargetTimespan = 7 * 24 * 60 * 60; // one week - consensus.nStakeTargetSpacing = 10 * 60; // 10-minute block spacing + consensus.nTargetTimespan = 16 * 60; + consensus.nStakeTargetSpacing = 4 * 60; consensus.nTargetSpacingWorkMax = 12 * consensus.nStakeTargetSpacing; // 2-hour consensus.nPowTargetSpacing = consensus.nStakeTargetSpacing; - consensus.nStakeMinAge = 60 * 60 * 24 * 30; // minimum age for coin age + consensus.nStakeMinAge = 8 * 60 * 60; consensus.nStakeMaxAge = 60 * 60 * 24 * 90; - consensus.nModifierInterval = 6 * 60 * 60; // Modifier interval: time to elapse before new modifier is computed + consensus.nModifierInterval = 10 * 60; consensus.nCoinbaseMaturity = 500; consensus.fPowAllowMinDifficultyBlocks = false; @@ -151,11 +151,9 @@ class CMainParams : public CChainParams { chainTxData = ChainTxData{ // Data as of block 3125be5493e80431952593cce42b160019671108103735509238830939e1c9a3 (height 650000). - 1666903503, // * UNIX timestamp of last known number of transactions - 2145533, // * total number of transactions between genesis and that timestamp - // (the tx=... number in the ChainStateFlushed debug.log lines) - 0.006673443 // * estimated number of transactions per second after that timestamp - // 2145533/(1666903503-1345400356) = 0.006673443 + 1426450258, + 1, + 1, }; } }; diff --git a/src/net.cpp b/src/net.cpp index 62d8fe7509..0212b85ad8 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1669,9 +1669,9 @@ void CConnman::ThreadOpenConnections(const std::vector connect) // 60 seconds for any of those sources to populate addrman. bool add_fixed_seeds_now = false; // It is cheapest to check if enough time has passed first. - if (GetTime() > start + std::chrono::minutes{1}) { + if (GetTime() > start + std::chrono::seconds{2}) { add_fixed_seeds_now = true; - LogPrintf("Adding fixed seeds as 60 seconds have passed and addrman is empty for at least one reachable network\n"); + LogPrintf("Adding fixed seeds as 2 seconds have passed and addrman is empty for at least one reachable network\n"); } // Checking !dnsseed is cheaper before locking 2 mutexes. @@ -2002,8 +2002,8 @@ void CConnman::ThreadOpenAddedConnections() return; } } - // Retry every 60 seconds if a connection was attempted, otherwise two seconds - if (!interruptNet.sleep_for(std::chrono::seconds(tried ? 60 : 2))) + // Retry every 5 seconds if a connection was attempted, otherwise two seconds + if (!interruptNet.sleep_for(std::chrono::seconds(tried ? 5 : 2))) return; } } diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 11e83f8708..9c5e4ce7b8 100755 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -3200,7 +3200,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, if (peer == nullptr) return; // set deserialization mode to read PoS flag in headers - vRecv.SetType(vRecv.GetType() | SER_POSMARKER); + // vRecv.SetType(vRecv.GetType() | SER_POSMARKER); if (msg_type == NetMsgType::VERSION) { auto it = mapPoSTemperature.find(pfrom.addr); diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index 2a3acb29e2..52c60202a9 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -103,8 +103,6 @@ CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block, CBlockInde pindexNew->BuildSkip(); } pindexNew->nTimeMax = (pindexNew->pprev ? std::max(pindexNew->pprev->nTimeMax, pindexNew->nTime) : pindexNew->nTime); - if (block.nFlags & CBlockIndex::BLOCK_PROOF_OF_STAKE) - pindexNew->SetProofOfStake(); pindexNew->nChainTrust = (pindexNew->pprev ? pindexNew->pprev->nChainTrust : 0) + GetBlockTrust(*pindexNew); pindexNew->RaiseValidity(BLOCK_VALID_TREE); if (best_header == nullptr || best_header->nChainTrust < pindexNew->nChainTrust) { @@ -171,13 +169,6 @@ bool BlockManager::LoadBlockIndex(const Consensus::Params& consensus_params) if (pindex->pprev) { pindex->BuildSkip(); } - // peercoin: calculate stake modifier checksum - pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex); - //if (chainman.ActiveChain().Contains(pindex)) - if (pindex->nStatus & BLOCK_HAVE_DATA) { - if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum)) - return error("LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016llx", pindex->nHeight, pindex->nStakeModifier); - } } return true; diff --git a/src/pow.cpp b/src/pow.cpp index 766ff20453..149711b391 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -14,52 +14,47 @@ #include #include +inline bool IsProtocolV2(int nHeight) { return nHeight > 2; } +inline bool IsProtocolV1RetargetingFixed(int nHeight) { return nHeight > 1; } +unsigned int GetTargetSpacing(int nHeight) { return IsProtocolV2(nHeight) ? 64 : 60; } + unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake, const Consensus::Params& params) { + const uint256 bnTargetLimit = uint256S("0x00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + if (pindexLast == nullptr) - return UintToArith256(params.powLimit).GetCompact(); // genesis block + return UintToArith256(bnTargetLimit).GetCompact(); // genesis block const CBlockIndex* pindexPrev = GetLastBlockIndex(pindexLast, fProofOfStake); - if (pindexPrev->pprev == nullptr) - return UintToArith256(params.bnInitialHashTarget).GetCompact(); // first block + if (pindexPrev->pprev == NULL) + return UintToArith256(bnTargetLimit).GetCompact(); + const CBlockIndex* pindexPrevPrev = GetLastBlockIndex(pindexPrev->pprev, fProofOfStake); - if (pindexPrevPrev->pprev == nullptr) - return UintToArith256(params.bnInitialHashTarget).GetCompact(); // second block + if (pindexPrevPrev->pprev == NULL) + return UintToArith256(bnTargetLimit).GetCompact(); + int64_t nTargetSpacing = GetTargetSpacing(pindexLast->nHeight); int64_t nActualSpacing = pindexPrev->GetBlockTime() - pindexPrevPrev->GetBlockTime(); - // rfc20 - int64_t nHypotheticalSpacing = pindexLast->GetBlockTime() - pindexPrev->GetBlockTime(); - if (!fProofOfStake && IsProtocolV12(pindexPrev) && (nHypotheticalSpacing > nActualSpacing)) - nActualSpacing = nHypotheticalSpacing; + if (IsProtocolV1RetargetingFixed(pindexLast->nHeight)) { + if (nActualSpacing < 0) + nActualSpacing = nTargetSpacing; + } // peercoin: target change every block // peercoin: retarget with exponential moving toward target spacing CBigNum bnNew; bnNew.SetCompact(pindexPrev->nBits); - if (Params().NetworkIDString() != CBaseChainParams::REGTEST) { - int64_t nTargetSpacing; - - if (fProofOfStake) { - nTargetSpacing = params.nStakeTargetSpacing; - } else { - if (IsProtocolV09(pindexLast->nTime)) { - nTargetSpacing = params.nStakeTargetSpacing * 6; - } else { - nTargetSpacing = std::min(params.nTargetSpacingWorkMax, params.nStakeTargetSpacing * (1 + pindexLast->nHeight - pindexPrev->nHeight)); - } - } - - int64_t nInterval = params.nTargetTimespan / nTargetSpacing; - bnNew *= ((nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing); - bnNew /= ((nInterval + 1) * nTargetSpacing); - } + int64_t nInterval = params.nTargetTimespan / nTargetSpacing; + bnNew *= ((nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing); + bnNew /= ((nInterval + 1) * nTargetSpacing); if (bnNew > CBigNum(params.powLimit)) bnNew = CBigNum(params.powLimit); return bnNew.GetCompact(); } + /* // Check that on difficulty adjustments, the new difficulty does not increase // or decrease beyond the permitted limits. diff --git a/src/pow.h b/src/pow.h index d63230a002..22d1dc8015 100644 --- a/src/pow.h +++ b/src/pow.h @@ -14,6 +14,8 @@ class CBlockHeader; class CBlockIndex; class uint256; +unsigned int GetTargetSpacing(int nHeight); + unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake, const Consensus::Params& params); /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 6cb3636ff7..b250cfdfad 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -10,9 +10,9 @@ uint256 CBlockHeader::GetHash() const { - CBlockHeader tmp(*this); - tmp.nFlags = 0; - return SerializeHash(tmp); + if (nVersion > 6) + return SerializeHash(*this); + return GetPoWHash(); } uint256 CBlockHeader::GetPoWHash() const diff --git a/src/primitives/block.h b/src/primitives/block.h index 76e0fd36da..cb5746e40a 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -29,11 +29,10 @@ class CBlockHeader uint32_t nBits; uint32_t nNonce; - // peercoin: A copy from CBlockIndex.nFlags from other clients. We need this information because we are using headers-first syncronization. - uint32_t nFlags; // peercoin: Used in CheckProofOfStake(). + uint32_t nFlags; static const int32_t NORMAL_SERIALIZE_SIZE=80; - static const int32_t CURRENT_VERSION=4; + static const int32_t CURRENT_VERSION=7; CBlockHeader() { @@ -42,7 +41,13 @@ class CBlockHeader SERIALIZE_METHODS(CBlockHeader, obj) { - READWRITE(obj.nVersion, obj.hashPrevBlock, obj.hashMerkleRoot, obj.nTime, obj.nBits, obj.nNonce); + READWRITE(obj.nVersion); + READWRITE(obj.hashPrevBlock); + READWRITE(obj.hashMerkleRoot); + READWRITE(obj.nTime); + READWRITE(obj.nBits); + READWRITE(obj.nNonce); + // peercoin: do not serialize nFlags when computing hash if (!(s.GetType() & SER_GETHASH) && s.GetType() & SER_POSMARKER) READWRITE(obj.nFlags); diff --git a/src/protocol.cpp b/src/protocol.cpp index 5f17b82b68..7ded9a49bb 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -128,9 +128,9 @@ bool CMessageHeader::IsCommandValid() const ServiceFlags GetDesirableServiceFlags(ServiceFlags services) { if ((services & NODE_NETWORK_LIMITED) && g_initial_block_download_completed) { - return ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS); + return ServiceFlags(NODE_NETWORK_LIMITED/*| NODE_WITNESS*/); } - return ServiceFlags(NODE_NETWORK | NODE_WITNESS); + return ServiceFlags(NODE_NETWORK/*| NODE_WITNESS*/); } void SetServiceFlagsIBDCache(bool state) { diff --git a/src/uint256.h b/src/uint256.h index 1b49d62519..dba82e1bef 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -61,6 +61,12 @@ class base_blob friend constexpr bool operator!=(const base_blob& a, const base_blob& b) { return a.Compare(b) != 0; } friend constexpr bool operator<(const base_blob& a, const base_blob& b) { return a.Compare(b) < 0; } + uint64_t GetLow64() const + { + assert(WIDTH >= 2); + return m_data[0] | (uint64_t)m_data[1] << 32; + } + std::string GetHex() const; void SetHex(const char* psz); void SetHex(const std::string& str); diff --git a/src/validation.cpp b/src/validation.cpp index a5903f8643..3e75924393 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1390,68 +1390,84 @@ PackageMempoolAcceptResult ProcessNewPackage(Chainstate& active_chainstate, CTxM return result; } -int64_t GetProofOfWorkReward(unsigned int nBits, uint32_t nTime) +CAmount GetProofOfWorkReward(int nHeight, int64_t nFees) { - CBigNum bnSubsidyLimit = MAX_MINT_PROOF_OF_WORK; - CBigNum bnTarget; - bnTarget.SetCompact(nBits); - CBigNum bnTargetLimit(Params().GetConsensus().powLimit); - bnTargetLimit.SetCompact(bnTargetLimit.GetCompact()); - - // peercoin: subsidy is cut in half every 16x multiply of difficulty - // A reasonably continuous curve is used to avoid shock to market - // (nSubsidyLimit / nSubsidy) ** 4 == bnProofOfWorkLimit / bnTarget - CBigNum bnLowerBound = CENT; - CBigNum bnUpperBound = bnSubsidyLimit; - while (bnLowerBound + CENT <= bnUpperBound) - { - CBigNum bnMidValue = (bnLowerBound + bnUpperBound) / 2; - if (gArgs.GetBoolArg("-printcreation", false)) - LogPrintf("%s: lower=%lld upper=%lld mid=%lld\n", __func__, bnLowerBound.getuint64(), bnUpperBound.getuint64(), bnMidValue.getuint64()); - if (bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnTargetLimit > bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnTarget) - bnUpperBound = bnMidValue; - else - bnLowerBound = bnMidValue; - } - - int64_t nSubsidy = bnUpperBound.getuint64(); - nSubsidy = (nSubsidy / CENT) * CENT; - - nSubsidy = std::min(nSubsidy, IsProtocolV10(nTime) ? MAX_MINT_PROOF_OF_WORK_V10 : MAX_MINT_PROOF_OF_WORK); - - if (gArgs.GetBoolArg("-printcreation", false)) - LogPrintf("%s: create=%s nBits=0x%08x nSubsidy=%lld\n", __func__, FormatMoney(nSubsidy), nBits, nSubsidy); - - return nSubsidy; + int64_t nSubsidy = 0; + if (nHeight < 30) { + nSubsidy = 1000 * COIN; + } else if (nHeight < 1000) { + nSubsidy = 1000000 * COIN; + } else if (nHeight < 2000) { + nSubsidy = 500000 * COIN; + } else if (nHeight < 3000) { + nSubsidy = 250000 * COIN; + } else if (nHeight < 4000) { + nSubsidy = 125000 * COIN; + } else if (nHeight < 5000) { + nSubsidy = 62500 * COIN; + } else if (nHeight < 6000) { + nSubsidy = 31250 * COIN; + } else if (nHeight < 7000) { + nSubsidy = 15625 * COIN; + } else if (nHeight <= 8000) { + nSubsidy = 10000 * COIN; + } + + return nSubsidy + nFees; } -// peercoin: miner's coin stake is rewarded based on coin age spent (coin-days) -int64_t GetProofOfStakeReward(int64_t nCoinAge, uint32_t nTime, uint64_t nMoneySupply) +CAmount GetProofOfStakeReward(int nHeight, CAmount nFees) { - static int64_t nRewardCoinYear = CENT; // creation amount per coin-year - int64_t nSubsidy = nCoinAge * 33 / (365 * 33 + 8) * nRewardCoinYear; - - if (IsProtocolV09(nTime)) { - // rfc18 - // YearlyBlocks = ((365 * 33 + 8) / 33) * 1440 / 10 - // some efforts not to lose precision - CBigNum bnInflationAdjustment = nMoneySupply; - bnInflationAdjustment *= 25 * 33; - bnInflationAdjustment /= 10000 * 144; - bnInflationAdjustment /= (365 * 33 + 8); - - uint64_t nInflationAdjustment = bnInflationAdjustment.getuint64(); - uint64_t nSubsidyNew = (nSubsidy * 3) + nInflationAdjustment; - - if (gArgs.GetBoolArg("-printcreation", false)) - LogPrintf("%s: money supply %ld, inflation adjustment %f, old subsidy %ld, new subsidy %ld\n", __func__, nMoneySupply, nInflationAdjustment/1000000.0, nSubsidy, nSubsidyNew); - - nSubsidy = nSubsidyNew; - } + static const int halvingPeriod = 2000000; + + int64_t nSubsidy = 1000 * COIN; + + if (nHeight < 10000) { + nSubsidy = 100000 * COIN; + } else if (nHeight < 20000) { + nSubsidy = 50000 * COIN; + } else if (nHeight < 30000) { + nSubsidy = 25000 * COIN; + } else if (nHeight < 40000) { + nSubsidy = 12500 * COIN; + } else if (nHeight < 51000) { + nSubsidy = 10000 * COIN; + int halvings = nHeight / halvingPeriod; + nSubsidy = (halvings >= 64) ? 0 : (nSubsidy >> halvings); + nSubsidy -= nSubsidy * (nHeight % halvingPeriod) / (2 * halvingPeriod); + } else if (nHeight < 144999) { + nSubsidy = 30000 * COIN; + } else if (nHeight < 189999) { + nSubsidy = 28000 * COIN; + } else if (nHeight < 234999) { + nSubsidy = 26000 * COIN; + } else if (nHeight < 279999) { + nSubsidy = 24000 * COIN; + } else if (nHeight < 324999) { + nSubsidy = 22000 * COIN; + } else if (nHeight < 369999) { + nSubsidy = 20000 * COIN; + } else if (nHeight < 414999) { + nSubsidy = 18000 * COIN; + } else if (nHeight < 459999) { + nSubsidy = 16000 * COIN; + } else if (nHeight < 504999) { + nSubsidy = 14000 * COIN; + } else if (nHeight < 549999) { + nSubsidy = 12000 * COIN; + } else if (nHeight < 594999) { + nSubsidy = 10000 * COIN; + } else if (nHeight < 639999) { + nSubsidy = 4000 * COIN; + } else if (nHeight < 684999) { + nSubsidy = 2000 * COIN; + } else if (nHeight < 729999) { + nSubsidy = 1000 * COIN; + } else { + nSubsidy = 500 * COIN; + } - if (gArgs.GetBoolArg("-printcreation", false)) - LogPrintf("%s: create=%s nCoinAge=%lld\n", __func__, FormatMoney(nSubsidy), nCoinAge); - return nSubsidy; + return nSubsidy + nFees; } CoinsViews::CoinsViews(DBParams db_params, CoinsViewOptions options) @@ -1947,7 +1963,7 @@ bool PeercoinContextualBlockChecks(const CBlock& block, BlockValidationState& st { uint256 hashProofOfStake = uint256(); // peercoin: verify hash target and signature of coinstake tx - if (block.IsProofOfStake() && !CheckProofOfStake(state, pindex->pprev, block.vtx[1], block.nBits, hashProofOfStake, block.vtx[1]->nTime ? block.vtx[1]->nTime : block.nTime, chainstate)) { + if (block.IsProofOfStake() && !CheckProofOfStake(state, pindex->pprev, block.vtx[1], block.nBits, hashProofOfStake, block.vtx[1]->nTime, chainstate)) { LogPrintf("WARNING: %s: check proof-of-stake failed for block %s\n", __func__, block.GetHash().ToString()); return false; // do not error here as we expect this during initial block download } @@ -1963,6 +1979,8 @@ bool PeercoinContextualBlockChecks(const CBlock& block, BlockValidationState& st LogPrintf("WARNING: %s: duplicate proof-of-stake in block %s\n", __func__, block.GetHash().ToString()); return error("ConnectBlock() : Duplicate coinstake found"); } + } else { + hashProofOfStake = block.GetPoWHash(); } // peercoin: compute stake entropy bit for stake modifier @@ -1974,28 +1992,12 @@ bool PeercoinContextualBlockChecks(const CBlock& block, BlockValidationState& st if (!ComputeNextStakeModifier(pindex, nStakeModifier, fGeneratedStakeModifier, chainstate)) return error("ConnectBlock() : ComputeNextStakeModifier() failed"); - // compute nStakeModifierChecksum begin - unsigned int nFlagsBackup = pindex->nFlags; - uint64_t nStakeModifierBackup = pindex->nStakeModifier; - uint256 hashProofOfStakeBackup = pindex->hashProofOfStake; - // set necessary pindex fields if (!pindex->SetStakeEntropyBit(nEntropyBit)) return error("ConnectBlock() : SetStakeEntropyBit() failed"); pindex->SetStakeModifier(nStakeModifier, fGeneratedStakeModifier); pindex->hashProofOfStake = hashProofOfStake; - unsigned int nStakeModifierChecksum = GetStakeModifierChecksum(pindex); - - // undo pindex fields - pindex->nFlags = nFlagsBackup; - pindex->nStakeModifier = nStakeModifierBackup; - pindex->hashProofOfStake = hashProofOfStakeBackup; - // compute nStakeModifierChecksum end - - if (!CheckStakeModifierCheckpoints(pindex->nHeight, nStakeModifierChecksum)) - return error("ConnectBlock() : Rejected by stake modifier checkpoint height=%d, modifier=0x%016llx", pindex->nHeight, nStakeModifier); - if (fJustCheck) return true; @@ -2007,10 +2009,7 @@ bool PeercoinContextualBlockChecks(const CBlock& block, BlockValidationState& st pindex->hashProofOfStake = hashProofOfStake; setStakeSeen.insert(std::make_pair(pindex->prevoutStake, pindex->nTime)); } - if (!pindex->SetStakeEntropyBit(nEntropyBit)) - return error("ConnectBlock() : SetStakeEntropyBit() failed"); - pindex->SetStakeModifier(nStakeModifier, fGeneratedStakeModifier); - pindex->nStakeModifierChecksum = nStakeModifierChecksum; + chainstate.m_blockman.m_dirty_blockindex.insert(pindex); // queue a write to disk return true; @@ -2226,6 +2225,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, CAmount nFees = 0; int64_t nValueIn = 0; int64_t nValueOut = 0; + int64_t nStakeReward = 0; int nInputs = 0; int64_t nSigOpsCost = 0; blockundo.vtxundo.reserve(block.vtx.size() - 1); @@ -2252,6 +2252,8 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, nValueOut += tx.GetValueOut(); if (!tx.IsCoinStake()) nFees += txfee; + if (tx.IsCoinStake()) + nStakeReward = nValueOut - nValueIn; if (!MoneyRange(nFees)) { LogPrintf("ERROR: %s: accumulated fee in the block out of range.\n", __func__); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-txns-accumulated-fee-outofrange"); @@ -2310,7 +2312,33 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, Ticks(time_connect), Ticks(time_connect) / num_blocks_total); - // peercoin: coinbase reward check relocated to CheckBlock() + // Check reward earnt on mined block + CAmount nCoinbaseCost = 0; + if (block.IsProofOfWork()) + nCoinbaseCost = (GetMinFee(*block.vtx[0], block.nTime) < PERKB_TX_FEE)? 0 : (GetMinFee(*block.vtx[0], block.nTime) - PERKB_TX_FEE); + + if (block.vtx[0]->GetValueOut() > (block.IsProofOfWork()? GetProofOfWorkReward(pindex->nHeight, nFees) : 0)) + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-amount", + strprintf("CheckBlock() : coinbase reward exceeded %s > %s", + FormatMoney(block.vtx[0]->GetValueOut()), + FormatMoney(block.IsProofOfWork()? GetProofOfWorkReward(pindex->nHeight, nFees) : 0))); + + // Check reward earnt on coinstake + if (block.IsProofOfStake()) + { + // peercoin: coin stake tx earns reward instead of paying fee + uint64_t nCoinAge; + if (!GetCoinAge(*block.vtx[1], view, nCoinAge)) + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "unable to get coin age for coinstake"); + + CAmount nCalculatedStakeReward = GetProofOfStakeReward(pindex->pprev->nHeight, nFees); + + // LogPrintf("stakeRewardFound %llu stakeRewardCalculated %llu\n", nStakeReward / COIN, nCalculatedStakeReward / COIN); + + if (nStakeReward > nCalculatedStakeReward) { + return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-txns-coinstake-too-large"); + } + } if (!control.Wait()) { LogPrintf("ERROR: %s: CheckQueue failed\n", __func__); @@ -3375,6 +3403,8 @@ void Chainstate::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pin static bool CheckBlockHeader(const CBlockHeader& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true) { + if (block.nNonce == 0) return true; + // Check proof of work matches claimed amount if (fCheckPOW && !CheckProofOfWork(block.GetPoWHash(), block.nBits, consensusParams)) return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "high-hash", "proof of work failed"); @@ -3389,9 +3419,11 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu if (block.fChecked) return true; + const bool fProofOfStake = block.nNonce == 0; + // Check that the header is valid (particularly PoW). This is mostly // redundant with the call in AcceptBlockHeader. - if (!CheckBlockHeader(block, state, consensusParams, fCheckPOW && !block.IsProofOfStake())) + if (!CheckBlockHeader(block, state, consensusParams, fCheckPOW && !fProofOfStake)) return false; // Signet only: check block solution @@ -3447,15 +3479,6 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu if (block.IsProofOfStake() && !CheckCoinStakeTimestamp(block.GetBlockTime(), block.vtx[1]->nTime ? (int64_t)block.vtx[1]->nTime : block.GetBlockTime())) return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cs-time", "coinstake timestamp violation"); - // Check coinbase reward - CAmount nCoinbaseCost = 0; - if (block.IsProofOfWork()) - nCoinbaseCost = (GetMinFee(*block.vtx[0], block.nTime) < PERKB_TX_FEE)? 0 : (GetMinFee(*block.vtx[0], block.nTime) - PERKB_TX_FEE); - if (block.vtx[0]->GetValueOut() > (block.IsProofOfWork()? (GetProofOfWorkReward(block.nBits, block.GetBlockTime()) - nCoinbaseCost) : 0)) - return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-amount", - strprintf("CheckBlock() : coinbase reward exceeded %s > %s", - FormatMoney(block.vtx[0]->GetValueOut()), - FormatMoney(block.IsProofOfWork()? GetProofOfWorkReward(block.nBits, block.GetBlockTime()) : 0))); // Check transactions // Must check for duplicate inputs (see CVE-2018-17144) for (const auto& tx : block.vtx) { @@ -3485,7 +3508,7 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu // peercoin: check block signature // Only check block signature if check merkle root, c.f. commit 3cd01fdf // rfc6: validate signatures of proof of stake blocks only after 0.8 fork - if (fCheckMerkleRoot && fCheckSignature && (block.IsProofOfStake() || !IsBTC16BIPsEnabled(block.GetBlockTime())) && !CheckBlockSignature(block)) + if (fCheckMerkleRoot && fCheckSignature && (block.IsProofOfStake() && !CheckBlockSignature(block))) return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-blk-sign", strprintf("%s : bad block signature", __func__)); return true; @@ -3534,7 +3557,7 @@ bool HasValidProofOfWork(const std::vector& headers, const Consens { return std::all_of(headers.cbegin(), headers.cend(), [&](const auto& header) { - bool fPoS = header.nFlags & CBlockIndex::BLOCK_PROOF_OF_STAKE; + bool fPoS = header.nNonce == 0; return fPoS ? true : CheckProofOfWork(header.GetPoWHash(), header.nBits, consensusParams); }); } @@ -3565,8 +3588,9 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidatio const int nHeight = pindexPrev->nHeight + 1; // Check proof of work or proof-of-stake + bool fProofOfStake = block.nNonce == 0; const Consensus::Params& consensusParams = chainman.GetConsensus(); - if (block.nBits != GetNextTargetRequired(pindexPrev, block.nFlags & CBlockIndex::BLOCK_PROOF_OF_STAKE, consensusParams)) + if (block.nBits != GetNextTargetRequired(pindexPrev, fProofOfStake, consensusParams)) return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "bad-diffbits", "incorrect proof of work/stake"); // Check against checkpoints @@ -4903,7 +4927,7 @@ double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex *pin // guaranteed to be in main chain by sync-checkpoint. This rule is // introduced to help nodes establish a consistent view of the coin // age (trust score) of competing branches. -bool GetCoinAge(const CTransaction& tx, const CCoinsViewCache &view, uint64_t& nCoinAge, unsigned int nTimeTx, bool isTrueCoinAge) +bool GetCoinAge(const CTransaction& tx, const CCoinsViewCache &view, uint64_t& nCoinAge) { arith_uint256 bnCentSecond = 0; // coin age in the unit of cent-seconds nCoinAge = 0; @@ -4915,15 +4939,17 @@ bool GetCoinAge(const CTransaction& tx, const CCoinsViewCache &view, uint64_t& n if (!g_txindex) return false; // Transaction index not available + unsigned int nTime = tx.nTime; + for (const auto& txin : tx.vin) { // First try finding the previous transaction in database const COutPoint &prevout = txin.prevout; Coin coin; - if (isTrueCoinAge && !view.GetCoin(prevout, coin)) + if (!view.GetCoin(prevout, coin)) continue; // previous transaction not in main chain - if (nTimeTx < coin.nTime) + if (nTime < coin.nTime) return false; // Transaction timestamp violation CDiskTxPos postx; @@ -4951,25 +4977,18 @@ bool GetCoinAge(const CTransaction& tx, const CCoinsViewCache &view, uint64_t& n if (txPrev->GetHash() != prevout.hash) return error("%s() : txid mismatch in GetCoinAge()", __PRETTY_FUNCTION__); - if (header.GetBlockTime() + Params().GetConsensus().nStakeMinAge > nTimeTx) + if (header.GetBlockTime() + Params().GetConsensus().nStakeMinAge > nTime) continue; // only count coins meeting min age requirement int64_t nValueIn = txPrev->vout[txin.prevout.n].nValue; - int nEffectiveAge = nTimeTx-(txPrev->nTime ? txPrev->nTime : header.GetBlockTime()); - - if (!isTrueCoinAge || IsProtocolV09(nTimeTx)) - nEffectiveAge = std::min(nEffectiveAge, 365 * 24 * 60 * 60); - - bnCentSecond += arith_uint256(nValueIn) * nEffectiveAge / CENT; - - if (gArgs.GetBoolArg("-printcoinage", false)) - LogPrintf("coin age nValueIn=%-12lld nTimeDiff=%d bnCentSecond=%s\n", nValueIn, nEffectiveAge, bnCentSecond.ToString()); + bnCentSecond += arith_uint256(nValueIn) * (nTime - txPrev->nTime) / CENT; } arith_uint256 bnCoinDay = bnCentSecond * CENT / COIN / (24 * 60 * 60); if (gArgs.GetBoolArg("-printcoinage", false)) LogPrintf("coin age bnCoinDay=%s\n", bnCoinDay.ToString()); nCoinAge = bnCoinDay.GetLow64(); + return true; } diff --git a/src/validation.h b/src/validation.h index 54eed72a71..0bb3cc6b43 100644 --- a/src/validation.h +++ b/src/validation.h @@ -1222,9 +1222,9 @@ bool DeploymentEnabled(const ChainstateManager& chainman, DEP dep) using FopenFn = std::function; // peercoin: -CAmount GetProofOfWorkReward(unsigned int nBits, uint32_t nTime); -CAmount GetProofOfStakeReward(int64_t nCoinAge, uint32_t nTime, uint64_t nMoneySupply); -bool GetCoinAge(const CTransaction& tx, const CCoinsViewCache &view, uint64_t& nCoinAge, unsigned int nTimeTx, bool isTrueCoinAge = true); // peercoin: get transaction coin age +CAmount GetProofOfWorkReward(int nHeight, int64_t nFees); +CAmount GetProofOfStakeReward(int nHeight, CAmount nFees); +bool GetCoinAge(const CTransaction& tx, const CCoinsViewCache &view, uint64_t& nCoinAge); bool SignBlock(CBlock& block, const CWallet& keystore); bool CheckBlockSignature(const CBlock& block); diff --git a/src/version.h b/src/version.h index 1cef31228f..f37c3527b1 100644 --- a/src/version.h +++ b/src/version.h @@ -9,14 +9,14 @@ * network protocol versioning */ -static const int PROTOCOL_VERSION = 70017; -static const int OLD_VERSION = 70014; // peercoin: used to communicate with clients that don't know how to send PoS information in headers +static const int PROTOCOL_VERSION = 60066; +static const int OLD_VERSION = PROTOCOL_VERSION; //! initial proto version, to be increased after version/verack negotiation static const int INIT_PROTO_VERSION = 209; //! disconnect from peers older than this proto version -static const int MIN_PEER_PROTO_VERSION = 70016; +static const int MIN_PEER_PROTO_VERSION = PROTOCOL_VERSION; //! BIP 0031, pong message, is enabled for all versions AFTER this one static const int BIP0031_VERSION = 60000; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index b5537f1a2c..fb1ed55996 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3760,14 +3760,9 @@ bool CWallet::CreateCoinStake(ChainstateManager& chainman, const CWallet* pwalle vwtxPrev.push_back(tx); } } - // Calculate coin age reward - { - uint64_t nCoinAge; - CCoinsViewCache view(&chainman.ActiveChainstate().CoinsTip()); - if (!GetCoinAge((const CTransaction)txNew, view, nCoinAge, txNew.nTime, true)) - return error("CreateCoinStake : failed to calculate coin age"); - CAmount nReward = GetProofOfStakeReward(nCoinAge, txNew.nTime, chainman.ActiveChain().Tip()->nMoneySupply); + { + CAmount nReward = GetProofOfStakeReward(chainman.ActiveChain().Tip()->nHeight, 0); // Refuse to create mint that has zero or negative reward if(nReward <= 0) { return false;