diff --git a/src/main.cpp b/src/main.cpp index 6d2a6719f..190366ebe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -968,8 +968,8 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) CAmount nValueOut = 0; BOOST_FOREACH(const CTxOut& txout, tx.vout) { - if (txout.IsEmpty() && !tx.IsCoinBase() && !tx.IsCoinStake()) - return state.DoS(100, error("CheckTransaction(): txout empty for user transaction")); + if (txout.IsEmpty() && !tx.IsCoinBase() && !tx.IsCoinStake()) + return state.DoS(100, error("CheckTransaction(): txout empty for user transaction")); if (txout.nValue < 0) return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative"); if (txout.nValue > MAX_MONEY) @@ -1076,7 +1076,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C // Coinstake is also only valid in a block, not as a loose transaction if (tx.IsCoinStake()) return state.DoS(100, error("AcceptToMemoryPool: coinstake as individual tx"), - REJECT_INVALID, "coinstake"); + REJECT_INVALID, "coinstake"); // Rather not work on nonstandard transactions (unless -testnet/-regtest) string reason; @@ -1098,7 +1098,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C // For the same reasons as in the case with non-final transactions if (tx.nTime > FutureDrift(GetAdjustedTime())) { - return state.DoS(0, false, REJECT_NONSTANDARD, "time-too-new"); + return state.DoS(0, false, REJECT_NONSTANDARD, "time-too-new"); } // is it already in the memory pool? @@ -1701,8 +1701,8 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus bool ReadFromDisk(CTransaction& tx, CDiskTxPos& txindex, CBlockTreeDB& txdb, COutPoint prevout) { if (!txdb.ReadTxIndex(prevout.hash, txindex)){ - LogPrintf("no tx index %s \n", prevout.hash.ToString()); - return false; + LogPrintf("no tx index %s \n", prevout.hash.ToString()); + return false; } if (!ReadFromDisk(tx, txindex)) return false; @@ -1735,7 +1735,7 @@ bool ReadFromDisk(CTransaction& tx, CDiskTxPos& txindex) CAmount GetProofOfWorkSubsidy() { - return 10000 * COIN; + return 10000 * COIN; } CAmount GetProofOfStakeSubsidy() @@ -1952,7 +1952,7 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach class CachingTransactionSignatureCheckerWithBlockReader : public CachingTransactionSignatureChecker, public BaseBlockReader { - typedef std::pair CoinbaseCacheItem; + typedef std::pair CoinbaseCacheItem; typedef boost::multi_index_container< CoinbaseCacheItem, boost::multi_index::indexed_by< @@ -1961,12 +1961,12 @@ class CachingTransactionSignatureCheckerWithBlockReader : public CachingTransact boost::multi_index::member > > - > CoinbaseCacheContainer; - + > CoinbaseCacheContainer; + int nHeight; uint256 hash; - - mutable boost::mutex mutexCache; + + mutable boost::mutex mutexCache; mutable CoinbaseCacheContainer cacheCoinbase; // block hash -> block coinbase void UpdateCache(const CoinbaseCacheItem& coinbase) const; @@ -2005,8 +2005,8 @@ CTransaction CachingTransactionSignatureCheckerWithBlockReader::GetBlockCoinbase return CTransaction(); CBlockIndex* pblockindex = chainActive[nHeight]; - - { + + { boost::lock_guard lock(mutexCache); CoinbaseCacheContainer::nth_index<1>::type::iterator it = cacheCoinbase.get<1>().find(*pblockindex->phashBlock); if (it != cacheCoinbase.get<1>().end()) @@ -2022,7 +2022,7 @@ CTransaction CachingTransactionSignatureCheckerWithBlockReader::GetBlockCoinbase CTransaction CachingTransactionSignatureCheckerWithBlockReader::ReadBlockCoinbase(CBlockIndex* pblockindex) const { - + CBlock block; if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) @@ -2100,7 +2100,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins // Check transaction timestamp if (coins->nTime > tx.nTime) return state.DoS(100, error("CheckInputs() : transaction timestamp earlier than input transaction"), - REJECT_INVALID, "bad-txns-time-earlier-than-input"); + REJECT_INVALID, "bad-txns-time-earlier-than-input"); // Check for negative or overflow input values nValueIn += coins->vout[prevout.n].nValue; @@ -2134,7 +2134,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi { if (!tx.IsCoinBase()) { - int height = GetSpendHeight(inputs); + int height = GetSpendHeight(inputs); if (!Consensus::CheckTxInputs(tx, state, inputs, height)) return false; @@ -2350,13 +2350,13 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), hash, k), CAddressUnspentValue())); } else if(out.scriptPubKey.IsPayToPublicKey()){ - uint160 uhashBytes = Hash160(out.scriptPubKey.begin()+1, out.scriptPubKey.begin()+34); + uint160 uhashBytes = Hash160(out.scriptPubKey.begin()+1, out.scriptPubKey.begin()+34); - // record receiving activity - addressIndex.push_back(make_pair(CAddressIndexKey(1, uhashBytes, pindex->nHeight, i, hash, k, false), out.nValue)); + // record receiving activity + addressIndex.push_back(make_pair(CAddressIndexKey(1, uhashBytes, pindex->nHeight, i, hash, k, false), out.nValue)); - // record unspent output - addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uhashBytes, hash, k), CAddressUnspentValue())); + // record unspent output + addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uhashBytes, hash, k), CAddressUnspentValue())); } else { continue; @@ -2425,13 +2425,13 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight, tx.nTime))); } else if(prevout.scriptPubKey.IsPayToPublicKey()){ - uint160 uhashBytes = Hash160(prevout.scriptPubKey.begin()+1, prevout.scriptPubKey.begin()+34); + uint160 uhashBytes = Hash160(prevout.scriptPubKey.begin()+1, prevout.scriptPubKey.begin()+34); - // record receiving activity - addressIndex.push_back(make_pair(CAddressIndexKey(1, uhashBytes, pindex->nHeight, i, hash, j, true), prevout.nValue * -1)); + // record receiving activity + addressIndex.push_back(make_pair(CAddressIndexKey(1, uhashBytes, pindex->nHeight, i, hash, j, true), prevout.nValue * -1)); - // record unspent output - addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uhashBytes, input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight, tx.nTime))); + // record unspent output + addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uhashBytes, input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight, tx.nTime))); } else { continue; @@ -2549,17 +2549,15 @@ static int64_t nTimeIndex = 0; static int64_t nTimeCallbacks = 0; static int64_t nTimeTotal = 0; -bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck) +bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck) { - const CChainParams& chainparams = Params(); - const uint256& hash = pindex->GetBlockHash(); AssertLockHeld(cs_main); int64_t nTimeStart = GetTimeMicros(); // Check it again in case a previous version let a bad block in - if (!CheckBlock(block, state, hash, !fJustCheck, !fJustCheck, !fJustCheck)) - return false; + if (!CheckBlock(block, state, chainparams.GetConsensus(), !fJustCheck, !fJustCheck, !fJustCheck)) + return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state)); // verify that the view's current state corresponds to the previous block uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash(); @@ -2567,17 +2565,16 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // Special case for the genesis block, skipping connection of its transactions // (its coinbase is unspendable) - if (hash == chainparams.GetConsensus().hashGenesisBlock) { - if (!fJustCheck) - view.SetBestBlock(pindex->GetBlockHash()); - return true; + if (block.GetHash() == chainparams.GetConsensus().hashGenesisBlock) { + if (!fJustCheck) + view.SetBestBlock(pindex->GetBlockHash()); + return true; } - // Check difficulty if (block.nBits != GetNextTargetRequired(pindex->pprev, &block, block.IsProofOfStake(), chainparams.GetConsensus())) - return state.DoS(100, error("%s: incorrect difficulty", __func__), - REJECT_INVALID, "bad-diffbits"); + return state.DoS(100, error("%s: incorrect difficulty", __func__), + REJECT_INVALID, "bad-diffbits"); pindex->nStakeModifier = ComputeStakeModifier(pindex->pprev, block.IsProofOfStake() ? block.vtx[1].vin[0].prevout.hash : pindex->GetBlockHash()); @@ -2589,7 +2586,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return state.DoS(100, error("%s: kernel input unavailable", __func__), REJECT_INVALID, "bad-cs-kernel"); - // Check proof-of-stake min confirmations + // Check proof-of-stake min confirmations if (pindex->nHeight - coins->nHeight < chainparams.GetConsensus().nStakeMinConfirmations) return state.DoS(100, error("%s: tried to stake at depth %d", __func__, pindex->nHeight - coins->nHeight), @@ -2658,13 +2655,12 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin flags |= SCRIPT_VERIFY_LOW_S; // Start enforcing CHECKLOCKTIMEVERIFY, (BIP65) since protocol v3 - if (block.GetBlockTime() > chainparams.GetConsensus().nProtocolV3Time) { flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; flags |= SCRIPT_VERIFY_NULLDUMMY; } - // Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic. +// Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic. // int nLockTimeFlags = 0; // if (VersionBitsState(pindex->pprev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE) { // flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; @@ -2679,7 +2675,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin std::vector prevheights; CAmount nFees = 0; - CAmount nActualStakeReward = 0; + CAmount nActualStakeReward = 0; int nInputs = 0; unsigned int nSigOps = 0; CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); @@ -2709,45 +2705,44 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (fAddressIndex || fSpentIndex) { - - for (size_t j = 0; j < tx.vin.size(); j++) { + for (size_t j = 0; j < tx.vin.size(); j++) { - const CTxIn input = tx.vin[j]; - const CTxOut &prevout = view.GetOutputFor(tx.vin[j]); - uint160 hashBytes; - int addressType; + const CTxIn input = tx.vin[j]; + const CTxOut &prevout = view.GetOutputFor(tx.vin[j]); + uint160 hashBytes; + int addressType; - if (prevout.scriptPubKey.IsPayToScriptHash()) { - hashBytes = uint160(vector (prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22)); - addressType = 2; - } else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) { - hashBytes = uint160(vector (prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23)); - addressType = 1; - } else if (prevout.scriptPubKey.IsPayToPublicKey()) { - hashBytes = Hash160(prevout.scriptPubKey.begin()+1, prevout.scriptPubKey.begin()+34); - addressType = 1; - } - else { - hashBytes.SetNull(); - addressType = 0; - } + if (prevout.scriptPubKey.IsPayToScriptHash()) { + hashBytes = uint160(vector (prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22)); + addressType = 2; + } else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) { + hashBytes = uint160(vector (prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23)); + addressType = 1; + } else if (prevout.scriptPubKey.IsPayToPublicKey()) { + hashBytes = Hash160(prevout.scriptPubKey.begin()+1, prevout.scriptPubKey.begin()+34); + addressType = 1; + } + else { + hashBytes.SetNull(); + addressType = 0; + } - if (fAddressIndex && addressType > 0) { + if (fAddressIndex && addressType > 0) { - // record spending activity - addressIndex.push_back(make_pair(CAddressIndexKey(addressType, hashBytes, pindex->nHeight, i, txhash, j, true), prevout.nValue * -1)); + // record spending activity + addressIndex.push_back(make_pair(CAddressIndexKey(addressType, hashBytes, pindex->nHeight, i, txhash, j, true), prevout.nValue * -1)); - // remove address from unspent index - addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(addressType, hashBytes, input.prevout.hash, input.prevout.n), CAddressUnspentValue())); - } + // remove address from unspent index + addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(addressType, hashBytes, input.prevout.hash, input.prevout.n), CAddressUnspentValue())); + } - if (fSpentIndex) { - // add the spent index to determine the txid and input that spent an output - // and to find the amount and address from an input - spentIndex.push_back(make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue(txhash, j, pindex->nHeight, prevout.nValue, addressType, hashBytes))); - } - } - + if (fSpentIndex) { + // add the spent index to determine the txid and input that spent an output + // and to find the amount and address from an input + spentIndex.push_back(make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue(txhash, j, pindex->nHeight, prevout.nValue, addressType, hashBytes))); + } + } + } if (fStrictPayToScriptHash) @@ -2761,8 +2756,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin REJECT_INVALID, "bad-blk-sigops"); } - if (tx.IsCoinStake()) - nActualStakeReward = tx.GetValueOut()-view.GetValueIn(tx); + if (tx.IsCoinStake()) + nActualStakeReward = tx.GetValueOut()-view.GetValueIn(tx); else nFees += view.GetValueIn(tx)-tx.GetValueOut(); @@ -2797,17 +2792,17 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uint160(hashBytes), txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight, tx.nTime))); } else if(out.scriptPubKey.IsPayToPublicKey()){ - uint160 uhashBytes = Hash160(out.scriptPubKey.begin()+1, out.scriptPubKey.begin()+34); + uint160 uhashBytes = Hash160(out.scriptPubKey.begin()+1, out.scriptPubKey.begin()+34); - // record receiving activity - addressIndex.push_back(make_pair(CAddressIndexKey(1, uhashBytes, pindex->nHeight, i, txhash, k, false), out.nValue)); + // record receiving activity + addressIndex.push_back(make_pair(CAddressIndexKey(1, uhashBytes, pindex->nHeight, i, txhash, k, false), out.nValue)); - // record unspent output - addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uhashBytes, txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight, tx.nTime))); + // record unspent output + addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(1, uhashBytes, txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight, tx.nTime))); - }else{ + } else { - continue; + continue; } @@ -2834,7 +2829,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin block.vtx[0].GetValueOut(), blockReward), REJECT_INVALID, "bad-cb-amount"); } - + if (block.IsProofOfStake() && block.GetBlockTime() > chainparams.GetConsensus().nProtocolV3Time) { CAmount blockReward = nFees + GetProofOfStakeSubsidy(); if (nActualStakeReward > blockReward) @@ -3182,7 +3177,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001); { CCoinsViewCache view(pcoinsTip); - bool rv = ConnectBlock(*pblock, state, pindexNew, view); + bool rv = ConnectBlock(*pblock, state, pindexNew, view, chainparams); GetMainSignals().BlockChecked(*pblock, state); if (!rv) { if (state.IsInvalid()) @@ -3395,14 +3390,14 @@ static void NotifyHeaderTip() { * or an activated best chain. pblock is either NULL or a pointer to a block * that is already loaded (to avoid loading it again from disk). */ -bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock, const uint256 *phash) { +bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock) { CBlockIndex *pindexMostWork = NULL; + CBlockIndex *pindexNewTip = NULL; do { boost::this_thread::interruption_point(); if (ShutdownRequested()) break; - CBlockIndex *pindexNewTip = NULL; const CBlockIndex *pindexFork; bool fInitialDownload; { @@ -3417,7 +3412,7 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, return true; bool fInvalidFound = false; - if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && (*phash) == pindexMostWork->GetBlockHash() ? pblock : NULL, fInvalidFound)) + if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL, fInvalidFound)) return false; if (fInvalidFound) { @@ -3561,57 +3556,58 @@ bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex) { // age (trust score) of competing branches. bool GetCoinAge(const CTransaction& tx, CBlockTreeDB& txdb, const CBlockIndex* pindexPrev, uint64_t& nCoinAge) { - arith_uint256 bnCentSecond = 0; // coin age in the unit of cent-seconds - nCoinAge = 0; + arith_uint256 bnCentSecond = 0; // coin age in the unit of cent-seconds + nCoinAge = 0; - if (tx.IsCoinBase()) - return true; + if (tx.IsCoinBase()) + return true; - BOOST_FOREACH(const CTxIn& txin, tx.vin) - { - // First try finding the previous transaction in database - CTransaction txPrev; - CDiskTxPos txindex; - if (!ReadFromDisk(txPrev, txindex, *pblocktree, txin.prevout)) - continue; // previous transaction not in main chain - if (tx.nTime < txPrev.nTime) - return false; // Transaction timestamp violation + BOOST_FOREACH(const CTxIn& txin, tx.vin) + { + // First try finding the previous transaction in database + CTransaction txPrev; + CDiskTxPos txindex; + if (!ReadFromDisk(txPrev, txindex, *pblocktree, txin.prevout)) + continue; // previous transaction not in main chain + if (tx.nTime < txPrev.nTime) + return false; // Transaction timestamp violation - if (Params().GetConsensus().IsProtocolV3(tx.nTime)) - { - int nSpendDepth; - if (IsConfirmedInNPrevBlocks(txindex, pindexPrev, Params().GetConsensus().nStakeMinConfirmations - 1, nSpendDepth)) - { - LogPrint("coinage", "coin age skip nSpendDepth=%d\n", nSpendDepth + 1); - continue; // only count coins meeting min confirmations requirement - } - } - else - { - // Read block header - CBlock block; - const CDiskBlockPos& pos = CDiskBlockPos(txindex.nFile, txindex.nPos); - if (!ReadBlockFromDisk(block, pos, Params().GetConsensus())) - return false; // unable to read block of previous transaction - if (block.GetBlockTime() + Params().GetConsensus().nStakeMinAge > tx.nTime) - continue; // only count coins meeting min age requirement - } + if (Params().GetConsensus().IsProtocolV3(tx.nTime)) + { + int nSpendDepth; + if (IsConfirmedInNPrevBlocks(txindex, pindexPrev, Params().GetConsensus().nStakeMinConfirmations - 1, nSpendDepth)) + { + LogPrint("coinage", "coin age skip nSpendDepth=%d\n", nSpendDepth + 1); + continue; // only count coins meeting min confirmations requirement + } + } + else + { + // Read block header + CBlock block; + const CDiskBlockPos& pos = CDiskBlockPos(txindex.nFile, txindex.nPos); + if (!ReadBlockFromDisk(block, pos, Params().GetConsensus())) + return false; // unable to read block of previous transaction + if (block.GetBlockTime() + Params().GetConsensus().nStakeMinAge > tx.nTime) + continue; // only count coins meeting min age requirement + } - int64_t nValueIn = txPrev.vout[txin.prevout.n].nValue; - bnCentSecond += arith_uint256(nValueIn) * (tx.nTime-txPrev.nTime) / CENT; + int64_t nValueIn = txPrev.vout[txin.prevout.n].nValue; + bnCentSecond += arith_uint256(nValueIn) * (tx.nTime-txPrev.nTime) / CENT; - LogPrint("coinage", "coin age nValueIn=%d nTimeDiff=%d bnCentSecond=%s\n", nValueIn, tx.nTime - txPrev.nTime, bnCentSecond.ToString()); - } + LogPrint("coinage", "coin age nValueIn=%d nTimeDiff=%d bnCentSecond=%s\n", nValueIn, tx.nTime - txPrev.nTime, bnCentSecond.ToString()); + } - arith_uint256 bnCoinDay = bnCentSecond * CENT / COIN / (24 * 60 * 60); - LogPrint("coinage", "coin age bnCoinDay=%s\n", bnCoinDay.ToString()); - nCoinAge = bnCoinDay.GetLow64(); - return true; + arith_uint256 bnCoinDay = bnCentSecond * CENT / COIN / (24 * 60 * 60); + LogPrint("coinage", "coin age bnCoinDay=%s\n", bnCoinDay.ToString()); + nCoinAge = bnCoinDay.GetLow64(); + return true; } -static CBlockIndex* AddToBlockIndex(const CBlockHeader& block, const uint256& hash) +static CBlockIndex* AddToBlockIndex(const CBlockHeader& block) { // Check for duplicate + uint256 hash = block.GetHash(); BlockMap::iterator it = mapBlockIndex.find(hash); if (it != mapBlockIndex.end()) return it->second; @@ -3645,8 +3641,8 @@ static CBlockIndex* AddToBlockIndex(const CBlockHeader& block, const uint256& ha /** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos) { - if (block.IsProofOfStake()) - pindexNew->SetProofOfStake(); + if (block.IsProofOfStake()) + pindexNew->SetProofOfStake(); pindexNew->nTx = block.vtx.size(); pindexNew->nChainTx = 0; pindexNew->nFile = pos.nFile; @@ -3778,7 +3774,7 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne return true; } -static bool CheckBlockSignature(const CBlock& block, const uint256& hash) +static bool CheckBlockSignature(const CBlock& block) { if (block.IsProofOfWork()) return block.vchBlockSig.empty(); @@ -3797,7 +3793,7 @@ static bool CheckBlockSignature(const CBlock& block, const uint256& hash) if (whichType == TX_PUBKEY) { vector& vchPubKey = vSolutions[0]; - return CPubKey(vchPubKey).Verify(hash, block.vchBlockSig); + return CPubKey(vchPubKey).Verify(block.GetHash(), block.vchBlockSig); } else { @@ -3809,6 +3805,8 @@ static bool CheckBlockSignature(const CBlock& block, const uint256& hash) opcodetype opcode; vector vchPushValue; + uint256 hash = block.GetHash(); + if (!script.GetOp(pc, opcode, vchPushValue)) return false; if (opcode != OP_RETURN) @@ -3823,26 +3821,21 @@ static bool CheckBlockSignature(const CBlock& block, const uint256& hash) return false; } -bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW) +bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW) { - if (block.nVersion < 7 && Params().GetConsensus().IsProtocolV2(block.GetBlockTime())) - return state.Invalid(error("%s: rejected nVersion=%d block", __func__, block.nVersion), - REJECT_OBSOLETE, "bad-version"); + if (block.nVersion < 7 && Params().GetConsensus().IsProtocolV2(block.GetBlockTime())) + return state.Invalid(error("%s: rejected nVersion=%d block", __func__, block.nVersion), + REJECT_OBSOLETE, "bad-version"); // Check proof of work matches claimed amount - if (fCheckPOW && !CheckProofOfWork(block.GetPoWHash(), block.nBits, Params().GetConsensus())) + if (fCheckPOW && !CheckProofOfWork(block.GetPoWHash(), block.nBits, consensusParams)) return state.DoS(50, error("CheckBlockHeader(): proof of work failed"), REJECT_INVALID, "high-hash"); - // Check timestamp - if (block.GetBlockTime() > FutureDrift(GetAdjustedTime())) - return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"), - REJECT_INVALID, "time-too-new"); - return true; } -bool CheckBlock(const CBlock& block, CValidationState& state, const uint256& hash, bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) +bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) { // These are checks that are independent of context. @@ -3851,7 +3844,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const uint256& has // Check that the header is valid (particularly PoW). This is mostly // redundant with the call in AcceptBlockHeader. - if (!CheckBlockHeader(block, state, block.IsProofOfWork())) + if (!CheckBlockHeader(block, state, consensusParams, block.IsProofOfWork())) return false; // Check the merkle root. @@ -3894,7 +3887,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const uint256& has // Check coinstake timestamp if (block.IsProofOfStake() && !CheckCoinStakeTimestamp(block.GetBlockTime(), block.vtx[1].nTime)) return state.DoS(50, error("CheckBlock(): coinstake timestamp violation nTimeBlock=%d nTimeTx=%u", block.GetBlockTime(), block.vtx[1].nTime), - REJECT_INVALID, "bad-cs-time"); + REJECT_INVALID, "bad-cs-time"); if (block.IsProofOfStake()) { @@ -3914,9 +3907,9 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const uint256& has } // Check proof-of-stake block signature - if (fCheckSig && !CheckBlockSignature(block, hash)) + if (fCheckSig && !CheckBlockSignature(block)) return state.DoS(100, error("CheckBlock(): bad proof-of-stake block signature"), - REJECT_INVALID, "bad-block-signature"); + REJECT_INVALID, "bad-block-signature"); // Check transactions BOOST_FOREACH(const CTransaction& tx, block.vtx){ @@ -3945,7 +3938,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const uint256& has return true; } -static bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidationState& state, const CChainParams& chainparams, const uint256& hash) +static bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidationState& state, const CChainParams& chainparams) { if (*pindexPrev->phashBlock == chainparams.GetConsensus().hashGenesisBlock) return true; @@ -3959,36 +3952,39 @@ static bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidati return true; } -bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev, const uint256& hash) +bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex * const pindexPrev) { - const Consensus::Params& consensusParams = Params().GetConsensus(); - if (hash == consensusParams.hashGenesisBlock) - return true; - - assert(pindexPrev); - - int nHeight = pindexPrev->nHeight+1; + uint256 hash = block.GetHash(); + if (hash == consensusParams.hashGenesisBlock) + return true; + assert(pindexPrev); + int nHeight = pindexPrev->nHeight+1; if (chainActive.Height() - nHeight >= consensusParams.nMaxReorganizationDepth) - return state.DoS(1, error("%s: forked chain older than max reorganization depth (height %d)", __func__, nHeight)); + return state.DoS(1, error("%s: forked chain older than max reorganization depth (height %d)", __func__, nHeight)); // Preliminary check difficulty in pos-only stage if (chainActive.Height() > consensusParams.nLastPOWBlock && nHeight > consensusParams.nLastPOWBlock && block.nBits != GetNextTargetRequired(pindexPrev, &block, true, consensusParams)) return state.DoS(100, error("%s: incorrect difficulty", __func__), - REJECT_INVALID, "bad-diffbits"); + REJECT_INVALID, "bad-diffbits"); // Preliminary check of pos timestamp if (nHeight > consensusParams.nLastPOWBlock && !CheckStakeBlockTimestamp(block.GetBlockTime())) return state.DoS(100, error("%s: incorrect pos block timestamp", __func__), - REJECT_INVALID, "bad-pos-time"); + REJECT_INVALID, "bad-pos-time"); // Check timestamp against prev if (block.GetBlockTime() <= pindexPrev->GetPastTimeLimit()) return state.Invalid(error("%s: block's timestamp is too early", __func__), REJECT_INVALID, "time-too-old"); + // Check timestamp + if (block.GetBlockTime() > FutureDrift(GetAdjustedTime())) + return state.Invalid(error("%s: block timestamp too far in the future", __func__), + REJECT_INVALID, "time-too-new"); + return true; } @@ -3998,7 +3994,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn const Consensus::Params& consensusParams = Params().GetConsensus(); if (block.IsProofOfWork() && nHeight > consensusParams.nLastPOWBlock) - return state.DoS(100, error("%s : reject proof-of-work at height %d", __func__, nHeight), REJECT_INVALID, "bad-pow-height"); + return state.DoS(100, error("%s : reject proof-of-work at height %d", __func__, nHeight), REJECT_INVALID, "bad-pow-height"); // Start enforcing BIP113 (Median Time Past) using versionbits logic. int nLockTimeFlags = 0; @@ -4013,7 +4009,6 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn } // Enforce rule that the coinbase starts with serialized block height - { CScript expect = CScript() << nHeight; if (block.vtx[0].vin[0].scriptSig.size() < expect.size() || @@ -4025,10 +4020,11 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn return true; } -static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const uint256& hash, const CChainParams& chainparams, CBlockIndex** ppindex=NULL) +static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex=NULL) { AssertLockHeld(cs_main); // Check for duplicate + uint256 hash = block.GetHash(); BlockMap::iterator miSelf = mapBlockIndex.find(hash); CBlockIndex *pindex = NULL; if (hash != chainparams.GetConsensus().hashGenesisBlock) { @@ -4043,8 +4039,8 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state return true; } - if (!CheckBlockHeader(block, state)) - return false; + if (!CheckBlockHeader(block, state, chainparams.GetConsensus())) + return error("%s: Consensus::CheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); // Get prev block index CBlockIndex* pindexPrev = NULL; @@ -4056,17 +4052,17 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); assert(pindexPrev); - if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, hash)) + if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams)) return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str()); - if (!ContextualCheckBlockHeader(block, state, pindexPrev, hash)) + if (!ContextualCheckBlockHeader(block, state, chainparams.GetConsensus(), pindexPrev)) return false; } if (pindex == NULL) - pindex = AddToBlockIndex(block, hash); + pindex = AddToBlockIndex(block); if (pindex->nHeight > chainparams.GetConsensus().nLastPOWBlock) - pindex->SetProofOfStake(); + pindex->SetProofOfStake(); if (ppindex) *ppindex = pindex; @@ -4075,14 +4071,14 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state } /** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */ -static bool AcceptBlock(const CBlock& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, const uint256& hash) +static bool AcceptBlock(const CBlock& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp) { AssertLockHeld(cs_main); CBlockIndex *pindexDummy = NULL; CBlockIndex *&pindex = ppindex ? *ppindex : pindexDummy; - if (!AcceptBlockHeader(block, state, hash, chainparams, &pindex)) + if (!AcceptBlockHeader(block, state, chainparams, &pindex)) return false; // Try to process all requested blocks that we don't have, but only @@ -4106,7 +4102,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha if (fTooFarAhead) return true; // Block height is too high } - if ((!CheckBlock(block, state, hash)) || !ContextualCheckBlock(block, state, pindex->pprev)) { + if ((!CheckBlock(block, state, chainparams.GetConsensus())) || !ContextualCheckBlock(block, state, pindex->pprev)) { if (state.IsInvalid() && !state.CorruptionPossible()) { pindex->nStatus |= BLOCK_FAILED_VALID; setDirtyBlockIndex.insert(pindex); @@ -4160,7 +4156,7 @@ bool static IsCanonicalBlockSignature(const CBlock* pblock) return IsLowDERSignature(pblock->vchBlockSig, NULL, false); } -bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, const uint256& hash) +bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp) { if (!IsCanonicalBlockSignature(pblock)) { if (pfrom && pfrom->nVersion >= CANONICAL_BLOCK_SIG_VERSION) @@ -4171,12 +4167,12 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, c { LOCK(cs_main); - bool fRequested = MarkBlockAsReceived(hash); + bool fRequested = MarkBlockAsReceived(pblock->GetHash()); fRequested |= fForceProcessing; // Store to disk CBlockIndex *pindex = NULL; - bool ret = AcceptBlock(*pblock, state, chainparams, &pindex, fRequested, dbp, hash); + bool ret = AcceptBlock(*pblock, state, chainparams, &pindex, fRequested, dbp); if (pindex && pfrom) { mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId(); } @@ -4187,7 +4183,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, c NotifyHeaderTip(); - if (!ActivateBestChain(state, chainparams, pblock, &hash)) + if (!ActivateBestChain(state, chainparams, pblock)) return error("%s: ActivateBestChain failed", __func__); return true; @@ -4197,7 +4193,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, { AssertLockHeld(cs_main); assert(pindexPrev && pindexPrev == chainActive.Tip()); - if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, block.GetHash())) + if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams)) return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str()); CCoinsViewCache viewNew(pcoinsTip); @@ -4205,15 +4201,14 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, indexDummy.pprev = pindexPrev; indexDummy.nHeight = pindexPrev->nHeight + 1; - uint256 hash = block.GetHash(); // NOTE: CheckBlockHeader is called by CheckBlock - if (!ContextualCheckBlockHeader(block, state, pindexPrev, hash)) - return false; - if (!CheckBlock(block, state, hash, fCheckPOW, fCheckMerkleRoot)) - return false; + if (!ContextualCheckBlockHeader(block, state, chainparams.GetConsensus(), pindexPrev)) + return error("%s: Consensus::ContextualCheckBlockHeader: %s", __func__, FormatStateMessage(state)); + if (!CheckBlock(block, state, chainparams.GetConsensus(), fCheckPOW, fCheckMerkleRoot)) + return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state)); if (!ContextualCheckBlock(block, state, pindexPrev)) - return false; - if (!ConnectBlock(block, state, &indexDummy, viewNew, true)) + return error("%s: Consensus::ContextualCheckBlock: %s", __func__, FormatStateMessage(state)); + if (!ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true)) return false; assert(state.IsValid()); @@ -4558,8 +4553,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); // check level 1: verify block validity - uint256 hash = block.GetHash(); - if (nCheckLevel >= 1 && !CheckBlock(block, state, hash)) + if (nCheckLevel >= 1 && !CheckBlock(block, state, chainparams.GetConsensus())) return error("VerifyDB(): *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); // check level 2: verify undo validity if (nCheckLevel >= 2 && pindex) { @@ -4598,7 +4592,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, CBlock block; if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); - if (!ConnectBlock(block, state, pindex, coins)) + if (!ConnectBlock(block, state, pindex, coins, chainparams)) return error("VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); } } @@ -4682,7 +4676,6 @@ bool InitBlockIndex(const CChainParams& chainparams) if (!fReindex) { try { CBlock &block = const_cast(chainparams.GenesisBlock()); - const uint256& hash = chainparams.GetConsensus().hashGenesisBlock; // Start new block file unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); CDiskBlockPos blockPos; @@ -4691,10 +4684,10 @@ bool InitBlockIndex(const CChainParams& chainparams) return error("LoadBlockIndex(): FindBlockPos failed"); if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) return error("LoadBlockIndex(): writing genesis block to disk failed"); - CBlockIndex *pindex = AddToBlockIndex(block, hash); + CBlockIndex *pindex = AddToBlockIndex(block); if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) return error("LoadBlockIndex(): genesis block not accepted"); - if (!ActivateBestChain(state, chainparams, &block, &hash)) + if (!ActivateBestChain(state, chainparams, &block)) return error("LoadBlockIndex(): genesis block cannot be activated"); // Force a chainstate write so that when we VerifyDB in a moment, it doesn't check stale data return FlushStateToDisk(state, FLUSH_STATE_ALWAYS); @@ -4765,7 +4758,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) { LOCK(cs_main); CValidationState state; - if (AcceptBlock(block, state, chainparams, NULL, true, dbp, hash)) + if (AcceptBlock(block, state, chainparams, NULL, true, dbp)) nLoaded++; if (state.IsError()) break; @@ -4799,7 +4792,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB head.ToString()); LOCK(cs_main); CValidationState dummy; - if (AcceptBlock(block, dummy, chainparams, NULL, true, &it->second, hash)) + if (AcceptBlock(block, dummy, chainparams, NULL, true, &it->second)) { nLoaded++; queue.push_back(block.GetHash()); @@ -5373,7 +5366,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->nTimeOffset = nTimeOffset; if (GetBoolArg("-synctime", false)) - AddTimeData(pfrom->addr, nTimeOffset); + AddTimeData(pfrom->addr, nTimeOffset); } @@ -5835,8 +5828,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, Misbehaving(pfrom->GetId(), 20); return error("non-continuous headers sequence"); } - uint256 hash = header.GetHash(); - if (!AcceptBlockHeader(header, state, hash, chainparams, &pindexLast)) { + if (!AcceptBlockHeader(header, state, chainparams, &pindexLast)) { int nDoS; if (state.IsInvalid(nDoS)) { if (nDoS > 0) @@ -5926,7 +5918,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Such an unrequested block may still be processed, subject to the // conditions in AcceptBlock(). bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(); - ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL, inv.hash); + ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL); int nDoS; if (state.IsInvalid(nDoS)) { assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes diff --git a/src/main.h b/src/main.h index 64158533d..57c34f701 100644 --- a/src/main.h +++ b/src/main.h @@ -214,7 +214,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals); * @param[out] dbp The already known disk position of pblock, or NULL if not yet stored. * @return True if state.IsValid() */ -bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, const uint256& hash); +bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp); /** Check whether enough disk space is available for an incoming block */ bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); /** Open a block file (blk?????.dat) */ @@ -254,7 +254,7 @@ std::string GetWarnings(const std::string& strFor); /** Retrieve a transaction (from memory pool, or from disk, if possible) */ bool GetTransaction(const uint256 &hash, CTransaction &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false); /** Find the best known block, and make it the tip of the block chain */ -bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL, const uint256 *phash = NULL); +bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL); CAmount GetProofOfWorkSubsidy(); CAmount GetProofOfStakeSubsidy(); @@ -801,14 +801,14 @@ bool ReadFromDisk(CTransaction& tx, CDiskTxPos& txindex); bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL); /** Apply the effects of this block (with given index) on the UTXO set represented by coins */ -bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false); +bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, const CChainParams& chainparams, bool fJustCheck = false); /** Context-independent validity checks */ -bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = false); -bool CheckBlock(const CBlock& block, CValidationState& state, const uint256& hash, bool fCheckPOW = true, bool fCheckMerkleRoot = true, bool fCheckSig = true); +bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = false); +bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true, bool fCheckSig = true); /** Context-dependent validity checks */ -bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev, const uint256& hash); +bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex *pindexPrev); bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex *pindexPrev); /** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */ diff --git a/src/miner.cpp b/src/miner.cpp index 19fb0034d..82e4e24df 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -89,7 +89,7 @@ int64_t GetMaxTransactionTime(CBlock* pblock) { int64_t maxTransactionTime = 0; for (std::vector::const_iterator it(pblock->vtx.begin()); it != pblock->vtx.end(); ++it) - maxTransactionTime = std::max(maxTransactionTime, (int64_t)it->nTime); + maxTransactionTime = std::max(maxTransactionTime, (int64_t)it->nTime); return maxTransactionTime; } @@ -109,12 +109,12 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s int nHeight = chainActive.Tip()->nHeight + 1; if (!fProofOfStake) { - txNew.vout[0].scriptPubKey = scriptPubKeyIn; + txNew.vout[0].scriptPubKey = scriptPubKeyIn; } else { - txNew.vin[0].scriptSig = (CScript() << nHeight) + COINBASE_FLAGS; - txNew.vout[0].SetEmpty(); + txNew.vin[0].scriptSig = (CScript() << nHeight) + COINBASE_FLAGS; + txNew.vout[0].SetEmpty(); } // Add dummy coinbase tx as first transaction @@ -166,7 +166,7 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s // -regtest only: allow overriding block.nVersion with // -blockversion=N to test forking scenarios if (chainparams.MineBlocksOnDemand()) - pblock->nVersion = GetArg("-blockversion", pblock->nVersion); + pblock->nVersion = GetArg("-blockversion", pblock->nVersion); int64_t nLockTimeCutoff = pblock->GetBlockTime(); @@ -302,25 +302,25 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s } nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; - // LogPrintf("CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d\n", nBlockSize, nBlockTx, nFees, nBlockSigOps); + // LogPrintf("CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d\n", nBlockSize, nBlockTx, nFees, nBlockSigOps); // Compute final coinbase transaction. - if (!fProofOfStake) { - txNew.vout[0].nValue = nFees + GetProofOfWorkSubsidy(); - txNew.vin[0].scriptSig = CScript() << nHeight << OP_0; - pblocktemplate->vTxFees[0] = -nFees; - } - txNew.nTime = pblock->nTime; + if (!fProofOfStake) { + txNew.vout[0].nValue = nFees + GetProofOfWorkSubsidy(); + txNew.vin[0].scriptSig = CScript() << nHeight << OP_0; + pblocktemplate->vTxFees[0] = -nFees; + } + txNew.nTime = pblock->nTime; pblock->vtx[0] = txNew; if (pFees) - *pFees = nFees; + *pFees = nFees; // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); pblock->nTime = max(pindexPrev->GetPastTimeLimit()+1, GetMaxTransactionTime(pblock)); if (!fProofOfStake) - UpdateTime(pblock, Params().GetConsensus(), pindexPrev); + UpdateTime(pblock, Params().GetConsensus(), pindexPrev); pblock->nBits = GetNextTargetRequired(pindexPrev, pblock, fProofOfStake, Params().GetConsensus()); pblock->nNonce = 0; pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); @@ -358,8 +358,7 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned // Internal miner // - -static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainparams, const uint256& hash) +static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainparams) { LogPrintf("%s\n", pblock->ToString()); LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue)); @@ -376,7 +375,7 @@ static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainpar // Process this block the same as if we had received it from another node CValidationState state; - if (!ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL, hash)) + if (!ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL)) return error("BitcoinMiner: ProcessNewBlock, block not accepted"); return true; @@ -457,18 +456,18 @@ void static BitcoinMiner(const CChainParams& chainparams) while (true) { // Check if something found - unsigned int nHashesDone = 0; - char scratchpad[SCRYPT_SCRATCHPAD_SIZE]; - while(true) - { - scrypt_1024_1_1_256_sp(BEGIN(pblock->nVersion), BEGIN(thash), scratchpad); + unsigned int nHashesDone = 0; + char scratchpad[SCRYPT_SCRATCHPAD_SIZE]; + while(true) + { + scrypt_1024_1_1_256_sp(BEGIN(pblock->nVersion), BEGIN(thash), scratchpad); if (UintToArith256(thash) <= hashTarget) { SetThreadPriority(THREAD_PRIORITY_NORMAL); LogPrintf("BitcoinMiner:\n"); LogPrintf("proof-of-work found \n powhash: %s \ntarget: %s\n", thash.GetHex(), hashTarget.GetHex()); - ProcessBlockFound(pblock, chainparams, thash); + ProcessBlockFound(pblock, chainparams); SetThreadPriority(THREAD_PRIORITY_LOWEST); coinbaseScript->KeepScript(); @@ -481,7 +480,7 @@ void static BitcoinMiner(const CChainParams& chainparams) pblock->nNonce += 1; nHashesDone += 1; if ((pblock->nNonce & 0xFF) == 0) - break; + break; } // Check for stop or if block needs to be rebuilt @@ -549,19 +548,17 @@ bool SignBlock(CBlock& block, CWallet& wallet, int64_t& nFees) // if we are trying to sign // something except proof-of-stake block template if (!block.vtx[0].vout[0].IsEmpty()){ - LogPrintf("something except proof-of-stake block\n"); - return false; + LogPrintf("something except proof-of-stake block\n"); + return false; } - // if we are trying to sign // a complete proof-of-stake block if (block.IsProofOfStake()){ - LogPrintf("trying to sign a complete proof-of-stake block\n"); - return true; + LogPrintf("trying to sign a complete proof-of-stake block\n"); + return true; } - static int64_t nLastCoinStakeSearchTime = GetAdjustedTime(); // startup timestamp CKey key; @@ -607,7 +604,6 @@ bool SignBlock(CBlock& block, CWallet& wallet, int64_t& nFees) void ThreadStakeMiner(CWallet *pwallet, const CChainParams& chainparams) { - SetThreadPriority(THREAD_PRIORITY_LOWEST); // Make this thread recognisable as the mining thread @@ -693,31 +689,9 @@ bool CheckStake(CBlock* pblock, CWallet& wallet, const CChainParams& chainparams } // Process this block the same as if we had received it from another node - if (!ProcessBlockFound(pblock, chainparams, pblock->GetHash())) + if (!ProcessBlockFound(pblock, chainparams)) return error("CheckStake() : ProcessBlock, block not accepted"); } return true; } - -//void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams) -//{ -// static boost::thread_group* minerThreads = NULL; -// -// if (nThreads < 0) -// nThreads = GetNumCores(); -// -// if (minerThreads != NULL) -// { -// minerThreads->interrupt_all(); -// delete minerThreads; -// minerThreads = NULL; -// } -// -// if (nThreads == 0 || !fGenerate) -// return; -// -// minerThreads = new boost::thread_group(); -// for (int i = 0; i < nThreads; i++) -// minerThreads->create_thread(boost::bind(&BitcoinMiner, boost::cref(chainparams))); -//} diff --git a/src/pos.cpp b/src/pos.cpp index 641c30197..1e683abbb 100644 --- a/src/pos.cpp +++ b/src/pos.cpp @@ -80,9 +80,13 @@ bool CheckStakeKernelHash(const CBlockIndex* pindexPrev, unsigned int nBits, con arith_uint256 bnTarget; bnTarget.SetCompact(nBits); + uint256 nStakeModifier = pindexPrev->nStakeModifier; + // Calculate hash - CHashWriter ss(SER_GETHASH, 0); - ss << pindexPrev->nStakeModifier << txPrev->nTime << prevout.hash << prevout.n << nTimeTx; + CDataStream ss(SER_GETHASH, 0); + ss << nStakeModifier; + ss << txPrev->nTime << prevout.hash << prevout.n << nTimeTx; + uint256 hashProofOfStake = ss.GetHash(); // Now check if proof-of-stake hash meets target protocol @@ -94,16 +98,16 @@ bool CheckStakeKernelHash(const CBlockIndex* pindexPrev, unsigned int nBits, con bool IsConfirmedInNPrevBlocks(const CDiskTxPos& txindex, const CBlockIndex* pindexFrom, int nMaxDepth, int& nActualDepth) { - for (const CBlockIndex* pindex = pindexFrom; pindex && pindexFrom->nHeight - pindex->nHeight < nMaxDepth; pindex = pindex->pprev) - { - if (pindex->nDataPos == txindex.nPos && pindex->nFile == txindex.nFile) - { - nActualDepth = pindexFrom->nHeight - pindex->nHeight; - return true; - } - } + for (const CBlockIndex* pindex = pindexFrom; pindex && pindexFrom->nHeight - pindex->nHeight < nMaxDepth; pindex = pindex->pprev) + { + if (pindex->nDataPos == txindex.nPos && pindex->nFile == txindex.nFile) + { + nActualDepth = pindexFrom->nHeight - pindex->nHeight; + return true; + } + } - return false; + return false; } // Check kernel hash target and coinstake signature @@ -168,31 +172,31 @@ bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTime, co auto it=cache.find(prevout); if(it == cache.end()) { - CTransaction txPrev; - CDiskTxPos txindex; - if (!ReadFromDisk(txPrev, txindex, *pblocktree, prevout)) - return false; + CTransaction txPrev; + CDiskTxPos txindex; + if (!ReadFromDisk(txPrev, txindex, *pblocktree, prevout)) + return false; - // Read block header - CBlock block; - const CDiskBlockPos& pos = CDiskBlockPos(txindex.nFile, txindex.nPos); - if (!ReadBlockFromDisk(block, pos, Params().GetConsensus())) - return false; + // Read block header + CBlock block; + const CDiskBlockPos& pos = CDiskBlockPos(txindex.nFile, txindex.nPos); + if (!ReadBlockFromDisk(block, pos, Params().GetConsensus())) + return false; - int nDepth; - if (IsConfirmedInNPrevBlocks(txindex, pindexPrev, Params().GetConsensus().nStakeMinConfirmations - 1, nDepth)) - return false; + int nDepth; + if (IsConfirmedInNPrevBlocks(txindex, pindexPrev, Params().GetConsensus().nStakeMinConfirmations - 1, nDepth)) + return false; - if (pBlockTime) - *pBlockTime = block.GetBlockTime(); + if (pBlockTime) + *pBlockTime = block.GetBlockTime(); - return CheckStakeKernelHash(pindexPrev, nBits, new CCoins(txPrev, pindexPrev->nHeight), prevout, nTime); - }else{ - //found in cache - const CStakeCache& stake = it->second; - if (pBlockTime) - *pBlockTime = stake.blockFrom.GetBlockTime(); - return CheckStakeKernelHash(pindexPrev, nBits, new CCoins(stake.txPrev, pindexPrev->nHeight), prevout, nTime); + return CheckStakeKernelHash(pindexPrev, nBits, new CCoins(txPrev, pindexPrev->nHeight), prevout, nTime); + } else { + //found in cache + const CStakeCache& stake = it->second; + if (pBlockTime) + *pBlockTime = stake.blockFrom.GetBlockTime(); + return CheckStakeKernelHash(pindexPrev, nBits, new CCoins(stake.txPrev, pindexPrev->nHeight), prevout, nTime); } } @@ -214,4 +218,3 @@ void CacheKernel(std::map& cache, const COutPoint& prevo CStakeCache c(block, txindex, txPrev); cache.insert({prevout, c}); } - diff --git a/src/pow.cpp b/src/pow.cpp index f6484db5b..aa93f31d8 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -30,26 +30,26 @@ static arith_uint256 GetTargetLimit(int64_t nTime, bool fProofOfStake, const Con unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, bool fProofOfStake, const Consensus::Params& params) { - unsigned int nTargetLimit = UintToArith256(params.powLimit).GetCompact(); + unsigned int nTargetLimit = UintToArith256(params.powLimit).GetCompact(); - // Genesis block - if (pindexLast == NULL) - return nTargetLimit; + // Genesis block + if (pindexLast == NULL) + return nTargetLimit; - const CBlockIndex* pindexPrev = GetLastBlockIndex(pindexLast, fProofOfStake); - if (pindexPrev->pprev == NULL) - return nTargetLimit; // first block - const CBlockIndex* pindexPrevPrev = GetLastBlockIndex(pindexPrev->pprev, fProofOfStake); - if (pindexPrevPrev->pprev == NULL) - return nTargetLimit; // second block + const CBlockIndex* pindexPrev = GetLastBlockIndex(pindexLast, fProofOfStake); + if (pindexPrev->pprev == NULL) + return nTargetLimit; // first block + const CBlockIndex* pindexPrevPrev = GetLastBlockIndex(pindexPrev->pprev, fProofOfStake); + if (pindexPrevPrev->pprev == NULL) + return nTargetLimit; // second block - return CalculateNextTargetRequired(pindexPrev, pindexPrevPrev->GetBlockTime(), params); + return CalculateNextTargetRequired(pindexPrev, pindexPrevPrev->GetBlockTime(), params); } unsigned int CalculateNextTargetRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params) { - if (params.fPowNoRetargeting) - return pindexLast->nBits; + if (params.fPowNoRetargeting) + return pindexLast->nBits; int64_t nActualSpacing = pindexLast->GetBlockTime() - nFirstBlockTime; int64_t nTargetSpacing = params.IsProtocolV2(pindexLast->GetBlockTime()) ? params.nTargetSpacing : params.nTargetSpacingV1; @@ -73,6 +73,7 @@ unsigned int CalculateNextTargetRequired(const CBlockIndex* pindexLast, int64_t return bnNew.GetCompact(); } + bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params) { bool fNegative; @@ -83,8 +84,7 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& // Check range if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit)) - return error("CheckProofOfWork(): nBits below minimum work"); - + return error("CheckProofOfWork(): nBits below minimum work"); // Check proof of work matches claimed amount if (UintToArith256(hash) > bnTarget) diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index b9f13b5b8..7516bf7c2 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -177,7 +177,7 @@ UniValue generate(const UniValue& params, bool fHelp) } CValidationState state; uint256 hash = pblock->GetHash(); - if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL, hash)) + if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL)) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; blockHashes.push_back(hash.GetHex()); @@ -707,7 +707,7 @@ UniValue submitblock(const UniValue& params, bool fHelp) CValidationState state; submitblock_StateCatcher sc(hash); RegisterValidationInterface(&sc); - bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL, hash); + bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL); UnregisterValidationInterface(&sc); if (fBlockPresent) { diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp index 20b29d736..cd042c157 100644 --- a/src/test/checkblock_tests.cpp +++ b/src/test/checkblock_tests.cpp @@ -57,7 +57,8 @@ BOOST_AUTO_TEST_CASE(May15) // After May 15'th, big blocks are OK: forkingBlock.nTime = tMay15; // Invalidates PoW - BOOST_CHECK(CheckBlock(forkingBlock, state, forkingBlock.GetHash(), false, false)); + const CChainParams& chainparams = Params(); + BOOST_CHECK(CheckBlock(forkingBlock, state, chainparams.GetConsensus(), false, false)); } SetMockTime(0); diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index d5612bd63..77f242e8d 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -114,7 +114,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); pblock->nNonce = blockinfo[i].nonce; CValidationState state; - BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL, pblock->GetHash())); + BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL)); BOOST_CHECK(state.IsValid()); pblock->hashPrevBlock = pblock->GetHash(); } diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 0e179f5e7..d6dfd54cb 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -111,7 +111,7 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector& while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; CValidationState state; - ProcessNewBlock(state, chainparams, NULL, &block, true, NULL, block.GetHash()); + ProcessNewBlock(state, chainparams, NULL, &block, true, NULL); CBlock result = block; delete pblocktemplate; diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 9e3b21778..6a0f11bc3 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -679,8 +679,8 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem if (it2 != mapTx.end()) continue; const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash); - if (nCheckFrequency != 0) assert(coins); - if (!coins || (coins->IsCoinBase() || coins->IsCoinStake() && ((signed long)nMemPoolHeight) - coins->nHeight < Params().GetConsensus().nCoinbaseMaturity)) { + if (nCheckFrequency != 0) assert(coins); + if ((!coins || (coins->IsCoinBase() || coins->IsCoinStake()) && ((signed long)nMemPoolHeight) - coins->nHeight < Params().GetConsensus().nCoinbaseMaturity)) { transactionsToRemove.push_back(tx); break; }