diff --git a/src/init.cpp b/src/init.cpp index c97ce386eab67..87cd094d59857 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2129,11 +2129,13 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) pwalletMain->postInitProcess(scheduler); #endif + threadGroup.create_thread(boost::bind(&ThreadSendAlert, boost::ref(connman))); + +#ifdef ENABLE_WALLET if(GetBoolArg("-staking", true)) { threadGroup.create_thread(std::bind(&ThreadStakeMinter, boost::ref(chainparams), boost::ref(connman))); } - - threadGroup.create_thread(boost::bind(&ThreadSendAlert, boost::ref(connman))); +#endif return !fRequestShutdown; } diff --git a/src/kernel.cpp b/src/kernel.cpp index dcc3d50f8e111..4603df94acb3b 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -222,7 +222,7 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexCurrent, uint64_t &nStake return true; } -static bool GetKernelStakeModifierV03(uint256 hashBlockFrom, unsigned int nTimeTx, uint64_t& nStakeModifier, int& nStakeModifierHeight, int64_t& nStakeModifierTime, bool fPrintProofOfStake) +static bool GetKernelStakeModifier(uint256 hashBlockFrom, unsigned int nTimeTx, uint64_t& nStakeModifier, int& nStakeModifierHeight, int64_t& nStakeModifierTime, bool fPrintProofOfStake) { nStakeModifier = 0; if (!mapBlockIndex.count(hashBlockFrom)) @@ -264,12 +264,6 @@ static bool GetKernelStakeModifierV03(uint256 hashBlockFrom, unsigned int nTimeT return true; } -// Get the stake modifier specified by the protocol to hash for a stake kernel -static bool GetKernelStakeModifier(uint256 hashBlockFrom, unsigned int nTimeTx, uint64_t& nStakeModifier, int& nStakeModifierHeight, int64_t& nStakeModifierTime, bool fPrintProofOfStake) -{ - return GetKernelStakeModifierV03(hashBlockFrom, nTimeTx, nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake); -} - uint256 stakeHash(unsigned int nTimeTx, CDataStream ss, unsigned int prevoutIndex, uint256 prevoutHash, unsigned int nTimeBlockFrom) { ss << nTimeBlockFrom << prevoutIndex << prevoutHash << nTimeTx; @@ -292,10 +286,6 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned bnTargetPerCoinDay.SetCompact(nBits); CAmount nValueIn = txPrev->vout[prevout.n].nValue; - // stake input must be of a minimum value - if (nValueIn < COIN) - return error("CheckStakeKernelHash() : nValueIn is less than COIN (nValueIn=%llu)", nValueIn); - // v0.3 protocol kernel hash weight starts from 0 at the 30-day min age // this change increases active coins participating the hash and helps // to secure the network when proof-of-stake difficulty is low @@ -310,6 +300,7 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned if (!GetKernelStakeModifier(blockFrom.GetHash(), nTimeTx, nStakeModifier, nStakeModifierHeight, nStakeModifierTime, false)) return false; + ss << nStakeModifier; ss << nTimeBlockFrom << nTxPrevOffset << txPrevTime << prevout.n << nTimeTx; hashProofOfStake = Hash(ss.begin(), ss.end()); @@ -363,8 +354,9 @@ bool CheckProofOfStake(const CBlock &block, uint256& hashProofOfStake) const auto &cons = Params().GetConsensus(); - if (!GetTransaction(txin.prevout.hash, txPrev, cons, hashBlock, true)) + if (!GetTransaction(txin.prevout.hash, txPrev, cons, hashBlock, true)) { return error("CheckProofOfStake() : INFO: read txPrev failed"); + } CTxOut prevTxOut = txPrev->vout[txin.prevout.n]; CBlockIndex* pindex = NULL; diff --git a/src/net.cpp b/src/net.cpp index 819dae27f5d31..5df33e0f60fcc 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1368,10 +1368,14 @@ void CConnman::ThreadSocketHandler() } } - // - // Service each socket - // - std::vector vNodesCopy = CopyNodeVector(); + std::vector vNodesCopy; + { + LOCK(cs_vNodes); + vNodesCopy = vNodes; + for (CNode* pnode : vNodesCopy) + pnode->AddRef(); + } + BOOST_FOREACH(CNode* pnode, vNodesCopy) { if (interruptNet) @@ -1494,7 +1498,11 @@ void CConnman::ThreadSocketHandler() } } } - ReleaseNodeVector(vNodesCopy); + { + LOCK(cs_vNodes); + for (CNode* pnode : vNodesCopy) + pnode->Release(); + } } } diff --git a/src/net.h b/src/net.h index 4bf1a8206f59c..6d52386c8c5c3 100644 --- a/src/net.h +++ b/src/net.h @@ -70,6 +70,8 @@ static const int WARNING_INTERVAL = 10 * 60; static const int FEELER_INTERVAL = 120; /** The maximum number of entries in an 'inv' protocol message */ static const unsigned int MAX_INV_SZ = 50000; +/** The maximum number of entries in a locator */ +static const unsigned int MAX_LOCATOR_SZ = 101; /** The maximum number of new addresses to accumulate before announcing. */ static const unsigned int MAX_ADDR_TO_SEND = 1000; /** Maximum length of incoming protocol messages (no message over 3 MiB is currently acceptable). */ diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 39e5b1e1c8087..51ccd6ec36aaa 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -231,6 +231,9 @@ struct CNodeState { */ bool fSupportsDesiredCmpctVersion; + //! Time of last new block announcement + int64_t m_last_block_announcement; + CNodeState(CAddress addrIn, std::string addrNameIn) : address(addrIn), name(addrNameIn) { fCurrentlyConnected = false; nMisbehavior = 0; @@ -251,6 +254,7 @@ struct CNodeState { fPreferHeaderAndIDs = false; fProvidesHeaderAndIDs = false; fSupportsDesiredCmpctVersion = false; + m_last_block_announcement = 0; } }; @@ -452,6 +456,7 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman& connman) { } } connman.ForNode(nodeid, [&connman](CNode* pfrom){ + AssertLockHeld(cs_main); bool fAnnounceUsingCMPCTBLOCK = false; uint64_t nCMPCTBLOCKVersion = 1; if (lNodesAnnouncingHeaderAndIDs.size() >= 3) { @@ -975,7 +980,6 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 0)) || // Best effort: only try output 0 and 1 pcoinsTip->HaveCoinInCache(COutPoint(inv.hash, 1)); } - case MSG_BLOCK: return mapBlockIndex.count(inv.hash); @@ -1022,7 +1026,6 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) case MSG_ISLOCK: return llmq::quorumInstantSendManager->AlreadyHave(inv); } - // Don't know what it is, just say we already got one return true; } @@ -1929,6 +1932,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr uint256 hashStop; vRecv >> locator >> hashStop; + if (locator.vHave.size() > MAX_LOCATOR_SZ) { + LogPrint("net", "getblocks locator size %lld > %d, disconnect peer=%d\n", locator.vHave.size(), MAX_LOCATOR_SZ, pfrom->GetId()); + pfrom->fDisconnect = true; + return true; + } + // We might have announced the currently-being-connected tip using a // compact block, which resulted in the peer sending a getblocks // request, which we would otherwise respond to without the new block. @@ -2040,6 +2049,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr uint256 hashStop; vRecv >> locator >> hashStop; + if (locator.vHave.size() > MAX_LOCATOR_SZ) { + LogPrint("net", "getheaders locator size %lld > %d, disconnect peer=%d\n", locator.vHave.size(), MAX_LOCATOR_SZ, pfrom->GetId()); + pfrom->fDisconnect = true; + return true; + } + LOCK(cs_main); if (IsInitialBlockDownload() && !pfrom->fWhitelisted) { LogPrint("net", "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom->id); @@ -2362,6 +2377,8 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr CBlockHeaderAndShortTxIDs cmpctblock; vRecv >> cmpctblock; + bool received_new_header = false; + { LOCK(cs_main); @@ -2371,6 +2388,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256())); return true; } + + if (!LookupBlockIndex(cmpctblock.header.GetHash())) { + received_new_header = true; + } } const CBlockIndex *pindex = NULL; @@ -2380,7 +2401,9 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (state.IsInvalid(nDoS)) { if (nDoS > 0) { LOCK(cs_main); - Misbehaving(pfrom->GetId(), nDoS); + Misbehaving(pfrom->GetId(), nDoS /*, strprintf("Peer %d sent us invalid header via cmpctblock\n", pfrom->GetId())*/); + } else { + LogPrint("net", "Peer %d sent us invalid header via cmpctblock\n", pfrom->GetId()); } LogPrintf("Peer %d sent us invalid header via cmpctblock\n", pfrom->id); return true; @@ -2410,6 +2433,14 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr assert(pindex); UpdateBlockAvailability(pfrom->GetId(), pindex->GetBlockHash()); + CNodeState *nodestate = State(pfrom->GetId()); + + // If this was a new header with more work than our tip, update the + // peer's last block announcement time + if (received_new_header && pindex->nChainWork > chainActive.Tip()->nChainWork) { + nodestate->m_last_block_announcement = GetTime(); + } + std::map::iterator> >::iterator blockInFlightIt = mapBlocksInFlight.find(pindex->GetBlockHash()); bool fAlreadyInFlight = blockInFlightIt != mapBlocksInFlight.end(); @@ -2432,8 +2463,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (!fAlreadyInFlight && !CanDirectFetch(chainparams.GetConsensus())) return true; - CNodeState *nodestate = State(pfrom->GetId()); - // We want to be a bit conservative just to be extra careful about DoS // possibilities in compact block processing... if (pindex->nHeight <= chainActive.Height() + 2) { @@ -2532,9 +2561,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr } bool fNewBlock = false; ProcessNewBlock(chainparams, pblock, true, &fNewBlock); - if (fNewBlock) + if (fNewBlock) { pfrom->nLastBlockTime = GetTime(); - + } else { + LOCK(cs_main); + mapBlockSource.erase(pblock->GetHash()); + } LOCK(cs_main); // hold cs_main for CBlockIndex::IsValid() if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS)) { // Clear download state for this block, which is in @@ -2609,8 +2641,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // Since we requested this block (it was in mapBlocksInFlight), force it to be processed, // even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc) ProcessNewBlock(chainparams, pblock, true, &fNewBlock); - if (fNewBlock) + if (fNewBlock) { pfrom->nLastBlockTime = GetTime(); + } else { + LOCK(cs_main); + mapBlockSource.erase(pblock->GetHash()); + } } } @@ -2759,7 +2795,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr } } } - } + } } else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing @@ -2786,8 +2822,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr } bool fNewBlock = false; ProcessNewBlock(chainparams, pblock, forceProcessing, &fNewBlock); - if (fNewBlock) + if (fNewBlock){ pfrom->nLastBlockTime = GetTime(); + } else { + LOCK(cs_main); + mapBlockSource.erase(pblock->GetHash()); + } } diff --git a/src/validation.cpp b/src/validation.cpp index 23579d098cdeb..2424539f68728 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1088,6 +1088,7 @@ bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHea bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams) { + LOCK(cs_main); block.SetNull(); // Open history file to read @@ -1112,7 +1113,13 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus: bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams) { - if (!ReadBlockFromDisk(block, pindex->GetBlockPos(), consensusParams)) + CDiskBlockPos blockPos; + { + LOCK(cs_main); + blockPos = pindex->GetBlockPos(); + } + + if (!ReadBlockFromDisk(block, blockPos, consensusParams)) return false; if (block.GetHash() != pindex->GetBlockHash()) return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s", @@ -3204,7 +3211,7 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block, enum BlockStatus nStatus // ppcoin: compute stake modifier uint64_t nStakeModifier = 0; bool fGeneratedStakeModifier = false; - if (!ComputeNextStakeModifier(pindexNew->pprev, nStakeModifier, fGeneratedStakeModifier)) + if (!ComputeNextStakeModifier(pindexNew, nStakeModifier, fGeneratedStakeModifier)) LogPrintf("AddToBlockIndex() : ComputeNextStakeModifier() failed \n"); pindexNew->SetStakeModifier(nStakeModifier, fGeneratedStakeModifier); pindexNew->nStakeModifierChecksum = GetStakeModifierChecksum(pindexNew); @@ -3215,7 +3222,6 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block, enum BlockStatus nStatus pindexNew->RaiseValidity(BLOCK_VALID_TREE); if (pindexBestHeader == NULL || pindexBestHeader->nChainWork < pindexNew->nChainWork) pindexBestHeader = pindexNew; - setDirtyBlockIndex.insert(pindexNew); return pindexNew; @@ -3505,32 +3511,12 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co if (!pindexPrev) return state.DoS(100, false, REJECT_INVALID, "bad-pindex-prev", false, strprintf("current block is not genesis but has null previous")); - // Test if stake matches target given - uint256 hashProofOfStake = uint256(); - if (block.IsProofOfStake()) - { - uint256 hash = block.GetHash(); - if(!CheckProofOfStake(block, hashProofOfStake)) - return state.DoS(100, error("CheckBlock(): check proof-of-stake failed for block %s\n", hash.ToString().c_str())); - - if(hashProofOfStake == uint256()) - return state.DoS(100, error("CheckBlock(): check proof-of-stake failed for block %s\n", hash.ToString().c_str())); - - if(!mapProofOfStake.count(hash)) // add to mapProofOfStake - mapProofOfStake.insert(std::make_pair(hash, hashProofOfStake)); - } - // Test nbits if proof of work - if (block.IsProofOfWork()) - { + if (block.IsProofOfWork()) { if (block.nBits != GetNextWorkRequired(pindexPrev, consensusParams)) return state.DoS(100, false, REJECT_INVALID, "bad-diffbits", false, strprintf("incorrect difficulty: block pow=Y bits=%08x calc=%08x", block.nBits, GetNextWorkRequired(pindexPrev, consensusParams))); } - else { - LogPrintf("Block pow=N bits=%08x found=%08x hashProof=%s\n", GetNextWorkRequired(pindexPrev, consensusParams), block.nBits, - hashProofOfStake.ToString().c_str()); - } // Start enforcing BIP113 (Median Time Past) using versionbits logic. int nLockTimeFlags = 0; @@ -3615,7 +3601,7 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state return true; } - if (!CheckBlockHeader(block, state, chainparams.GetConsensus(), block.nNonce != uint32_t(0))) + if (!CheckBlockHeader(block, state, chainparams.GetConsensus(), false)) return error("%s: Consensus::CheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); // Get prev block index @@ -3689,7 +3675,6 @@ static bool AcceptBlock(const std::shared_ptr& pblock, CValidation CBlockIndex *pindexDummy = NULL; CBlockIndex *&pindex = ppindex ? *ppindex : pindexDummy; - if (!AcceptBlockHeader(block, state, chainparams, &pindex)) return false; @@ -3790,6 +3775,21 @@ static bool AcceptBlock(const std::shared_ptr& pblock, CValidation } } + // test if hashproofofstake matches + uint256 hashProofOfStake = uint256(); + if (block.IsProofOfStake()) + { + if(!CheckProofOfStake(block, hashProofOfStake)) + return state.DoS(100, error("CheckBlock(): check proof-of-stake failed for block %s\n", hashProofOfStake.ToString().c_str())); + + uint256 hash = block.GetHash(); + if(!mapProofOfStake.count(hash)) // add to mapProofOfStake + mapProofOfStake.insert(std::make_pair(hash, hashProofOfStake)); + + LogPrintf("Block pow=N bits=%08x found=%08x hashProof=%s\n", + GetNextWorkRequired(pindex->pprev, Params().GetConsensus()),block.nBits, hashProofOfStake.ToString().c_str()); + } + // Write block to history file try { unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); @@ -4472,6 +4472,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB // detect out of order blocks, and store them for later uint256 hash = block.GetHash(); + LOCK(cs_main); if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex.find(block.hashPrevBlock) == mapBlockIndex.end()) { LogPrint("reindex", "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(), block.hashPrevBlock.ToString()); diff --git a/src/validation.h b/src/validation.h index 2772cb77464df..33d54f04cff57 100644 --- a/src/validation.h +++ b/src/validation.h @@ -512,6 +512,13 @@ class CVerifyDB { bool VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth); }; +inline CBlockIndex* LookupBlockIndex(const uint256& hash) +{ + AssertLockHeld(cs_main); + BlockMap::const_iterator it = mapBlockIndex.find(hash); + return it == mapBlockIndex.end() ? nullptr : it->second; +} + /** Find the last common block between the parameter chain and a locator. */ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator);