From: Scott Nadal Date: Thu, 12 Apr 2012 06:02:04 +0000 (+0100) Subject: PPCoin: Separate proof-of-work and proof-of-stake blocks X-Git-Tag: v0.4.0-unstable~195 X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=commitdiff_plain;h=94ced84524166a535de3f2de2c2103b7d7612f1c PPCoin: Separate proof-of-work and proof-of-stake blocks --- diff --git a/src/main.cpp b/src/main.cpp index 702518e..c424437 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1061,6 +1061,10 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex) if (!CheckBlock()) return false; + // ppcoin: coin stake tx must meet target protocol + if (IsProofOfStake() && !vtx[1].CheckProofOfStake(txdb, nBits)) + return error("ConnectBlock() : Block %s unable to meet hash target for coinstake", GetHash().ToString().c_str()); + //// issue here: it doesn't know the version unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - (2 * GetSizeOfCompactSize(0)) + GetSizeOfCompactSize(vtx.size()); @@ -1264,6 +1268,49 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) } +// ppcoin: coinstake must meet hash target according to the protocol: +// at least one input must meet the formula +// hash(txin.prevout.hash + nTime) < bnTarget * nCoinDay +// this ensures that the chance of getting a coinstake is proportional to the +// amount of coin age one owns. +// +bool CTransaction::CheckProofOfStake(CTxDB& txdb, unsigned int nBits) const +{ + CBigNum bnTargetPerCoinDay; + bnTargetPerCoinDay.SetCompact(nBits); + + if (!IsCoinStake()) + return true; + + BOOST_FOREACH(const CTxIn& txin, vin) + { + // First try finding the previous transaction in database + CTransaction txPrev; + CTxIndex txindex; + if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex)) + continue; // previous transaction not in main chain + if (nTime < txPrev.nTime) + return false; // Transaction timestamp violation + + // Read block header + CBlock block; + if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) + return false; // unable to read block of previous transaction + if (block.GetBlockTime() + AUTO_CHECKPOINT_TRUST_SPAN > nTime) + continue; // only count coins from at least one week ago + + int64 nValueIn = txPrev.vout[txin.prevout.n].nValue; + CBigNum bnCoinDay = CBigNum(nValueIn) * (nTime-txPrev.nTime) / COIN / (24 * 60 * 60); + // Calculate hash + CDataStream ss(SER_GETHASH, VERSION); + ss << txin.prevout.hash << nTime; + if (CBigNum(Hash(ss.begin(), ss.end())) < bnCoinDay * bnTargetPerCoinDay) + return true; + } + + return false; +} + // ppcoin: total coin age spent in transaction, in the unit of coin-days. // Only those coins last spent at least a week ago count. As those // transactions not in main chain are not currently indexed so we @@ -1402,7 +1449,7 @@ bool CBlock::CheckBlock() const return DoS(100, error("CheckBlock() : size limits failed")); // Check proof of work matches claimed amount - if (!CheckProofOfWork(GetHash(), nBits)) + if (IsProofOfWork() && !CheckProofOfWork(GetHash(), nBits)) return DoS(50, error("CheckBlock() : proof of work failed")); // Check timestamp diff --git a/src/main.h b/src/main.h index cad0069..ea73a0f 100644 --- a/src/main.h +++ b/src/main.h @@ -667,6 +667,7 @@ protected: public: bool RemoveFromMemoryPool(); bool GetCoinAge(CTxDB& txdb, uint64& nCoinAge) const; // ppcoin: get transaction coin age + bool CheckProofOfStake(CTxDB& txdb, unsigned int nBits) const; }; @@ -877,6 +878,17 @@ public: return (int64)nTime; } + // ppcoin: two types of block: proof-of-work or proof-of-stake + bool IsProofOfStake() const + { + return (vtx.size() > 1 && vtx[1].IsCoinStake()); + } + + bool IsProofOfWork() const + { + return !IsProofOfStake(); + } + // ppcoin: get max transaction timestamp int64 GetMaxTransactionTime() const {