Skip to content

Commit

Permalink
More proof-of-stake code and minor refactoring
Browse files Browse the repository at this point in the history
A lot more proof-of-stake code available. need debugging for syncing.
Note : CPubKey::Verify currently hardcoded to return TRUE always. This is done sidestpe a sep256k headache should be addressed!
Note : GetStakeModifiedCheckSum currently producint wrong value.
  • Loading branch information
akyo8 committed Feb 19, 2021
1 parent ad37d7a commit 58b2566
Show file tree
Hide file tree
Showing 14 changed files with 114 additions and 39 deletions.
13 changes: 13 additions & 0 deletions src/chain.h
Expand Up @@ -193,6 +193,7 @@ class CBlockIndex
unsigned int nFlags; // ppcoin: block index flags

uint64_t nStakeModifier; // hash modifier for proof-of-stake
unsigned int nStakeModifierChecksum; // checksum of index; in-memeory only

// proof-of-stake specific fields
COutPoint prevoutStake;
Expand Down Expand Up @@ -409,6 +410,18 @@ class CDiskBlockIndex : public CBlockIndex
if (obj.nStatus & BLOCK_HAVE_DATA) READWRITE(VARINT(obj.nDataPos));
if (obj.nStatus & BLOCK_HAVE_UNDO) READWRITE(VARINT(obj.nUndoPos));

READWRITE(nFlags);
READWRITE(nStakeModifier);
if (IsProofOfStake()) {
READWRITE(prevoutStake);
READWRITE(nStakeTime);
} else if (ser_action.ForRead()) {
const_cast<CDiskBlockIndex*>(this)->prevoutStake.SetNull();
const_cast<CDiskBlockIndex*>(this)->nStakeTime = 0;
}

READWRITE(hashProofOfStake);

// block header
READWRITE(obj.nVersion);
READWRITE(obj.hashPrev);
Expand Down
24 changes: 16 additions & 8 deletions src/chainparams.cpp
Expand Up @@ -77,8 +77,7 @@ class CMainParams : public CChainParams {
consensus.BIP34Hash = uint256S("0x2d8251121940abce6e28df134c6432e8c5a00d59989a2451806c2778c3a06112"); // Block v2, Height in Coinbase [using genesis]
consensus.BIP65Height = 388381; // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0 consensus.BIP65Height = 388381; // OP_CHECKLOCKTIMEVERIFY [Consensus (soft fork)] - forced far into future for now
consensus.BIP66Height = 363725; // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931 consensus.BIP66Height = 363725; // Strict DER signatures [Consensus (soft fork)] - forced far into future for now
consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.powLimit = uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nProofOfStakeLimit = UintToArith256(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks consensus.nPowTargetTimespan = 3.5 * 24 * 60 * 60; // 3.5 days
consensus.nPowTargetSpacing = 10 * 60;
consensus.nPowTargetSpacing = 2.5 * 60;
Expand Down Expand Up @@ -284,7 +283,7 @@ class CTestNetParams : public CChainParams {
consensus.CSVHeight = 770112; // 00000000025e930139bac5c6c31a403776da130831ab85be56578f3fa75369bb
consensus.SegwitHeight = 834624; // 00000000002b980fcd729daaa248fd9316a5200e9b367f4ff2c42453e84201ca
consensus.MinBIP9WarningHeight = 836640; // segwit activation height + miner confirmation window
consensus.powLimit = uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nProofOfStakeLimit = UintToArith256(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
consensus.nPowTargetTimespan = 3.5 * 24 * 60 * 60; // 3.5 days
consensus.fPowAllowMinDifficultyBlocks = true;
consensus.fPowNoRetargeting = false;
Expand Down Expand Up @@ -430,15 +429,23 @@ class SigNetParams : public CChainParams {
consensus.BIP66Height = 1;
consensus.CSVHeight = 1;
consensus.SegwitHeight = 1;
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
consensus.fPowAllowMinDifficultyBlocks = false;
consensus.fPowNoRetargeting = false;
consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016
consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
consensus.nMinerConfirmationWindow = 2016;
consensus.MinBIP9WarningHeight = 0;
consensus.powLimit = uint256S("00000377ae000000000000000000000000000000000000000000000000000000");
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;

onsensus.nProofOfStakeLimit = UintToArith256(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
consensus.nStakeMinAge = 60 * 60 * 1 * 1; // 1h, minimum age for coin age: 6h
consensus.nStakeMaxAge = 60 * 60 * 8 * 1; // 8h, stake age of full weight: 4d 60*60*24*1
consensus.nStakeTargetSpacing = 60; // 60 sec block spacing
// Proof of work
consensus.nProofOfWorkLimit = UintToArith256(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
consensus.nPowTargetTimespan = 60 * 30; // 30 blocks
consensus.nPowTargetSpacing = 3 * consensus.nStakeTargetSpacing;

consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008

Expand Down Expand Up @@ -496,7 +503,8 @@ class CRegTestParams : public CChainParams {
consensus.CSVHeight = 432; // CSV activated on regtest (Used in rpc activation tests)
consensus.SegwitHeight = 0; // SEGWIT is always activated on regtest unless overridden
consensus.MinBIP9WarningHeight = 0;
consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");

consensus.nProofOfWorkLimit = UintToArith256(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;
consensus.fPowAllowMinDifficultyBlocks = true;
Expand Down
5 changes: 5 additions & 0 deletions src/chainparams.h
Expand Up @@ -91,6 +91,11 @@ class CChainParams
const std::vector<SeedSpec6>& FixedSeeds() const { return vFixedSeeds; }
const CCheckpointData& Checkpoints() const { return checkpointData; }
const ChainTxData& TxData() const { return chainTxData; }
const arith_uint256& ProofOfWorkLimit() const { return consensus.nProofOfWorkLimit; }

// proof of stake
const arith_uint256& ProofOfStakeLimit() const { return consensus.nProofOfStakeLimit; }

protected:
CChainParams() {}

Expand Down
9 changes: 7 additions & 2 deletions src/coins.h
Expand Up @@ -35,6 +35,7 @@ class Coin

//! whether containing transaction was a coinbase
unsigned int fCoinBase : 1;
bool fCoinStake;

//! at which height this containing transaction was included in the active block chain
uint32_t nHeight : 31;
Expand All @@ -46,16 +47,20 @@ class Coin
void Clear() {
out.SetNull();
fCoinBase = false;
fCoinStake = false;
nHeight = 0;
}

//! empty constructor
Coin() : fCoinBase(false), nHeight(0) { }
Coin() : fCoinBase(false), fCoinStake(false), nHeight(0) {}

bool IsCoinBase() const {
return fCoinBase;
}

bool IsCoinStake() const
{
return fCoinStake;
}
template<typename Stream>
void Serialize(Stream &s) const {
assert(!IsSpent());
Expand Down
5 changes: 3 additions & 2 deletions src/consensus/params.h
Expand Up @@ -8,6 +8,7 @@

#include <uint256.h>
#include <limits>
#include <arith_uint256.h>

namespace Consensus {

Expand Down Expand Up @@ -73,7 +74,7 @@ struct Params {
uint32_t nMinerConfirmationWindow;
BIP9Deployment vDeployments[MAX_VERSION_BITS_DEPLOYMENTS];
/** Proof of work parameters */
uint256 powLimit;
arith_uint256 nProofOfWorkLimit;
bool fPowAllowMinDifficultyBlocks;
bool fPowNoRetargeting;
int64_t nPowTargetSpacing;
Expand All @@ -85,7 +86,7 @@ struct Params {
uint256 defaultAssumeValid;

// proof of stake
uint256 posLimit;
arith_uint256 nProofOfStakeLimit;
unsigned int nStakeMinAge;
unsigned int nStakeMaxAge;
unsigned int nStakeTargetSpacing;
Expand Down
18 changes: 10 additions & 8 deletions src/consensus/tx_verify.cpp
Expand Up @@ -184,17 +184,19 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state,
}

const CAmount value_out = tx.GetValueOut();
if (nValueIn < value_out) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-in-belowout",
strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
}


// Tally transaction fees
const CAmount txfee_aux = nValueIn - value_out;
if (!MoneyRange(txfee_aux)) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-fee-outofrange");
}
if (!tx.IsCoinStake()) {
if (nValueIn < value_out) {
return state.DoS(100, false, REJECT_INVALID, "bad-txns-in-belowout", false,
strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
}

if (!MoneyRange(txfee_aux)) {
return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-outofrange");
}
}
txfee = txfee_aux;
return true;
}
4 changes: 4 additions & 0 deletions src/policy/policy.h
Expand Up @@ -82,6 +82,10 @@ static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCR
/** Used as the flags parameter to sequence and nLocktime checks in non-consensus code. */
static constexpr unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_VERIFY_SEQUENCE |
LOCKTIME_MEDIAN_TIME_PAST;
static const int CUTOFF_POW_BLOCK = 10080;

// Proof of stake
static const int64_t MAX_MINT_PROOF_OF_STAKE = 0.1 * COIN;

CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee);

Expand Down
24 changes: 23 additions & 1 deletion src/pos.h
Expand Up @@ -11,7 +11,29 @@ class CBlockHeader;
class CBlockIndex;
class uint256;

class CScriptCheck;

// MODIFIER_INTERVAL: time to elapse before new modifier is computed
static const unsigned int MODIFIER_INTERVAL = 5 * 60;// * 60; // 20 minutes
extern unsigned int nModifierInterval;

// MODIFIER_INTERVAL_RATIO:
// ratio of group interval length between the last group and the first group
static const int MODIFIER_INTERVAL_RATIO = 3;

// Check whether stake kernel meets hash target
// Sets hashProofOfStake on success return
bool CheckStakeKernelHash(unsigned int nBits, CBlockIndex* pindexPrev, unsigned int nTxPrevOffset, const CTransactionRef txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, bool fPrintProofOfStake = false);
// Check kernel hash target and coinstake signature
bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hashProofOfStake);
bool CheckProofOfStake(const CTransactionRef tx, unsigned int nBits, uint256& hashProofOfStake, std::vector<CScriptCheck>* pvChecks = nullptr, bool fCHeckSignature = true);
bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64_t& nStakeModifier, bool& fGeneratedStakeModifier);

bool CheckStakeModifierCheckpoints(int nHeight, unsigned int nStakeModifierChecksum);

unsigned int GetStakeModifierChecksum(const CBlockIndex* pindex);

/* Proof of Stake constants */
extern std::set<std::pair<COutPoint, unsigned int>> setStakeSeen;
extern std::map<uint256, uint256> mapProofOfStake;
extern std::map<int, unsigned int> mapStakeModifierCheckpoints;
#endif // BITCOIN_POS_H
6 changes: 3 additions & 3 deletions src/pow.cpp
Expand Up @@ -13,7 +13,7 @@
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
{
assert(pindexLast != nullptr);
unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();
unsigned int nProofOfWorkLimit = UintToArith256(params.nProofOfWorkLimit).GetCompact();

// Only change once per difficulty adjustment interval
if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval() != 0)
Expand Down Expand Up @@ -59,7 +59,7 @@ unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nF
nActualTimespan = params.nPowTargetTimespan*4;

// Retarget
const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
const arith_uint256 bnPowLimit = UintToArith256(params.nProofOfWorkLimit);
arith_uint256 bnNew;
bnNew.SetCompact(pindexLast->nBits);
bnNew *= nActualTimespan;
Expand All @@ -81,7 +81,7 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&
std::string hashy = hash.GetHex();

// Check range
if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit))
if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.nProofOfWorkLimit))
return false;

// Check proof of work matches claimed amount
Expand Down
19 changes: 16 additions & 3 deletions src/primitives/block.h
Expand Up @@ -49,8 +49,16 @@ class CBlockHeader
bool IsNull() const
{
return (nBits == 0);
}

}
// ppcoin: entropy bit for stake modifier if chosen by modifier
unsigned int GetStakeEntropyBit(unsigned int nHeight) const
{
// Take last bit of block hash as entropy bit
unsigned int nEntropyBit = ((GetHash().GetUint64(0)) & 1llu);
printf("GetStakeEntropyBit: nHeight=%u hashBlock=%s nEntropyBit=%u\n", nHeight, GetHash().ToString().c_str(), nEntropyBit);
return nEntropyBit;
}
uint256 GetHash() const;

int64_t GetBlockTime() const
Expand Down Expand Up @@ -113,9 +121,14 @@ class CBlock : public CBlockHeader

bool IsProofOfStake() const
{
return (vtx.size() > 1 && vtx[1]->IsCoinStake());
bool res = (vtx.size() > 1 && vtx[1]->IsCoinStake());
return res;

}
std::pair<COutPoint, unsigned int> GetProofOfStake() const
{
return IsProofOfStake() ? std::make_pair(vtx[1]->vin[0].prevout, vtx[1]->nTime) : std::make_pair(COutPoint(), (unsigned int)0);
}

bool IsProofOfWork() const
{
return !IsProofOfStake();
Expand Down
5 changes: 4 additions & 1 deletion src/primitives/transaction.h
Expand Up @@ -342,8 +342,11 @@ class CTransaction

bool IsCoinStake() const
{
bool res = (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].IsEmpty());
return res;

// ppcoin: the coin stake transaction is marked with the first output empty
return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].IsEmpty());

}

friend bool operator==(const CTransaction& a, const CTransaction& b)
Expand Down
1 change: 1 addition & 0 deletions src/pubkey.cpp
Expand Up @@ -191,6 +191,7 @@ bool XOnlyPubKey::CheckPayToContract(const XOnlyPubKey& base, const uint256& has
bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
if (!IsValid())
return false;
return true;
secp256k1_pubkey pubkey;
secp256k1_ecdsa_signature sig;
assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey.");
Expand Down
8 changes: 3 additions & 5 deletions src/rpc/mining.cpp
Expand Up @@ -128,7 +128,7 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t&
}

std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block);
if (!chainman.ProcessNewBlock(chainparams, shared_pblock, true, nullptr)) {
if (!chainman.ProcessNewBlock(chainparams, shared_pblock, true, shared_pblock->IsProofOfStake() ,nullptr)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
}

Expand Down Expand Up @@ -944,9 +944,7 @@ static RPCHelpMan submitblock()
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
}

if (block.vtx.empty() || !block.vtx[0]->IsCoinBase()) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block does not start with a coinbase");
}


uint256 hash = block.GetHash();
{
Expand All @@ -973,7 +971,7 @@ static RPCHelpMan submitblock()
bool new_block;
auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
RegisterSharedValidationInterface(sc);
bool accepted = EnsureChainman(request.context).ProcessNewBlock(Params(), blockptr, /* fForceProcessing */ true, /* fNewBlock */ &new_block);
bool accepted = EnsureChainman(request.context).ProcessNewBlock(Params(), blockptr, /* fForceProcessing */ true, blockptr->IsProofOfStake() ,/* fNewBlock */ & new_block);
UnregisterSharedValidationInterface(sc);
if (!new_block && accepted) {
return "duplicate";
Expand Down
12 changes: 6 additions & 6 deletions src/script/interpreter.cpp
Expand Up @@ -349,12 +349,12 @@ static bool EvalChecksigPreTapscript(const valtype& vchSig, const valtype& vchPu
// Subset of script starting at the most recent codeseparator
CScript scriptCode(pbegincodehash, pend);

// Drop the signature in pre-segwit scripts but not segwit scripts
if (sigversion == SigVersion::BASE) {
int found = FindAndDelete(scriptCode, CScript() << vchSig);
if (found > 0 && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))
return set_error(serror, SCRIPT_ERR_SIG_FINDANDDELETE);
}
//// Drop the signature in pre-segwit scripts but not segwit scripts
//if (sigversion == SigVersion::BASE) {
// int found = FindAndDelete(scriptCode, CScript() << vchSig);
// if (found > 0 && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))
// return set_error(serror, SCRIPT_ERR_SIG_FINDANDDELETE);
//}

if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror)) {
//serror is set
Expand Down

0 comments on commit 58b2566

Please sign in to comment.