From 8d43f1482a14263a76c039c227c4383580dcc1db Mon Sep 17 00:00:00 2001 From: CryptoManiac Date: Thu, 10 Jul 2014 22:22:22 +0400 Subject: [PATCH] Transactions verification update CheckBlock(): allow coinbase timestamp drift, add nonce checking for proof-of-stake. --- src/kernel.cpp | 7 ----- src/kernel.h | 3 -- src/main.cpp | 68 ++++++++++++++++++++++++++++++++++++++----------------- src/main.h | 2 +- src/miner.cpp | 5 +++- 5 files changed, 52 insertions(+), 33 deletions(-) diff --git a/src/kernel.cpp b/src/kernel.cpp index a0d1bdb..bd1cdf3 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -369,13 +369,6 @@ bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hash return true; } -// Check whether the coinstake timestamp meets protocol -bool CheckCoinStakeTimestamp(int64 nTimeBlock, int64 nTimeTx) -{ - // v0.3 protocol - return (nTimeBlock == nTimeTx); -} - // Get stake modifier checksum unsigned int GetStakeModifierChecksum(const CBlockIndex* pindex) { diff --git a/src/kernel.h b/src/kernel.h index dc2fbb0..00c7163 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -24,9 +24,6 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned // Sets hashProofOfStake on success return bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hashProofOfStake, uint256& targetProofOfStake); -// Check whether the coinstake timestamp meets protocol -bool CheckCoinStakeTimestamp(int64 nTimeBlock, int64 nTimeTx); - // Get stake modifier checksum unsigned int GetStakeModifierChecksum(const CBlockIndex* pindex); diff --git a/src/main.cpp b/src/main.cpp index e14b73e..090dd4b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -996,7 +996,7 @@ CBigNum inline GetProofOfStakeLimit(int nHeight, unsigned int nTime) } // miner's coin base reward based on nBits -int64 GetProofOfWorkReward(unsigned int nBits) +int64 GetProofOfWorkReward(unsigned int nBits, int64 nFees) { CBigNum bnSubsidyLimit = MAX_MINT_PROOF_OF_WORK; @@ -1031,7 +1031,7 @@ int64 GetProofOfWorkReward(unsigned int nBits) if (fDebug && GetBoolArg("-printcreation")) printf("GetProofOfWorkReward() : create=%s nBits=0x%08x nSubsidy=%"PRI64d"\n", FormatMoney(nSubsidy).c_str(), nBits, nSubsidy); - return min(nSubsidy, MAX_MINT_PROOF_OF_WORK); + return min(nSubsidy, MAX_MINT_PROOF_OF_WORK) + nFees; } // miner's coin stake reward based on nBits and coin age spent (coin-days) @@ -1638,6 +1638,8 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck) if (!CheckBlock(!fJustCheck, !fJustCheck, false)) return false; + bool fProtocol048 = fTestNet || VALIDATION_SWITCH_TIME < nTime; + // Do not allow blocks that contain transactions which 'overwrite' older transactions, // unless those are already completely spent. // If such overwrites are allowed, coinbases and transactions depending upon those @@ -1721,15 +1723,26 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck) mapQueuedChanges[hashTx] = CTxIndex(posThisTx, tx.vout.size()); } - // ppcoin: track money supply and mint amount info + if (IsProofOfWork()) + { + int64 nBlockReward = GetProofOfWorkReward(nBits, fProtocol048 ? nFees : 0); + + // Check coinbase reward + if (vtx[0].GetValueOut() > nBlockReward) + return error("CheckBlock() : coinbase reward exceeded (actual=%"PRI64d" vs calculated=%"PRI64d")", + vtx[0].GetValueOut(), + nBlockReward); + } + + // track money supply and mint amount info pindex->nMint = nValueOut - nValueIn + nFees; pindex->nMoneySupply = (pindex->pprev? pindex->pprev->nMoneySupply : 0) + nValueOut - nValueIn; if (!txdb.WriteBlockIndex(CDiskBlockIndex(pindex))) return error("Connect() : WriteBlockIndex for pindex failed"); - // ppcoin: fees are not collected by miners as in bitcoin - // ppcoin: fees are destroyed to compensate the entire network - if (fDebug && GetBoolArg("-printcreation")) + // fees are not collected by proof-of-stake miners + // fees are destroyed to compensate the entire network + if (fProtocol048 && fDebug && IsProofOfStake() && GetBoolArg("-printcreation")) printf("ConnectBlock() : destroy=%s nFees=%"PRI64d"\n", FormatMoney(nFees).c_str(), nFees); if (fJustCheck) @@ -2155,6 +2168,8 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) c if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) return DoS(100, error("CheckBlock() : size limits failed")); + bool fProtocol048 = fTestNet || VALIDATION_SWITCH_TIME < nTime; + // Check proof of work matches claimed amount if (fCheckPOW && IsProofOfWork() && !CheckProofOfWork(GetHash(), nBits)) return DoS(50, error("CheckBlock() : proof of work failed")); @@ -2166,16 +2181,38 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) c // First transaction must be coinbase, the rest must not be if (vtx.empty() || !vtx[0].IsCoinBase()) return DoS(100, error("CheckBlock() : first tx is not coinbase")); + + if (!fProtocol048) + { + // Check coinbase timestamp + if (GetBlockTime() < (int64)vtx[0].nTime) + return DoS(100, error("CheckBlock() : coinbase timestamp violation")); + } + else + { + // Check coinbase timestamp + if (GetBlockTime() < PastDrift((int64)vtx[0].nTime)) + return DoS(50, error("CheckBlock() : coinbase timestamp is too late")); + } + for (unsigned int i = 1; i < vtx.size(); i++) + { if (vtx[i].IsCoinBase()) return DoS(100, error("CheckBlock() : more than one coinbase")); - // Check coinbase timestamp - if (GetBlockTime() > FutureDrift((int64)vtx[0].nTime)) - return DoS(50, error("CheckBlock() : coinbase timestamp is too early")); + // Check transaction timestamp + if (GetBlockTime() < (int64)vtx[i].nTime) + return DoS(50, error("CheckBlock() : block timestamp earlier than transaction timestamp")); + } if (IsProofOfStake()) { + if (fProtocol048) + { + if (nNonce != 0) + return DoS(100, error("CheckBlock() : non-zero nonce in proof-of-stake block")); + } + // Coinbase output should be empty if proof-of-stake block if (vtx[0].vout.size() != 1 || !vtx[0].vout[0].IsEmpty()) return DoS(100, error("CheckBlock() : coinbase output not empty for proof-of-stake block")); @@ -2188,7 +2225,7 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) c return DoS(100, error("CheckBlock() : more than one coinstake")); // Check coinstake timestamp - if (!CheckCoinStakeTimestamp(GetBlockTime(), (int64)vtx[1].nTime)) + if (GetBlockTime() != (int64)vtx[1].nTime) return DoS(50, error("CheckBlock() : coinstake timestamp violation nTimeBlock=%"PRI64d" nTimeTx=%u", GetBlockTime(), vtx[1].nTime)); // NovaCoin: check proof-of-stake block signature @@ -2197,13 +2234,6 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) c } else { - int64 nReward = GetProofOfWorkReward(nBits); - // Check coinbase reward - if (vtx[0].GetValueOut() > nReward) - return DoS(50, error("CheckBlock() : coinbase reward exceeded (actual=%"PRI64d" vs calculated=%"PRI64d")", - vtx[0].GetValueOut(), - nReward)); - // Should we check proof-of-work block signature or not? // // * Always skip on TestNet @@ -2225,10 +2255,6 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) c { if (!tx.CheckTransaction()) return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed")); - - // ppcoin: check transaction timestamp - if (GetBlockTime() < (int64)tx.nTime) - return DoS(50, error("CheckBlock() : block timestamp earlier than transaction timestamp")); } // Check for duplicate txids. This is caught by ConnectInputs(), diff --git a/src/main.h b/src/main.h index 6b30019..84f93f7 100644 --- a/src/main.h +++ b/src/main.h @@ -113,7 +113,7 @@ bool LoadExternalBlockFile(FILE* fileIn); bool CheckProofOfWork(uint256 hash, unsigned int nBits); unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake); -int64 GetProofOfWorkReward(unsigned int nBits); +int64 GetProofOfWorkReward(unsigned int nBits, int64 nFees=0); int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTime, bool bCoinYearOnly=false); unsigned int ComputeMinWork(unsigned int nBase, int64 nTime); unsigned int ComputeMinStake(unsigned int nBase, int64 nTime, unsigned int nBlockTime); diff --git a/src/miner.cpp b/src/miner.cpp index 0038474..9926765 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -355,7 +355,10 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake) printf("CreateNewBlock(): total size %"PRI64u"\n", nBlockSize); if (!fProofOfStake) - pblock->vtx[0].vout[0].nValue = GetProofOfWorkReward(pblock->nBits); + { + bool fProtocol048 = fTestNet || VALIDATION_SWITCH_TIME < pblock->nTime; + pblock->vtx[0].vout[0].nValue = GetProofOfWorkReward(pblock->nBits, fProtocol048 ? nFees : 0); + } // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); -- 1.7.1