diff options
Diffstat (limited to 'src/validation.cpp')
| -rw-r--r-- | src/validation.cpp | 67 |
1 files changed, 51 insertions, 16 deletions
diff --git a/src/validation.cpp b/src/validation.cpp index 2390dac57..3a03d206c 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -142,7 +142,7 @@ private: * ahead and mark descendants of invalid blocks as FAILED_CHILD at that time, * instead of putting things in this set. */ - std::set<CBlockIndex*> g_failed_blocks; + std::set<CBlockIndex*> m_failed_blocks; public: CChain chainActive; @@ -1286,7 +1286,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew) void CChainState::InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) { if (!state.CorruptionPossible()) { pindex->nStatus |= BLOCK_FAILED_VALID; - g_failed_blocks.insert(pindex); + m_failed_blocks.insert(pindex); setDirtyBlockIndex.insert(pindex); setBlockIndexCandidates.erase(pindex); InvalidChainFound(pindex); @@ -1615,22 +1615,27 @@ void static FlushBlockFile(bool fFinalize = false) LOCK(cs_LastBlockFile); CDiskBlockPos posOld(nLastBlockFile, 0); + bool status = true; FILE *fileOld = OpenBlockFile(posOld); if (fileOld) { if (fFinalize) - TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nSize); - FileCommit(fileOld); + status &= TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nSize); + status &= FileCommit(fileOld); fclose(fileOld); } fileOld = OpenUndoFile(posOld); if (fileOld) { if (fFinalize) - TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nUndoSize); - FileCommit(fileOld); + status &= TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nUndoSize); + status &= FileCommit(fileOld); fclose(fileOld); } + + if (!status) { + AbortNode("Flushing block file to disk failed. This is likely the result of an I/O error."); + } } static bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize); @@ -1726,16 +1731,38 @@ public: // Protected by cs_main static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS]; +// 0.13.0 was shipped with a segwit deployment defined for testnet, but not for +// mainnet. We no longer need to support disabling the segwit deployment +// except for testing purposes, due to limitations of the functional test +// environment. See test/functional/p2p-segwit.py. +static bool IsScriptWitnessEnabled(const Consensus::Params& params) +{ + return params.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout != 0; +} + static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& consensusparams) { AssertLockHeld(cs_main); unsigned int flags = SCRIPT_VERIFY_NONE; - // Start enforcing P2SH (BIP16) - if (pindex->nHeight >= consensusparams.BIP16Height) { + // BIP16 didn't become active until Apr 1 2012 (on mainnet, and + // retroactively applied to testnet) + // However, only one historical block violated the P2SH rules (on both + // mainnet and testnet), so for simplicity, always leave P2SH + // on except for the one violating block. + if (consensusparams.BIP16Exception.IsNull() || // no bip16 exception on this chain + pindex->phashBlock == nullptr || // this is a new candidate block, eg from TestBlockValidity() + *pindex->phashBlock != consensusparams.BIP16Exception) // this block isn't the historical exception + { flags |= SCRIPT_VERIFY_P2SH; } + // Enforce WITNESS rules whenever P2SH is in effect (and the segwit + // deployment is defined). + if (flags & SCRIPT_VERIFY_P2SH && IsScriptWitnessEnabled(consensusparams)) { + flags |= SCRIPT_VERIFY_WITNESS; + } + // Start enforcing the DERSIG (BIP66) rule if (pindex->nHeight >= consensusparams.BIP66Height) { flags |= SCRIPT_VERIFY_DERSIG; @@ -1751,9 +1778,7 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consens flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; } - // Start enforcing WITNESS rules using versionbits logic. - if (IsWitnessEnabled(pindex->pprev, consensusparams)) { - flags |= SCRIPT_VERIFY_WITNESS; + if (IsNullDummyEnabled(pindex->pprev, consensusparams)) { flags |= SCRIPT_VERIFY_NULLDUMMY; } @@ -2787,7 +2812,7 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c pindex->nStatus |= BLOCK_FAILED_VALID; setDirtyBlockIndex.insert(pindex); setBlockIndexCandidates.erase(pindex); - g_failed_blocks.insert(pindex); + m_failed_blocks.insert(pindex); // DisconnectTip will add transactions to disconnectpool; try to add these // back to the mempool. @@ -2833,7 +2858,7 @@ bool CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) { // Reset invalid block marker if it was pointing to one of those. pindexBestInvalid = nullptr; } - g_failed_blocks.erase(it->second); + m_failed_blocks.erase(it->second); } it++; } @@ -3103,6 +3128,12 @@ bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& pa return (VersionBitsState(pindexPrev, params, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == ThresholdState::ACTIVE); } +bool IsNullDummyEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params) +{ + LOCK(cs_main); + return (VersionBitsState(pindexPrev, params, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == ThresholdState::ACTIVE); +} + // Compute at which vout of the block's coinbase transaction the witness // commitment occurs, or -1 if not found. static int GetWitnessCommitmentIndex(const CBlock& block) @@ -3327,7 +3358,7 @@ bool CChainState::AcceptBlockHeader(const CBlockHeader& block, CValidationState& return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); if (!pindexPrev->IsValid(BLOCK_VALID_SCRIPTS)) { - for (const CBlockIndex* failedit : g_failed_blocks) { + for (const CBlockIndex* failedit : m_failed_blocks) { if (pindexPrev->GetAncestor(failedit->nHeight) == failedit) { assert(failedit->nStatus & BLOCK_FAILED_VALID); CBlockIndex* invalid_walk = pindexPrev; @@ -4098,6 +4129,9 @@ bool CChainState::RewindBlockIndex(const CChainParams& params) int nHeight = 1; while (nHeight <= chainActive.Height()) { + // Although SCRIPT_VERIFY_WITNESS is now generally enforced on all + // blocks in ConnectBlock, we don't need to go back and + // re-download/re-verify blocks from before segwit actually activated. if (IsWitnessEnabled(chainActive[nHeight - 1], params.GetConsensus()) && !(chainActive[nHeight]->nStatus & BLOCK_OPT_WITNESS)) { break; } @@ -4199,7 +4233,7 @@ bool RewindBlockIndex(const CChainParams& params) { void CChainState::UnloadBlockIndex() { nBlockSequenceId = 1; - g_failed_blocks.clear(); + m_failed_blocks.clear(); setBlockIndexCandidates.clear(); } @@ -4741,7 +4775,8 @@ bool DumpMempool(void) } file << mapDeltas; - FileCommit(file.Get()); + if (!FileCommit(file.Get())) + throw std::runtime_error("FileCommit failed"); file.fclose(); RenameOver(GetDataDir() / "mempool.dat.new", GetDataDir() / "mempool.dat"); int64_t last = GetTimeMicros(); |