Merge #9665: Use cached [compact] blocks to respond to getdata messages

b49ad44 Add comment about cs_most_recent_block coverage (Matt Corallo)
c47f5b7 Cache witness-enabled state with recent-compact-block-cache (Matt Corallo)
efc135f Use cached [compact] blocks to respond to getdata messages (Matt Corallo)

Tree-SHA512: ffc478bddbf14b8ed304a3041f47746520ce545bdeffa9652eff2ccb25c8b0d5194abe72568c10f9c1b246ee361176ba217767af834752a2ca7263d292005e87
This commit is contained in:
Wladimir J. van der Laan 2017-04-13 17:20:31 +02:00
commit eab00d96df
No known key found for this signature in database
GPG key ID: 74810B012346C9A6

View file

@ -774,10 +774,12 @@ void PeerLogicValidation::BlockConnected(const std::shared_ptr<const CBlock>& pb
} }
} }
// All of the following cache a recent block, and are protected by cs_most_recent_block
static CCriticalSection cs_most_recent_block; static CCriticalSection cs_most_recent_block;
static std::shared_ptr<const CBlock> most_recent_block; static std::shared_ptr<const CBlock> most_recent_block;
static std::shared_ptr<const CBlockHeaderAndShortTxIDs> most_recent_compact_block; static std::shared_ptr<const CBlockHeaderAndShortTxIDs> most_recent_compact_block;
static uint256 most_recent_block_hash; static uint256 most_recent_block_hash;
static bool fWitnessesPresentInMostRecentCompactBlock;
void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) { void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) {
std::shared_ptr<const CBlockHeaderAndShortTxIDs> pcmpctblock = std::make_shared<const CBlockHeaderAndShortTxIDs> (*pblock, true); std::shared_ptr<const CBlockHeaderAndShortTxIDs> pcmpctblock = std::make_shared<const CBlockHeaderAndShortTxIDs> (*pblock, true);
@ -798,6 +800,7 @@ void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std:
most_recent_block_hash = hashBlock; most_recent_block_hash = hashBlock;
most_recent_block = pblock; most_recent_block = pblock;
most_recent_compact_block = pcmpctblock; most_recent_compact_block = pcmpctblock;
fWitnessesPresentInMostRecentCompactBlock = fWitnessEnabled;
} }
connman->ForEachNode([this, &pcmpctblock, pindex, &msgMaker, fWitnessEnabled, &hashBlock](CNode* pnode) { connman->ForEachNode([this, &pcmpctblock, pindex, &msgMaker, fWitnessEnabled, &hashBlock](CNode* pnode) {
@ -990,6 +993,15 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
{ {
bool send = false; bool send = false;
BlockMap::iterator mi = mapBlockIndex.find(inv.hash); BlockMap::iterator mi = mapBlockIndex.find(inv.hash);
std::shared_ptr<const CBlock> a_recent_block;
std::shared_ptr<const CBlockHeaderAndShortTxIDs> a_recent_compact_block;
bool fWitnessesPresentInARecentCompactBlock;
{
LOCK(cs_most_recent_block);
a_recent_block = most_recent_block;
a_recent_compact_block = most_recent_compact_block;
fWitnessesPresentInARecentCompactBlock = fWitnessesPresentInMostRecentCompactBlock;
}
if (mi != mapBlockIndex.end()) if (mi != mapBlockIndex.end())
{ {
if (mi->second->nChainTx && !mi->second->IsValid(BLOCK_VALID_SCRIPTS) && if (mi->second->nChainTx && !mi->second->IsValid(BLOCK_VALID_SCRIPTS) &&
@ -999,11 +1011,6 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// before ActivateBestChain but after AcceptBlock). // before ActivateBestChain but after AcceptBlock).
// In this case, we need to run ActivateBestChain prior to checking the relay // In this case, we need to run ActivateBestChain prior to checking the relay
// conditions below. // conditions below.
std::shared_ptr<const CBlock> a_recent_block;
{
LOCK(cs_most_recent_block);
a_recent_block = most_recent_block;
}
CValidationState dummy; CValidationState dummy;
ActivateBestChain(dummy, Params(), a_recent_block); ActivateBestChain(dummy, Params(), a_recent_block);
} }
@ -1037,14 +1044,20 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// it's available before trying to send. // it's available before trying to send.
if (send && (mi->second->nStatus & BLOCK_HAVE_DATA)) if (send && (mi->second->nStatus & BLOCK_HAVE_DATA))
{ {
// Send block from disk std::shared_ptr<const CBlock> pblock;
CBlock block; if (a_recent_block && a_recent_block->GetHash() == (*mi).second->GetBlockHash()) {
if (!ReadBlockFromDisk(block, (*mi).second, consensusParams)) pblock = a_recent_block;
assert(!"cannot load block from disk"); } else {
// Send block from disk
std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
if (!ReadBlockFromDisk(*pblockRead, (*mi).second, consensusParams))
assert(!"cannot load block from disk");
pblock = pblockRead;
}
if (inv.type == MSG_BLOCK) if (inv.type == MSG_BLOCK)
connman.PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block)); connman.PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, *pblock));
else if (inv.type == MSG_WITNESS_BLOCK) else if (inv.type == MSG_WITNESS_BLOCK)
connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::BLOCK, block)); connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::BLOCK, *pblock));
else if (inv.type == MSG_FILTERED_BLOCK) else if (inv.type == MSG_FILTERED_BLOCK)
{ {
bool sendMerkleBlock = false; bool sendMerkleBlock = false;
@ -1053,7 +1066,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
LOCK(pfrom->cs_filter); LOCK(pfrom->cs_filter);
if (pfrom->pfilter) { if (pfrom->pfilter) {
sendMerkleBlock = true; sendMerkleBlock = true;
merkleBlock = CMerkleBlock(block, *pfrom->pfilter); merkleBlock = CMerkleBlock(*pblock, *pfrom->pfilter);
} }
} }
if (sendMerkleBlock) { if (sendMerkleBlock) {
@ -1066,7 +1079,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// however we MUST always provide at least what the remote peer needs // however we MUST always provide at least what the remote peer needs
typedef std::pair<unsigned int, uint256> PairType; typedef std::pair<unsigned int, uint256> PairType;
BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn) BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn)
connman.PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, *block.vtx[pair.first])); connman.PushMessage(pfrom, msgMaker.Make(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, *pblock->vtx[pair.first]));
} }
// else // else
// no response // no response
@ -1080,10 +1093,15 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
bool fPeerWantsWitness = State(pfrom->GetId())->fWantsCmpctWitness; bool fPeerWantsWitness = State(pfrom->GetId())->fWantsCmpctWitness;
int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS; int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
if (CanDirectFetch(consensusParams) && mi->second->nHeight >= chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) { if (CanDirectFetch(consensusParams) && mi->second->nHeight >= chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) {
CBlockHeaderAndShortTxIDs cmpctblock(block, fPeerWantsWitness); if ((fPeerWantsWitness || !fWitnessesPresentInARecentCompactBlock) && a_recent_compact_block && a_recent_compact_block->header.GetHash() == mi->second->GetBlockHash()) {
connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock)); connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block));
} else } else {
connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCK, block)); CBlockHeaderAndShortTxIDs cmpctblock(*pblock, fPeerWantsWitness);
connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
}
} else {
connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCK, *pblock));
}
} }
// Trigger the peer node to send a getblocks request for the next batch of inventory // Trigger the peer node to send a getblocks request for the next batch of inventory
@ -2974,7 +2992,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
{ {
LOCK(cs_most_recent_block); LOCK(cs_most_recent_block);
if (most_recent_block_hash == pBestIndex->GetBlockHash()) { if (most_recent_block_hash == pBestIndex->GetBlockHash()) {
if (state.fWantsCmpctWitness) if (state.fWantsCmpctWitness || !fWitnessesPresentInMostRecentCompactBlock)
connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *most_recent_compact_block)); connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *most_recent_compact_block));
else { else {
CBlockHeaderAndShortTxIDs cmpctblock(*most_recent_block, state.fWantsCmpctWitness); CBlockHeaderAndShortTxIDs cmpctblock(*most_recent_block, state.fWantsCmpctWitness);