From 9e93196396462302d640ba28b09adf0bcdb2d601 Mon Sep 17 00:00:00 2001 From: Jordan Earls Date: Fri, 25 Aug 2017 01:15:40 -0400 Subject: [PATCH 1/9] Use UTXO set and ChainState instead of txindex for checking PoS stakes --- src/pos.cpp | 91 +++++++++++++++++++++++-------------------- src/pos.h | 9 ++--- src/script/sign.cpp | 5 ++- src/script/sign.h | 3 +- src/wallet/wallet.cpp | 2 +- 5 files changed, 59 insertions(+), 51 deletions(-) diff --git a/src/pos.cpp b/src/pos.cpp index 7ad419161a8f2..720a839993b2f 100644 --- a/src/pos.cpp +++ b/src/pos.cpp @@ -51,9 +51,9 @@ uint256 ComputeStakeModifier(const CBlockIndex* pindexPrev, const uint256& kerne // quantities so as to generate blocks faster, degrading the system back into // a proof-of-work situation. // -bool CheckStakeKernelHash(CBlockIndex* pindexPrev, unsigned int nBits, const CBlockHeader& blockFrom, unsigned int nTxPrevOffset, CAmount prevoutValue, const COutPoint& prevout, unsigned int nTimeBlock, uint256& hashProofOfStake, uint256& targetProofOfStake, bool fPrintProofOfStake) +bool CheckStakeKernelHash(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t blockFromTime, CAmount prevoutValue, const COutPoint& prevout, unsigned int nTimeBlock, uint256& hashProofOfStake, uint256& targetProofOfStake, bool fPrintProofOfStake) { - if (nTimeBlock < blockFrom.nTime) // Transaction timestamp violation + if (nTimeBlock < blockFromTime) // Transaction timestamp violation return error("CheckStakeKernelHash() : nTime violation"); // Base target @@ -72,14 +72,14 @@ bool CheckStakeKernelHash(CBlockIndex* pindexPrev, unsigned int nBits, const CBl // Calculate hash CDataStream ss(SER_GETHASH, 0); ss << nStakeModifier; - ss << blockFrom.nTime << prevout.hash << prevout.n << nTimeBlock; + ss << blockFromTime << prevout.hash << prevout.n << nTimeBlock; hashProofOfStake = Hash(ss.begin(), ss.end()); if (fPrintProofOfStake) { LogPrintf("CheckStakeKernelHash() : check modifier=%s nTimeBlockFrom=%u nPrevout=%u nTimeBlock=%u hashProof=%s\n", nStakeModifier.GetHex().c_str(), - blockFrom.nTime, prevout.n, nTimeBlock, + blockFromTime, prevout.n, nTimeBlock, hashProofOfStake.ToString()); } @@ -91,7 +91,7 @@ bool CheckStakeKernelHash(CBlockIndex* pindexPrev, unsigned int nBits, const CBl { LogPrintf("CheckStakeKernelHash() : check modifier=%s nTimeBlockFrom=%u nPrevout=%u nTimeBlock=%u hashProof=%s\n", nStakeModifier.GetHex().c_str(), - blockFrom.nTime, prevout.n, nTimeBlock, + blockFromTime, prevout.n, nTimeBlock, hashProofOfStake.ToString()); } @@ -107,27 +107,24 @@ bool CheckProofOfStake(CBlockIndex* pindexPrev, CValidationState& state, const C // Kernel (input 0) must match the stake hash target (nBits) const CTxIn& txin = tx.vin[0]; - // First try finding the previous transaction in database - CMutableTransaction txPrev; - CDiskTxPos txindex; - if (!ReadFromDisk(txPrev, txindex, *pblocktree, txin.prevout)) - return state.DoS(1, error("CheckProofOfStake() : INFO: read txPrev failed")); // previous transaction not in main chain, may occur during initial download + CCoins coinsPrev; + if(!pcoinsTip->GetCoins(txin.prevout.hash, coinsPrev)){ + return false; + } + + if(pindexPrev->nHeight-coinsPrev.nHeight < COINBASE_MATURITY){ + return false; + } + CBlockIndex* blockFrom = pindexPrev->GetAncestor(coinsPrev.nHeight); + if(!blockFrom) { + return false; + } // Verify signature - if (!VerifySignature(txPrev, tx, 0, SCRIPT_VERIFY_NONE)) + if (!VerifySignature(coinsPrev, txin.prevout.hash, tx, 0, SCRIPT_VERIFY_NONE)) return state.DoS(100, error("CheckProofOfStake() : VerifySignature failed on coinstake %s", tx.GetHash().ToString())); - // Read block header - CBlockHeader blockFrom; - if (!ReadFromDisk(blockFrom, txindex.nFile, txindex.nPos)) - return fDebug? error("CheckProofOfStake() : read block failed") : false; // unable to read block of previous transaction - - // Min age requirement - int nDepth; - if (IsConfirmedInNPrevBlocks(txindex, pindexPrev, COINBASE_MATURITY - 1, nDepth)) - return state.DoS(100, error("CheckProofOfStake() : tried to stake at depth %d", nDepth + 1)); - - if (!CheckStakeKernelHash(pindexPrev, nBits, blockFrom, txindex.nTxOffset - txindex.nPos, txPrev.vout[txin.prevout.n].nValue, txin.prevout, nTimeBlock, hashProofOfStake, targetProofOfStake, fDebug)) + if (!CheckStakeKernelHash(pindexPrev, nBits, blockFrom->nTime, coinsPrev.vout[txin.prevout.n].nValue, txin.prevout, nTimeBlock, hashProofOfStake, targetProofOfStake, fDebug)) return state.DoS(1, error("CheckProofOfStake() : INFO: check kernel failed on coinstake %s, hashProof=%s", tx.GetHash().ToString(), hashProofOfStake.ToString())); // may occur during initial download or if behind on block chain sync return true; @@ -151,44 +148,53 @@ bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBloc auto it=cache.find(prevout); if(it == cache.end()) { //not found in cache (shouldn't happen during staking, only during verification which does not use cache) - CMutableTransaction txPrev; - CDiskTxPos txindex; - if (!ReadFromDisk(txPrev, txindex, *pblocktree, prevout)) + CCoins coinsPrev; + if(!pcoinsTip->GetCoins(prevout.hash, coinsPrev)){ return false; + } - // Read block header - CBlockHeader block; - if (!ReadFromDisk(block, txindex.nFile, txindex.nPos)) + if(pindexPrev->nHeight-coinsPrev.nHeight < COINBASE_MATURITY){ return false; - - int nDepth; - if (IsConfirmedInNPrevBlocks(txindex, pindexPrev, COINBASE_MATURITY - 1, nDepth)) + } + CBlockIndex* blockFrom = pindexPrev->GetAncestor(coinsPrev.nHeight); + if(!blockFrom) { return false; + } - return CheckStakeKernelHash(pindexPrev, nBits, block, txindex.nTxOffset - txindex.nPos, txPrev.vout[prevout.n].nValue, prevout, + return CheckStakeKernelHash(pindexPrev, nBits, blockFrom->nTime, coinsPrev.vout[prevout.n].nValue, prevout, nTimeBlock, hashProofOfStake, targetProofOfStake); }else{ //found in cache const CStakeCache& stake = it->second; - return CheckStakeKernelHash(pindexPrev, nBits, stake.blockFrom, stake.txindex.nTxOffset - stake.txindex.nPos, stake.amount, prevout, - nTimeBlock, hashProofOfStake, targetProofOfStake); + if(CheckStakeKernelHash(pindexPrev, nBits, stake.blockFromTime, stake.amount, prevout, + nTimeBlock, hashProofOfStake, targetProofOfStake)){ + //Cache could potentially cause false positive stakes in the event of deep reorgs, so check without cache also + return CheckKernel(pindexPrev, nBits, nTimeBlock, prevout); + } } + return false; } -void CacheKernel(std::map& cache, const COutPoint& prevout){ +void CacheKernel(std::map& cache, const COutPoint& prevout, CBlockIndex* pindexPrev){ if(cache.find(prevout) != cache.end()){ //already in cache return; } - CMutableTransaction txPrev; - CDiskTxPos txindex; - if (!ReadFromDisk(txPrev, txindex, *pblocktree, prevout)) + + CCoins coinsPrev; + if(!pcoinsTip->GetCoins(prevout.hash, coinsPrev)){ return; - // Read block header - CBlockHeader block; - if (!ReadFromDisk(block, txindex.nFile, txindex.nPos)) + } + + if(pindexPrev->nHeight-coinsPrev.nHeight < COINBASE_MATURITY){ return; - CStakeCache c(block, txindex, txPrev.vout[prevout.n].nValue); + } + CBlockIndex* blockFrom = pindexPrev->GetAncestor(coinsPrev.nHeight); + if(!blockFrom) { + return; + } + + CStakeCache c(blockFrom->nTime, coinsPrev.vout[prevout.n].nValue); cache.insert({prevout, c}); } @@ -212,5 +218,6 @@ void CacheKernel(std::map& cache, const COutPoint& prevo + diff --git a/src/pos.h b/src/pos.h index c50f78a3e98eb..cdfed371b1e3b 100644 --- a/src/pos.h +++ b/src/pos.h @@ -21,21 +21,20 @@ static const uint32_t STAKE_TIMESTAMP_MASK = 15; struct CStakeCache{ - CStakeCache(CBlockHeader blockFrom_, CDiskTxPos txindex_, CAmount amount_) : blockFrom(blockFrom_), txindex(txindex_), amount(amount_){ + CStakeCache(uint32_t blockFromTime_, CAmount amount_) : blockFromTime(blockFromTime_), amount(amount_){ } - CBlockHeader blockFrom; - CDiskTxPos txindex; + uint32_t blockFromTime; CAmount amount; }; -void CacheKernel(std::map& cache, const COutPoint& prevout); +void CacheKernel(std::map& cache, const COutPoint& prevout, CBlockIndex* pindexPrev); // Compute the hash modifier for proof-of-stake uint256 ComputeStakeModifier(const CBlockIndex* pindexPrev, const uint256& kernel); // Check whether stake kernel meets hash target // Sets hashProofOfStake on success return -bool CheckStakeKernelHash(CBlockIndex* pindexPrev, unsigned int nBits, const CBlockHeader& blockFrom, unsigned int nTxPrevOffset, CAmount prevoutAmount, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, uint256& targetProofOfStake, bool fPrintProofOfStake=false); +bool CheckStakeKernelHash(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t blockFromTime, CAmount prevoutAmount, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, uint256& targetProofOfStake, bool fPrintProofOfStake=false); // Check kernel hash target and coinstake signature // Sets hashProofOfStake on success return diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 05e077f58f0b8..60cdbb57497a2 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -11,6 +11,7 @@ #include "primitives/transaction.h" #include "script/standard.h" #include "uint256.h" +#include "coins.h" #include @@ -228,7 +229,7 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutab return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType); } -bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, unsigned int flags) +bool VerifySignature(const CCoins& txFrom, const uint256 txFromHash, const CTransaction& txTo, unsigned int nIn, unsigned int flags) { TransactionSignatureChecker checker(&txTo, nIn, 0); @@ -237,7 +238,7 @@ bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsig return false; const CTxOut& txout = txFrom.vout[txin.prevout.n]; - if (txin.prevout.hash != txFrom.GetHash()) + if (txin.prevout.hash != txFromHash) return false; return VerifyScript(txin.scriptSig, txout.scriptPubKey, NULL, flags, checker); diff --git a/src/script/sign.h b/src/script/sign.h index d18e0208c625f..521bead47e016 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -7,6 +7,7 @@ #define BITCOIN_SCRIPT_SIGN_H #include "script/interpreter.h" +#include "coins.h" class CKeyID; class CKeyStore; @@ -73,7 +74,7 @@ bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& script /** Produce a script signature for a transaction. */ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType); bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType); -bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsigned int nIn, unsigned int flags); +bool VerifySignature(const CCoins& txFrom, uint256 txFromHash, const CTransaction& txTo, unsigned int nIn, unsigned int flags); /** Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 placeholders. */ SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const SignatureData& scriptSig1, const SignatureData& scriptSig2); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index a3919f9ee58a1..f79524767e93f 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3177,7 +3177,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, con { boost::this_thread::interruption_point(); COutPoint prevoutStake = COutPoint(pcoin.first->GetHash(), pcoin.second); - CacheKernel(stakeCache, prevoutStake); //this will do a 2 disk loads per op + CacheKernel(stakeCache, prevoutStake, pindexPrev); //this will do a 2 disk loads per op } } int64_t nCredit = 0; From 0e52ff6775c6ea1adf0c189682938b368dda1d67 Mon Sep 17 00:00:00 2001 From: Jordan Earls Date: Wed, 6 Sep 2017 18:35:05 +0800 Subject: [PATCH 2/9] Propogate coin view from ConnectBlock for caching benefits --- src/miner.cpp | 2 +- src/pos.cpp | 25 +++++++++++++------------ src/pos.h | 8 ++++---- src/validation.cpp | 20 ++++++++++---------- src/wallet/wallet.cpp | 4 ++-- 5 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 2bd5d6a8b3481..8fcebdbaf7102 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1039,7 +1039,7 @@ bool CheckStake(const std::shared_ptr pblock, CWallet& wallet) // verify hash target and signature of coinstake tx CValidationState state; - if (!CheckProofOfStake(mapBlockIndex[pblock->hashPrevBlock], state, *pblock->vtx[1], pblock->nBits, pblock->nTime, proofHash, hashTarget)) + if (!CheckProofOfStake(mapBlockIndex[pblock->hashPrevBlock], state, *pblock->vtx[1], pblock->nBits, pblock->nTime, proofHash, hashTarget, *pcoinsTip)) return error("CheckStake() : proof-of-stake checking failed"); //// debug print diff --git a/src/pos.cpp b/src/pos.cpp index 720a839993b2f..ad3bf4b4abe76 100644 --- a/src/pos.cpp +++ b/src/pos.cpp @@ -99,7 +99,7 @@ bool CheckStakeKernelHash(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t } // Check kernel hash target and coinstake signature -bool CheckProofOfStake(CBlockIndex* pindexPrev, CValidationState& state, const CTransaction& tx, unsigned int nBits, uint32_t nTimeBlock, uint256& hashProofOfStake, uint256& targetProofOfStake) +bool CheckProofOfStake(CBlockIndex* pindexPrev, CValidationState& state, const CTransaction& tx, unsigned int nBits, uint32_t nTimeBlock, uint256& hashProofOfStake, uint256& targetProofOfStake, CCoinsViewCache& view) { if (!tx.IsCoinStake()) return error("CheckProofOfStake() : called on non-coinstake %s", tx.GetHash().ToString()); @@ -108,11 +108,11 @@ bool CheckProofOfStake(CBlockIndex* pindexPrev, CValidationState& state, const C const CTxIn& txin = tx.vin[0]; CCoins coinsPrev; - if(!pcoinsTip->GetCoins(txin.prevout.hash, coinsPrev)){ + if(!view.GetCoins(txin.prevout.hash, coinsPrev)){ return false; } - if(pindexPrev->nHeight-coinsPrev.nHeight < COINBASE_MATURITY){ + if(pindexPrev->nHeight + 1 - coinsPrev.nHeight < COINBASE_MATURITY){ return false; } CBlockIndex* blockFrom = pindexPrev->GetAncestor(coinsPrev.nHeight); @@ -137,23 +137,24 @@ bool CheckCoinStakeTimestamp(uint32_t nTimeBlock) } -bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBlock, const COutPoint& prevout){ +bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBlock, const COutPoint& prevout, CCoinsViewCache& view) +{ std::map tmp; - return CheckKernel(pindexPrev, nBits, nTimeBlock, prevout, tmp); + return CheckKernel(pindexPrev, nBits, nTimeBlock, prevout, view, tmp); } -bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBlock, const COutPoint& prevout, const std::map& cache) +bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBlock, const COutPoint& prevout, CCoinsViewCache& view, const std::map& cache) { uint256 hashProofOfStake, targetProofOfStake; auto it=cache.find(prevout); if(it == cache.end()) { //not found in cache (shouldn't happen during staking, only during verification which does not use cache) CCoins coinsPrev; - if(!pcoinsTip->GetCoins(prevout.hash, coinsPrev)){ + if(!view.GetCoins(prevout.hash, coinsPrev)){ return false; } - if(pindexPrev->nHeight-coinsPrev.nHeight < COINBASE_MATURITY){ + if(pindexPrev->nHeight + 1 - coinsPrev.nHeight < COINBASE_MATURITY){ return false; } CBlockIndex* blockFrom = pindexPrev->GetAncestor(coinsPrev.nHeight); @@ -169,24 +170,24 @@ bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBloc if(CheckStakeKernelHash(pindexPrev, nBits, stake.blockFromTime, stake.amount, prevout, nTimeBlock, hashProofOfStake, targetProofOfStake)){ //Cache could potentially cause false positive stakes in the event of deep reorgs, so check without cache also - return CheckKernel(pindexPrev, nBits, nTimeBlock, prevout); + return CheckKernel(pindexPrev, nBits, nTimeBlock, prevout, view); } } return false; } -void CacheKernel(std::map& cache, const COutPoint& prevout, CBlockIndex* pindexPrev){ +void CacheKernel(std::map& cache, const COutPoint& prevout, CBlockIndex* pindexPrev, CCoinsViewCache& view){ if(cache.find(prevout) != cache.end()){ //already in cache return; } CCoins coinsPrev; - if(!pcoinsTip->GetCoins(prevout.hash, coinsPrev)){ + if(!view.GetCoins(prevout.hash, coinsPrev)){ return; } - if(pindexPrev->nHeight-coinsPrev.nHeight < COINBASE_MATURITY){ + if(pindexPrev->nHeight + 1 - coinsPrev.nHeight < COINBASE_MATURITY){ return; } CBlockIndex* blockFrom = pindexPrev->GetAncestor(coinsPrev.nHeight); diff --git a/src/pos.h b/src/pos.h index cdfed371b1e3b..acbf007e36125 100644 --- a/src/pos.h +++ b/src/pos.h @@ -27,7 +27,7 @@ struct CStakeCache{ CAmount amount; }; -void CacheKernel(std::map& cache, const COutPoint& prevout, CBlockIndex* pindexPrev); +void CacheKernel(std::map& cache, const COutPoint& prevout, CBlockIndex* pindexPrev, CCoinsViewCache& view); // Compute the hash modifier for proof-of-stake uint256 ComputeStakeModifier(const CBlockIndex* pindexPrev, const uint256& kernel); @@ -38,7 +38,7 @@ bool CheckStakeKernelHash(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t // Check kernel hash target and coinstake signature // Sets hashProofOfStake on success return -bool CheckProofOfStake(CBlockIndex* pindexPrev, CValidationState& state, const CTransaction& tx, unsigned int nBits, uint32_t nTimeBlock, uint256& hashProofOfStake, uint256& targetProofOfStake); +bool CheckProofOfStake(CBlockIndex* pindexPrev, CValidationState& state, const CTransaction& tx, unsigned int nBits, uint32_t nTimeBlock, uint256& hashProofOfStake, uint256& targetProofOfStake, CCoinsViewCache& view); // Check whether the coinstake timestamp meets protocol bool CheckCoinStakeTimestamp(uint32_t nTimeBlock); @@ -46,7 +46,7 @@ bool CheckCoinStakeTimestamp(uint32_t nTimeBlock); // Wrapper around CheckStakeKernelHash() // Also checks existence of kernel input and min age // Convenient for searching a kernel -bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBlock, const COutPoint& prevout); -bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBlock, const COutPoint& prevout, const std::map& cache); +bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBlock, const COutPoint& prevout, CCoinsViewCache& view); +bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBlock, const COutPoint& prevout, CCoinsViewCache& view, const std::map& cache); #endif // QUANTUM_POS_H diff --git a/src/validation.cpp b/src/validation.cpp index 600a9eb8fb326..05750686137d1 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -105,7 +105,7 @@ CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE; CTxMemPool mempool(::minRelayTxFee); static void CheckBlockIndex(const Consensus::Params& consensusParams); -static bool UpdateHashProof(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex* pindex); +static bool UpdateHashProof(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex* pindex, CCoinsViewCache& view); /** Constant stuff for coinbase transactions we create: */ CScript COINBASE_FLAGS; @@ -1253,7 +1253,7 @@ bool CheckHeaderPoS(const CBlockHeader& block, const Consensus::Params& consensu // Check the kernel hash CBlockIndex* pindexPrev = (*mi).second; - return CheckKernel(pindexPrev, block.nBits, block.StakeTime(), block.prevoutStake); + return CheckKernel(pindexPrev, block.nBits, block.StakeTime(), block.prevoutStake, *pcoinsTip); } bool CheckHeaderProof(const CBlockHeader& block, const Consensus::Params& consensusParams){ @@ -2422,11 +2422,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin uint64_t countCumulativeGasUsed = 0; ///////////////////////////////////////////////// - // State is filled in by UpdateHashProof - if (!UpdateHashProof(block, state, chainparams.GetConsensus(), pindex)) { - return error("%s: ConnectBlock(): %s", __func__, state.GetRejectReason().c_str()); - } - // Move this check from CheckBlock to ConnectBlock as it depends on DGP values if (block.vtx.empty() || block.vtx.size() > dgpMaxBlockSize || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) > dgpMaxBlockSize) // qtum return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false, "size limits failed"); @@ -2452,6 +2447,11 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return true; } + // State is filled in by UpdateHashProof + if (!UpdateHashProof(block, state, chainparams.GetConsensus(), pindex, view)) { + return error("%s: ConnectBlock(): %s", __func__, state.GetRejectReason().c_str()); + } + bool fScriptChecks = true; if (!hashAssumeValid.IsNull()) { // We've been configured with the hash of a block which has been externally verified to have a valid history. @@ -4224,7 +4224,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co } -static bool UpdateHashProof(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex* pindex) +static bool UpdateHashProof(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex* pindex, CCoinsViewCache& view) { int nHeight = pindex->nHeight; uint256 hash = block.GetHash(); @@ -4246,7 +4246,7 @@ static bool UpdateHashProof(const CBlock& block, CValidationState& state, const if (block.IsProofOfStake()) { uint256 targetProofOfStake; - if (!CheckProofOfStake(pindex->pprev, state, *block.vtx[1], block.nBits, block.nTime, hashProof, targetProofOfStake)) + if (!CheckProofOfStake(pindex->pprev, state, *block.vtx[1], block.nBits, block.nTime, hashProof, targetProofOfStake, view)) { return error("UpdateHashProof() : check proof-of-stake failed for block %s", hash.ToString()); } @@ -4347,7 +4347,7 @@ static bool AcceptBlock(const std::shared_ptr& pblock, CValidation return false; if(block.IsProofOfWork()) { - if (!UpdateHashProof(block, state, chainparams.GetConsensus(), pindex)) + if (!UpdateHashProof(block, state, chainparams.GetConsensus(), pindex, *pcoinsTip)) { return error("%s: AcceptBlock(): %s", __func__, state.GetRejectReason().c_str()); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index f79524767e93f..6a90dc417e12b 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3177,7 +3177,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, con { boost::this_thread::interruption_point(); COutPoint prevoutStake = COutPoint(pcoin.first->GetHash(), pcoin.second); - CacheKernel(stakeCache, prevoutStake, pindexPrev); //this will do a 2 disk loads per op + CacheKernel(stakeCache, prevoutStake, pindexPrev, *pcoinsTip); //this will do a 2 disk loads per op } } int64_t nCredit = 0; @@ -3189,7 +3189,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, con // Search backward in time from the given txNew timestamp // Search nSearchInterval seconds back up to nMaxStakeSearchInterval COutPoint prevoutStake = COutPoint(pcoin.first->GetHash(), pcoin.second); - if (CheckKernel(pindexPrev, nBits, nTimeBlock, prevoutStake, stakeCache)) + if (CheckKernel(pindexPrev, nBits, nTimeBlock, prevoutStake, *pcoinsTip, stakeCache)) { // Found a kernel LogPrint("coinstake", "CreateCoinStake : kernel found\n"); From f3256b64eee7e01daf4128dcf71e365a2fa6b538 Mon Sep 17 00:00:00 2001 From: Jordan Earls Date: Thu, 7 Sep 2017 10:47:38 +0800 Subject: [PATCH 3/9] Add new stake index database --- src/txdb.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++++++ src/txdb.h | 6 +++++ src/validation.cpp | 9 +++++-- src/validation.h | 1 + 4 files changed, 81 insertions(+), 2 deletions(-) diff --git a/src/txdb.cpp b/src/txdb.cpp index 5cb2cd1bacd8d..a9fbfda010865 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -22,6 +22,7 @@ static const char DB_BLOCK_INDEX = 'b'; ////////////////////////////////////////// // qtum static const char DB_HEIGHTINDEX = 'h'; +static const char DB_STAKEINDEX = 's'; ////////////////////////////////////////// static const char DB_BEST_BLOCK = 'B'; @@ -250,6 +251,72 @@ bool CBlockTreeDB::WipeHeightIndex() { return WriteBatch(batch); } + + +bool CBlockTreeDB::WriteStakeIndex(unsigned int height, uint256 txid) { + CDBBatch batch(*this); + batch.Write(std::make_pair(DB_STAKEINDEX, height), txid); + return WriteBatch(batch); +} + +bool CBlockTreeDB::ReadStakeIndex(unsigned int height, uint256& txid){ + boost::scoped_ptr pcursor(NewIterator()); + + pcursor->Seek(std::make_pair(DB_STAKEINDEX, height)); + + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + std::pair key; + if (pcursor->GetKey(key) && key.first == DB_STAKEINDEX) { + pcursor->GetValue(txid); + return true; + }else{ + return false; + } + } + return false; +} +bool CBlockTreeDB::ReadStakeIndex(unsigned int high, unsigned int low, std::vector txids){ + boost::scoped_ptr pcursor(NewIterator()); + + pcursor->Seek(std::make_pair(DB_STAKEINDEX, low)); + + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + std::pair key; + if (pcursor->GetKey(key) && key.first == DB_STAKEINDEX && key.second.height < high) { + uint256 value; + pcursor->GetValue(value); + txids.push_back(value); + pcursor->Next(); + } else { + break; + } + } + + return true; +} + +bool CBlockTreeDB::EraseStakeIndex(unsigned int height) { + + boost::scoped_ptr pcursor(NewIterator()); + CDBBatch batch(*this); + + pcursor->Seek(std::make_pair(DB_STAKEINDEX, height)); + + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + std::pair key; + if (pcursor->GetKey(key) && key.first == DB_HEIGHTINDEX && key.second.height == height) { + batch.Erase(key); + pcursor->Next(); + } else { + break; + } + } + + return WriteBatch(batch); +} /////////////////////////////////////////////////////// bool CBlockTreeDB::LoadBlockIndexGuts(boost::function insertBlockIndex) diff --git a/src/txdb.h b/src/txdb.h index cc4c1a382f1ec..c00e320dd861f 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -127,6 +127,12 @@ class CBlockTreeDB : public CDBWrapper bool EraseHeightIndex(const unsigned int &height); bool WipeHeightIndex(); + + bool WriteStakeIndex(unsigned int height, uint256 txid); + bool ReadStakeIndex(unsigned int height, uint256& txid); + bool ReadStakeIndex(unsigned int high, unsigned int low, std::vector txids); + bool EraseStakeIndex(unsigned int height); + ////////////////////////////////////////////////////////////////////////////// }; diff --git a/src/validation.cpp b/src/validation.cpp index 05750686137d1..5903c637cfcb7 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1261,7 +1261,7 @@ bool CheckHeaderProof(const CBlockHeader& block, const Consensus::Params& consen return CheckHeaderPoW(block, consensusParams); } if(block.IsProofOfStake()){ - return CheckHeaderPoS(block, consensusParams); + return true; // CheckHeaderPoS(block, consensusParams); } return false; } @@ -1878,6 +1878,7 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI storageRes.deleteResults(block.vtx); pblocktree->EraseHeightIndex(pindex->nHeight); } + pblocktree->EraseStakeIndex(pindex->nHeight); if (pfClean) { *pfClean = fClean; @@ -2900,7 +2901,11 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return AbortNode(state, "Failed to write height index"); } } - + if(block.IsProofOfStake()){ + pblocktree->WriteStakeIndex(pindex->nHeight, block.vtx[1]->GetHash()); + }else{ + pblocktree->WriteStakeIndex(pindex->nHeight, block.vtx[0]->GetHash()); + } if (fTxIndex) if (!pblocktree->WriteTxIndex(vPos)) return AbortNode(state, "Failed to write transaction index"); diff --git a/src/validation.h b/src/validation.h index 8234aa8485ef9..27fb0b048c352 100644 --- a/src/validation.h +++ b/src/validation.h @@ -440,6 +440,7 @@ struct CHeightTxIndexKey { address.clear(); } }; + //////////////////////////////////////////////////////////// /** Get the block height at which the BIP9 deployment switched into the state for the block building on the current tip. */ From 1a24495f96889762c2681a37dbfa1ab826395843 Mon Sep 17 00:00:00 2001 From: Jordan Earls Date: Thu, 7 Sep 2017 14:58:59 +0800 Subject: [PATCH 4/9] Store address in stakeindex instead of txid, fix several bugs --- src/txdb.cpp | 20 ++++++++++--------- src/txdb.h | 6 +++--- src/validation.cpp | 45 +++++++++++-------------------------------- src/wallet/wallet.cpp | 17 +++++----------- 4 files changed, 30 insertions(+), 58 deletions(-) diff --git a/src/txdb.cpp b/src/txdb.cpp index a9fbfda010865..2c6fe6c3d9b18 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -253,13 +253,13 @@ bool CBlockTreeDB::WipeHeightIndex() { } -bool CBlockTreeDB::WriteStakeIndex(unsigned int height, uint256 txid) { +bool CBlockTreeDB::WriteStakeIndex(unsigned int height, uint160 address) { CDBBatch batch(*this); - batch.Write(std::make_pair(DB_STAKEINDEX, height), txid); + batch.Write(std::make_pair(DB_STAKEINDEX, height), address); return WriteBatch(batch); } -bool CBlockTreeDB::ReadStakeIndex(unsigned int height, uint256& txid){ +bool CBlockTreeDB::ReadStakeIndex(unsigned int height, uint160& address){ boost::scoped_ptr pcursor(NewIterator()); pcursor->Seek(std::make_pair(DB_STAKEINDEX, height)); @@ -267,8 +267,9 @@ bool CBlockTreeDB::ReadStakeIndex(unsigned int height, uint256& txid){ while (pcursor->Valid()) { boost::this_thread::interruption_point(); std::pair key; - if (pcursor->GetKey(key) && key.first == DB_STAKEINDEX) { - pcursor->GetValue(txid); + pcursor->GetKey(key); //note: it's apparently ok if this returns an error https://github.com/bitcoin/bitcoin/issues/7890 + if (key.first == DB_STAKEINDEX) { + pcursor->GetValue(address); return true; }else{ return false; @@ -276,7 +277,7 @@ bool CBlockTreeDB::ReadStakeIndex(unsigned int height, uint256& txid){ } return false; } -bool CBlockTreeDB::ReadStakeIndex(unsigned int high, unsigned int low, std::vector txids){ +bool CBlockTreeDB::ReadStakeIndex(unsigned int high, unsigned int low, std::vector addresses){ boost::scoped_ptr pcursor(NewIterator()); pcursor->Seek(std::make_pair(DB_STAKEINDEX, low)); @@ -284,10 +285,11 @@ bool CBlockTreeDB::ReadStakeIndex(unsigned int high, unsigned int low, std::vect while (pcursor->Valid()) { boost::this_thread::interruption_point(); std::pair key; - if (pcursor->GetKey(key) && key.first == DB_STAKEINDEX && key.second.height < high) { - uint256 value; + pcursor->GetKey(key); //note: it's apparently ok if this returns an error https://github.com/bitcoin/bitcoin/issues/7890 + if (key.first == DB_STAKEINDEX && key.second.height < high) { + uint160 value; pcursor->GetValue(value); - txids.push_back(value); + addresses.push_back(value); pcursor->Next(); } else { break; diff --git a/src/txdb.h b/src/txdb.h index c00e320dd861f..33408b62ca73d 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -128,9 +128,9 @@ class CBlockTreeDB : public CDBWrapper bool WipeHeightIndex(); - bool WriteStakeIndex(unsigned int height, uint256 txid); - bool ReadStakeIndex(unsigned int height, uint256& txid); - bool ReadStakeIndex(unsigned int high, unsigned int low, std::vector txids); + bool WriteStakeIndex(unsigned int height, uint160 address); + bool ReadStakeIndex(unsigned int height, uint160& address); + bool ReadStakeIndex(unsigned int high, unsigned int low, std::vector addresses); bool EraseStakeIndex(unsigned int height); ////////////////////////////////////////////////////////////////////////////// diff --git a/src/validation.cpp b/src/validation.cpp index 5903c637cfcb7..5bfc9bf41785c 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1261,7 +1261,7 @@ bool CheckHeaderProof(const CBlockHeader& block, const Consensus::Params& consen return CheckHeaderPoW(block, consensusParams); } if(block.IsProofOfStake()){ - return true; // CheckHeaderPoS(block, consensusParams); + return CheckHeaderPoS(block, consensusParams); } return false; } @@ -2041,10 +2041,6 @@ bool CheckReward(const CBlock& block, CValidationState& state, int nHeight, cons } else { - // Check proof-of-stake timestamp - if (!CheckTransactionTimestamp(*block.vtx[offset], block.nTime, *pblocktree)) - return error("CheckReward() : %s transaction timestamp check failure", block.vtx[offset]->GetHash().ToString()); - // Check full reward CAmount blockReward = nFees + GetBlockSubsidy(nHeight, consensusParams); if (nActualStakeReward > blockReward) @@ -2902,9 +2898,17 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } } if(block.IsProofOfStake()){ - pblocktree->WriteStakeIndex(pindex->nHeight, block.vtx[1]->GetHash()); + // Read the public key from the second output + std::vector vchPubKey; + if(GetBlockPublicKey(block, vchPubKey)) + { + uint160 pkh = uint160(ToByteVector(CPubKey(vchPubKey).GetID())); + pblocktree->WriteStakeIndex(pindex->nHeight, pkh); + }else{ + pblocktree->WriteStakeIndex(pindex->nHeight, uint160()); + } }else{ - pblocktree->WriteStakeIndex(pindex->nHeight, block.vtx[0]->GetHash()); + pblocktree->WriteStakeIndex(pindex->nHeight, uint160()); } if (fTxIndex) if (!pblocktree->WriteTxIndex(vPos)) @@ -3609,33 +3613,6 @@ bool ResetBlockFailureFlags(CBlockIndex *pindex) { return true; } -bool CheckTransactionTimestamp(const CTransaction& tx, const uint32_t& nTimeBlock, CBlockTreeDB& txdb) -{ - if (tx.IsCoinBase()) - return true; - - BOOST_FOREACH(const CTxIn& txin, tx.vin) - { - // First try finding the previous transaction in database - CMutableTransaction txPrev; - CDiskTxPos txindex; - if (!ReadFromDisk(txPrev, txindex, txdb, txin.prevout)) - continue; // previous transaction not in main chain - - // Read block header - CBlockHeader blockFrom; - if (!ReadFromDisk(blockFrom, txindex.nFile, txindex.nPos)) - return false; // unable to read block of previous transaction - - if (nTimeBlock < blockFrom.nTime) - return false; // Transaction timestamp violation - - LogPrint("Transaction timestamp", "timestamp nTimeDiff=%d", nTimeBlock - blockFrom.nTime); - } - - return true; -} - CBlockIndex* AddToBlockIndex(const CBlockHeader& block) { // Check for duplicate diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 6a90dc417e12b..2f53ed670f7cf 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -166,19 +166,15 @@ bool AddMPoSScript(std::vector &mposScriptList, int nHeight, const Cons } // Read the block - CBlock block; - if (!ReadBlockFromDisk(block, pblockindex, consensusParams)) - { - LogPrint("coinstake", "Block read from disk failed\n"); + uint160 stakeAddress; + if(!pblocktree->ReadStakeIndex(nHeight, stakeAddress)){ return false; } // The block reward for PoS is in the second transaction (coinstake) and the second or third output - if(block.vtx.size() > 1 && block.vtx[1]->IsCoinStake() && block.vtx[1]->vout.size() > 1 ) + if(pblockindex->IsProofOfStake()) { - // Read the public key from the second output - std::vector vchPubKey; - if(!GetBlockPublicKey(block, vchPubKey)) + if(stakeAddress == uint160()) { LogPrint("coinstake", "Fail to solve script for mpos reward recipient\n"); //This should never fail, but in case it somehow did we don't want it to bring the network to a halt @@ -186,7 +182,7 @@ bool AddMPoSScript(std::vector &mposScriptList, int nHeight, const Cons script = CScript() << OP_RETURN; }else{ // Make public key hash script - script = CScript() << OP_DUP << OP_HASH160 << ToByteVector(CPubKey(vchPubKey).GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; + script = CScript() << OP_DUP << OP_HASH160 << ToByteVector(stakeAddress) << OP_EQUALVERIFY << OP_CHECKSIG; } // Add the script into the list @@ -3280,9 +3276,6 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, con int64_t nRewardPiece = 0; // Calculate reward { - if (!CheckTransactionTimestamp(txNew, nTimeBlock, *pblocktree)) - return error("CreateCoinStake : Transaction timestamp check failure."); - int64_t nReward = nTotalFees + GetBlockSubsidy(pindexPrev->nHeight, consensusParams); if (nReward < 0) return false; From 896a33b2288e5e8ddcefde2f9b3ecf69c91c8a94 Mon Sep 17 00:00:00 2001 From: Jordan Earls Date: Thu, 7 Sep 2017 15:05:21 +0800 Subject: [PATCH 5/9] Revert "Fixing issue #300 (by soft-disabling the -prune and -txindex flags)" This reverts commit bbc7530e3fbf8153c1f74f0529b48443f49c5498. --- src/init.cpp | 29 ----------------------------- src/qt/intro.cpp | 6 ------ src/validation.cpp | 6 ------ src/wallet/wallet.cpp | 4 ---- 4 files changed, 45 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 30707cb2a6418..f459a57553edf 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -354,22 +354,15 @@ std::string HelpMessage(HelpMessageMode mode) #ifndef WIN32 strUsage += HelpMessageOpt("-pid=", strprintf(_("Specify pid file (default: %s)"), BITCOIN_PID_FILENAME)); #endif -#if 0 -// *** The Qtum wallet currently requires txindex to be set/true. Therefore pruning is not allowed. -// *** TODO: Add support for pruning (while still maintaining txindex). strUsage += HelpMessageOpt("-prune=", strprintf(_("Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. " "Warning: Reverting this setting requires re-downloading the entire blockchain. " "(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >%u = automatically prune block files to stay under the specified target size in MiB)"), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024)); -#endif strUsage += HelpMessageOpt("-record-log-opcodes", strprintf(_("Logs all EVM LOG opcode operations to the file vmExecLogs.json"))); strUsage += HelpMessageOpt("-reindex-chainstate", _("Rebuild chain state from the currently indexed blocks")); strUsage += HelpMessageOpt("-reindex", _("Rebuild chain state and block index from the blk*.dat files on disk")); #ifndef WIN32 strUsage += HelpMessageOpt("-sysperms", _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)")); #endif -#if 0 -// *** The Qtum wallet currently requires txindex to be set/true. -// *** TODO: Add support for pruning (while still maintaining txindex). strUsage += HelpMessageOpt("-txindex", strprintf(_("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)"), DEFAULT_TXINDEX)); #endif strUsage += HelpMessageOpt("-logevents", strprintf(_("Maintain a full EVM log index, used by searchlogs and gettransactionreceipt rpc calls (default: %u)"), DEFAULT_LOGEVENTS)); @@ -451,13 +444,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-limitdescendantsize=", strprintf("Do not accept transactions if any ancestor would have more than kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT)); strUsage += HelpMessageOpt("-bip9params=deployment:start:end", "Use given start/end times for specified BIP9 deployment (regtest-only)"); } -#if 0 -// *** The Qtum wallet currently requires txindex to be set/true. Therefore pruning is not allowed. -// *** TODO: Add support for pruning (while still maintaining txindex) std::string debugCategories = "addrman, alert, bench, cmpctblock, coindb, db, http, libevent, lock, mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq"; // Don't translate these and qt below -#else - std::string debugCategories = "addrman, alert, bench, cmpctblock, coindb, db, http, libevent, lock, mempool, mempoolrej, net, proxy, rand, reindex, rpc, selectcoins, tor, zmq"; // Don't translate these and qt below -#endif if (mode == HMM_BITCOIN_QT) debugCategories += ", qt"; strUsage += HelpMessageOpt("-debug=", strprintf(_("Output debugging information (default: %u, supplying is optional)"), 0) + ". " + @@ -907,15 +894,11 @@ bool AppInitParameterInteraction() // also see: InitParameterInteraction() -#if 0 -// *** The Qtum wallet currently requires txindex to be set/true. Therefore pruning is not allowed. -// *** TODO: Add support for pruning (while still maintaining txindex). // if using block pruning, then disallow txindex if (GetArg("-prune", 0)) { if (GetBoolArg("-txindex", DEFAULT_TXINDEX)) return InitError(_("Prune mode is incompatible with -txindex.")); } -#endif // Make sure enough file descriptors are available int nBind = std::max( @@ -1001,14 +984,8 @@ bool AppInitParameterInteraction() else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS) nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS; -#if 0 -// *** The Qtum wallet currently requires txindex to be set/true. Therefore pruning is not allowed. -// *** TODO: Add support for pruning (while still maintaining txindex). // block pruning; get the amount of disk space (in MiB) to allot for block & undo files int64_t nPruneArg = GetArg("-prune", 0); -#else - int64_t nPruneArg = 0; -#endif if (nPruneArg < 0) { return InitError(_("Prune cannot be configured with a negative value.")); } @@ -1455,13 +1432,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greater than nMaxDbcache int64_t nBlockTreeDBCache = nTotalCache / 8; -#if 0 -// *** The Qtum wallet currently requires txindex to be set/true. -// *** TODO: Add support for pruning (while still maintaining txindex). nBlockTreeDBCache = std::min(nBlockTreeDBCache, (GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxBlockDBAndTxIndexCache : nMaxBlockDBCache) << 20); -#else - nBlockTreeDBCache = std::min(nBlockTreeDBCache, nMaxBlockDBAndTxIndexCache << 20); -#endif nTotalCache -= nBlockTreeDBCache; int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache nCoinDBCache = std::min(nCoinDBCache, nMaxCoinsDBCache << 20); // cap total coins db cache diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index 5e9724540ad80..ea5e3d8f9713c 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -124,13 +124,7 @@ Intro::Intro(QWidget *parent) : ui->setupUi(this); ui->welcomeLabel->setText(ui->welcomeLabel->text().arg(tr(PACKAGE_NAME))); ui->storageLabel->setText(ui->storageLabel->text().arg(tr(PACKAGE_NAME))); -#if 0 -// *** The Qtum wallet currently requires txindex to be set/true. Therefore pruning is not allowed. -// *** TODO: Add support for pruning (while still maintaining txindex). uint64_t pruneTarget = std::max(0, GetArg("-prune", 0)); -#else - uint64_t pruneTarget = 0; -#endif requiredSpace = BLOCK_CHAIN_SIZE; if (pruneTarget) { uint64_t prunedGBs = std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES); diff --git a/src/validation.cpp b/src/validation.cpp index 5bfc9bf41785c..152a68cbe6cf7 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -5093,14 +5093,8 @@ bool InitBlockIndex(const CChainParams& chainparams) if (chainActive.Genesis() != NULL) return true; -#if 0 -// *** The Qtum wallet currently requires txindex to be set/true. -// *** TODO: Add support for pruning (while still maintaining txindex). // Use the provided setting for -txindex in the new database fTxIndex = GetBoolArg("-txindex", DEFAULT_TXINDEX); -#else - fTxIndex = DEFAULT_TXINDEX; -#endif pblocktree->WriteFlag("txindex", fTxIndex); // Use the provided setting for -txindex in the new database diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 2f53ed670f7cf..06df20ea771de 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4432,12 +4432,8 @@ bool CWallet::ParameterInteraction() if (GetBoolArg("-sysperms", false)) return InitError("-sysperms is not allowed in combination with enabled wallet functionality"); -#if 0 -// *** The Qtum wallet currently requires txindex to be set/true. Therefore pruning is not allowed. -// *** TODO: Add support for pruning (while still maintaining txindex). if (GetArg("-prune", 0) && GetBoolArg("-rescan", false)) return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.")); -#endif if (::minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB) InitWarning(AmountHighWarn("-minrelaytxfee") + " " + From fa362cc0ceeac66e69662df856a6a434ecf25940 Mon Sep 17 00:00:00 2001 From: Jordan Earls Date: Thu, 7 Sep 2017 16:12:32 +0800 Subject: [PATCH 6/9] Add some error checking, fix bug, and disable txindex by default --- src/init.cpp | 1 - src/pos.cpp | 3 +++ src/validation.cpp | 10 +++++++--- src/validation.h | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index f459a57553edf..9bdb1551fa3af 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -364,7 +364,6 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-sysperms", _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)")); #endif strUsage += HelpMessageOpt("-txindex", strprintf(_("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)"), DEFAULT_TXINDEX)); -#endif strUsage += HelpMessageOpt("-logevents", strprintf(_("Maintain a full EVM log index, used by searchlogs and gettransactionreceipt rpc calls (default: %u)"), DEFAULT_LOGEVENTS)); strUsage += HelpMessageGroup(_("Connection options:")); diff --git a/src/pos.cpp b/src/pos.cpp index ad3bf4b4abe76..8fdf49c758a06 100644 --- a/src/pos.cpp +++ b/src/pos.cpp @@ -161,6 +161,9 @@ bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBloc if(!blockFrom) { return false; } + if(!coinsPrev.IsAvailable(prevout.n)){ + return false; + } return CheckStakeKernelHash(pindexPrev, nBits, blockFrom->nTime, coinsPrev.vout[prevout.n].nValue, prevout, nTimeBlock, hashProofOfStake, targetProofOfStake); diff --git a/src/validation.cpp b/src/validation.cpp index 152a68cbe6cf7..025595bf7dbae 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1326,8 +1326,12 @@ bool ReadBlockFromDisk(Block& block, const CDiskBlockPos& pos, const Consensus:: } // Check the header - if (!CheckHeaderProof(block, consensusParams)) - return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); + if(!block.IsProofOfStake()) { + //PoS blocks can be loaded out of order from disk, which makes PoS impossible to validate. So, do not validate their headers + //they will be validated later in CheckBlock and ConnectBlock anyway + if (!CheckHeaderProof(block, consensusParams)) + return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); + } return true; } @@ -2658,7 +2662,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return state.DoS(100, false, REJECT_INVALID, "bad-txns-invalid-sender-script"); } - QtumTxConverter convert(tx, NULL, &block.vtx); + QtumTxConverter convert(tx, &view, &block.vtx); ExtractQtumTX resultConvertQtumTX; if(!convert.extractionQtumTransactions(resultConvertQtumTX)){ diff --git a/src/validation.h b/src/validation.h index 27fb0b048c352..63f2e1890aadb 100644 --- a/src/validation.h +++ b/src/validation.h @@ -158,7 +158,7 @@ static const int64_t MAX_FEE_ESTIMATION_TIP_AGE = 3 * 60 * 60; /** Default for -permitbaremultisig */ static const bool DEFAULT_PERMIT_BAREMULTISIG = true; static const bool DEFAULT_CHECKPOINTS_ENABLED = true; -static const bool DEFAULT_TXINDEX = true; +static const bool DEFAULT_TXINDEX = false; static const bool DEFAULT_LOGEVENTS = false; static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100; From 0f6cb806115b36a1b2f5d17718f81455f67da5c1 Mon Sep 17 00:00:00 2001 From: Jordan Earls Date: Thu, 7 Sep 2017 18:03:18 +0800 Subject: [PATCH 7/9] Remove txindex usage from mempool since it does no rule checks anyway --- src/validation.cpp | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index 025595bf7dbae..513b92c19796a 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -842,24 +842,6 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C fSpendsCoinbase = true; break; } - - COutPoint prevout = txin.prevout; - CMutableTransaction txPrev; - std::shared_ptr ptx = mempool.get(prevout.hash); - if(ptx) - { - txPrev = *ptx; - } - else - { - CDiskTxPos txindex; - if (!ReadFromDisk(txPrev, txindex, *pblocktree, prevout)) - return state.DoS(100, error("%s : previous transaction not found", __func__), REJECT_INVALID, "bad-txns-not-found"); - } - - if (txPrev.vout[prevout.n].IsEmpty()) - return state.DoS(1, error("%s : special marker is not spendable", __func__), REJECT_INVALID, "bad-txns-not-spendable"); - } CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, dPriority, chainActive.Height(), From 397694a621afd8aac0ea107ef8f13d29b49e3f20 Mon Sep 17 00:00:00 2001 From: Jordan Earls Date: Thu, 7 Sep 2017 19:46:04 +0800 Subject: [PATCH 8/9] Replace false returns with DoS errors --- src/pos.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pos.cpp b/src/pos.cpp index 8fdf49c758a06..2a83ffcbcbc6c 100644 --- a/src/pos.cpp +++ b/src/pos.cpp @@ -102,22 +102,22 @@ bool CheckStakeKernelHash(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t bool CheckProofOfStake(CBlockIndex* pindexPrev, CValidationState& state, const CTransaction& tx, unsigned int nBits, uint32_t nTimeBlock, uint256& hashProofOfStake, uint256& targetProofOfStake, CCoinsViewCache& view) { if (!tx.IsCoinStake()) - return error("CheckProofOfStake() : called on non-coinstake %s", tx.GetHash().ToString()); + return error("CheckProofOfStake() : called on non-coinstake %s", tx.GetHash().ToString());s // Kernel (input 0) must match the stake hash target (nBits) const CTxIn& txin = tx.vin[0]; CCoins coinsPrev; if(!view.GetCoins(txin.prevout.hash, coinsPrev)){ - return false; + return state.DoS(100, error("CheckProofOfStake() : Stake prevout does not exist %s", txin.prevout.hash.ToString())); } if(pindexPrev->nHeight + 1 - coinsPrev.nHeight < COINBASE_MATURITY){ - return false; + return state.DoS(100, error("CheckProofOfStake() : Stake prevout is not mature, expecting %i and only matured to %i", COINBASE_MATURITY, pindexPrev->nHeight + 1 - coinsPrev.nHeight)); } CBlockIndex* blockFrom = pindexPrev->GetAncestor(coinsPrev.nHeight); if(!blockFrom) { - return false; + return state.DoS(100, error("CheckProofOfStake() : Block at height %i for prevout can not be loaded", coinsPrev.nHeight)); } // Verify signature From c2ddc52c5cc93130b81257e63b92679d32c8eae6 Mon Sep 17 00:00:00 2001 From: Jordan Earls Date: Thu, 7 Sep 2017 19:59:00 +0800 Subject: [PATCH 9/9] fix typo, remove base58.h from validation, add miner debug category --- src/init.cpp | 2 +- src/pos.cpp | 2 +- src/validation.cpp | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 9bdb1551fa3af..f7d53230f8c7d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -443,7 +443,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-limitdescendantsize=", strprintf("Do not accept transactions if any ancestor would have more than kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT)); strUsage += HelpMessageOpt("-bip9params=deployment:start:end", "Use given start/end times for specified BIP9 deployment (regtest-only)"); } - std::string debugCategories = "addrman, alert, bench, cmpctblock, coindb, db, http, libevent, lock, mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq"; // Don't translate these and qt below + std::string debugCategories = "addrman, alert, bench, cmpctblock, coindb, db, http, libevent, lock, mempool, mempoolrej, miner, net, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq"; // Don't translate these and qt below if (mode == HMM_BITCOIN_QT) debugCategories += ", qt"; strUsage += HelpMessageOpt("-debug=", strprintf(_("Output debugging information (default: %u, supplying is optional)"), 0) + ". " + diff --git a/src/pos.cpp b/src/pos.cpp index 2a83ffcbcbc6c..28ec0857b9f41 100644 --- a/src/pos.cpp +++ b/src/pos.cpp @@ -102,7 +102,7 @@ bool CheckStakeKernelHash(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t bool CheckProofOfStake(CBlockIndex* pindexPrev, CValidationState& state, const CTransaction& tx, unsigned int nBits, uint32_t nTimeBlock, uint256& hashProofOfStake, uint256& targetProofOfStake, CCoinsViewCache& view) { if (!tx.IsCoinStake()) - return error("CheckProofOfStake() : called on non-coinstake %s", tx.GetHash().ToString());s + return error("CheckProofOfStake() : called on non-coinstake %s", tx.GetHash().ToString()); // Kernel (input 0) must match the stake hash target (nBits) const CTxIn& txin = tx.vin[0]; diff --git a/src/validation.cpp b/src/validation.cpp index 513b92c19796a..e63035437d88c 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -40,7 +40,6 @@ #include "pubkey.h" #include "key.h" #include "wallet/wallet.h" -#include "base58.h" #include #include