From 2d6e5619afa2d43a37a0a38daf33f58965ddfa80 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Sun, 4 Dec 2016 00:17:30 -0800 Subject: [PATCH] Switch pblock in ProcessNewBlock to a shared_ptr This (finally) fixes a performance regression in b3b3c2a5623d5c942d2b3565cc2d833c65105555 --- src/net_processing.cpp | 16 ++++++++-------- src/rpc/mining.cpp | 8 +++++--- src/test/miner_tests.cpp | 3 ++- src/test/test_bitcoin.cpp | 3 ++- src/validation.cpp | 9 ++------- src/validation.h | 2 +- 6 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 747167264b772..e81332d618e30 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1895,7 +1895,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, BlockTransactions resp; vRecv >> resp; - CBlock block; + std::shared_ptr pblock = std::make_shared(); bool fBlockRead = false; { LOCK(cs_main); @@ -1908,7 +1908,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } PartiallyDownloadedBlock& partialBlock = *it->second.second->partialBlock; - ReadStatus status = partialBlock.FillBlock(block, resp.txn); + ReadStatus status = partialBlock.FillBlock(*pblock, resp.txn); if (status == READ_STATUS_INVALID) { MarkBlockAsReceived(resp.blockhash); // Reset in-flight state in case of whitelist Misbehaving(pfrom->GetId(), 100); @@ -1951,7 +1951,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, bool fNewBlock = false; // 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, &block, true, NULL, &fNewBlock); + ProcessNewBlock(chainparams, pblock, true, NULL, &fNewBlock); if (fNewBlock) pfrom->nLastBlockTime = GetTime(); } @@ -2112,17 +2112,17 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing { - CBlock block; - vRecv >> block; + std::shared_ptr pblock = std::make_shared(); + vRecv >> *pblock; - LogPrint("net", "received block %s peer=%d\n", block.GetHash().ToString(), pfrom->id); + LogPrint("net", "received block %s peer=%d\n", pblock->GetHash().ToString(), pfrom->id); // Process all blocks from whitelisted peers, even if not requested, // unless we're still syncing with the network. // Such an unrequested block may still be processed, subject to the // conditions in AcceptBlock(). bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(); - const uint256 hash(block.GetHash()); + const uint256 hash(pblock->GetHash()); { LOCK(cs_main); // Also always process if we requested the block explicitly, as we may @@ -2133,7 +2133,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, mapBlockSource.emplace(hash, std::make_pair(pfrom->GetId(), true)); } bool fNewBlock = false; - ProcessNewBlock(chainparams, &block, forceProcessing, NULL, &fNewBlock); + ProcessNewBlock(chainparams, pblock, forceProcessing, NULL, &fNewBlock); if (fNewBlock) pfrom->nLastBlockTime = GetTime(); } diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 61408b3b60222..cb22dec342e9b 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -131,7 +131,8 @@ UniValue generateBlocks(boost::shared_ptr coinbaseScript, int nG if (pblock->nNonce == nInnerLoopCount) { continue; } - if (!ProcessNewBlock(Params(), pblock, true, NULL, NULL)) + std::shared_ptr shared_pblock = std::make_shared(*pblock); + if (!ProcessNewBlock(Params(), shared_pblock, true, NULL, NULL)) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); @@ -728,7 +729,8 @@ UniValue submitblock(const JSONRPCRequest& request) + HelpExampleRpc("submitblock", "\"mydata\"") ); - CBlock block; + std::shared_ptr blockptr = std::make_shared(); + CBlock& block = *blockptr; if (!DecodeHexBlk(block, request.params[0].get_str())) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); @@ -758,7 +760,7 @@ UniValue submitblock(const JSONRPCRequest& request) submitblock_StateCatcher sc(block.GetHash()); RegisterValidationInterface(&sc); - bool fAccepted = ProcessNewBlock(Params(), &block, true, NULL, NULL); + bool fAccepted = ProcessNewBlock(Params(), blockptr, true, NULL, NULL); UnregisterValidationInterface(&sc); if (fBlockPresent) { diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index ca703841db63c..bc1bdd8874d9f 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -223,7 +223,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) txFirst.push_back(pblock->vtx[0]); pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); pblock->nNonce = blockinfo[i].nonce; - BOOST_CHECK(ProcessNewBlock(chainparams, pblock, true, NULL, NULL)); + std::shared_ptr shared_pblock = std::make_shared(*pblock); + BOOST_CHECK(ProcessNewBlock(chainparams, shared_pblock, true, NULL, NULL)); pblock->hashPrevBlock = pblock->GetHash(); } diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index f979d01a37eab..139389117a593 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -127,7 +127,8 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector& while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; - ProcessNewBlock(chainparams, &block, true, NULL, NULL); + std::shared_ptr shared_pblock = std::make_shared(block); + ProcessNewBlock(chainparams, shared_pblock, true, NULL, NULL); CBlock result = block; return result; diff --git a/src/validation.cpp b/src/validation.cpp index bd66c5679bef7..0983c1f7626f6 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3123,7 +3123,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha return true; } -bool ProcessNewBlock(const CChainParams& chainparams, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, bool *fNewBlock) +bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr pblock, bool fForceProcessing, const CDiskBlockPos* dbp, bool *fNewBlock) { { LOCK(cs_main); @@ -3142,13 +3142,8 @@ bool ProcessNewBlock(const CChainParams& chainparams, const CBlock* pblock, bool NotifyHeaderTip(); - //TODO: This copy is a major performance regression, but callers need updated to fix this - std::shared_ptr block_ptr; - if (pblock) - block_ptr.reset(new CBlock(*pblock)); - CValidationState state; // Only used to report errors, not invalidity - ignore it - if (!ActivateBestChain(state, chainparams, block_ptr)) + if (!ActivateBestChain(state, chainparams, pblock)) return error("%s: ActivateBestChain failed", __func__); return true; diff --git a/src/validation.h b/src/validation.h index 2d055d1900166..3a2b51bfec96e 100644 --- a/src/validation.h +++ b/src/validation.h @@ -233,7 +233,7 @@ static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024; * @param[out] fNewBlock A boolean which is set to indicate if the block was first received via this call * @return True if state.IsValid() */ -bool ProcessNewBlock(const CChainParams& chainparams, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, bool* fNewBlock); +bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr pblock, bool fForceProcessing, const CDiskBlockPos* dbp, bool* fNewBlock); /** * Process incoming block headers.