Skip to content

Commit 3908fc4

Browse files
committed
Merge #9375: Relay compact block messages prior to full block connection
02ee4eb Make most_recent_compact_block a pointer to a const (Matt Corallo) 73666ad Add comment to describe callers to ActivateBestChain (Matt Corallo) 962f7f0 Call ActivateBestChain without cs_main/with most_recent_block (Matt Corallo) 0df777d Use a temp pindex to avoid a const_cast in ProcessNewBlockHeaders (Matt Corallo) c1ae4fc Avoid holding cs_most_recent_block while calling ReadBlockFromDisk (Matt Corallo) 9eb67f5 Ensure we meet the BIP 152 old-relay-types response requirements (Matt Corallo) 5749a85 Cache most-recently-connected compact block (Matt Corallo) 9eaec08 Cache most-recently-announced block's shared_ptr (Matt Corallo) c802092 Relay compact block messages prior to full block connection (Matt Corallo) 6987219 Add a CValidationInterface::NewPoWValidBlock callback (Matt Corallo) 180586f Call AcceptBlock with the block's shared_ptr instead of CBlock& (Matt Corallo) 8baaba6 [qa] Avoid race in preciousblock test. (Matt Corallo) 9a0b2f4 [qa] Make compact blocks test construction using fetch methods (Matt Corallo) 8017547 Make CBlockIndex*es in net_processing const (Matt Corallo)
2 parents 8b66bf7 + 02ee4eb commit 3908fc4

File tree

8 files changed

+220
-60
lines changed

8 files changed

+220
-60
lines changed

qa/rpc-tests/p2p-compactblocks.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,9 @@ def test_compactblock_construction(self, node, test_node, version, use_witness_a
310310
tip = int(node.getbestblockhash(), 16)
311311
assert(test_node.wait_for_block_announcement(tip))
312312

313+
# Make sure we will receive a fast-announce compact block
314+
self.request_cb_announcements(test_node, node, version)
315+
313316
# Now mine a block, and look at the resulting compact block.
314317
test_node.clear_block_announcement()
315318
block_hash = int(node.generate(1)[0], 16)
@@ -319,27 +322,36 @@ def test_compactblock_construction(self, node, test_node, version, use_witness_a
319322
[tx.calc_sha256() for tx in block.vtx]
320323
block.rehash()
321324

322-
# Don't care which type of announcement came back for this test; just
323-
# request the compact block if we didn't get one yet.
325+
# Wait until the block was announced (via compact blocks)
324326
wait_until(test_node.received_block_announcement, timeout=30)
325327
assert(test_node.received_block_announcement())
326328

329+
# Now fetch and check the compact block
330+
header_and_shortids = None
331+
with mininode_lock:
332+
assert(test_node.last_cmpctblock is not None)
333+
# Convert the on-the-wire representation to absolute indexes
334+
header_and_shortids = HeaderAndShortIDs(test_node.last_cmpctblock.header_and_shortids)
335+
self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)
336+
337+
# Now fetch the compact block using a normal non-announce getdata
327338
with mininode_lock:
328-
if test_node.last_cmpctblock is None:
329-
test_node.clear_block_announcement()
330-
inv = CInv(4, block_hash) # 4 == "CompactBlock"
331-
test_node.send_message(msg_getdata([inv]))
339+
test_node.clear_block_announcement()
340+
inv = CInv(4, block_hash) # 4 == "CompactBlock"
341+
test_node.send_message(msg_getdata([inv]))
332342

333343
wait_until(test_node.received_block_announcement, timeout=30)
334344
assert(test_node.received_block_announcement())
335345

336-
# Now we should have the compactblock
346+
# Now fetch and check the compact block
337347
header_and_shortids = None
338348
with mininode_lock:
339349
assert(test_node.last_cmpctblock is not None)
340350
# Convert the on-the-wire representation to absolute indexes
341351
header_and_shortids = HeaderAndShortIDs(test_node.last_cmpctblock.header_and_shortids)
352+
self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)
342353

354+
def check_compactblock_construction_from_block(self, version, header_and_shortids, block_hash, block):
343355
# Check that we got the right block!
344356
header_and_shortids.header.calc_sha256()
345357
assert_equal(header_and_shortids.header.sha256, block_hash)

qa/rpc-tests/preciousblock.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def run_test(self):
102102
assert_equal(self.nodes[2].getblockcount(), 6)
103103
hashL = self.nodes[2].getbestblockhash()
104104
print("Connect nodes and check no reorg occurs")
105-
node_sync_via_rpc(self.nodes[0:3])
105+
node_sync_via_rpc(self.nodes[1:3])
106106
connect_nodes_bi(self.nodes,1,2)
107107
connect_nodes_bi(self.nodes,0,2)
108108
assert_equal(self.nodes[0].getbestblockhash(), hashH)

src/net_processing.cpp

Lines changed: 161 additions & 41 deletions
Large diffs are not rendered by default.

src/net_processing.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class PeerLogicValidation : public CValidationInterface {
2424
virtual void SyncTransaction(const CTransaction& tx, const CBlockIndex* pindex, int nPosInBlock);
2525
virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload);
2626
virtual void BlockChecked(const CBlock& block, const CValidationState& state);
27+
virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock);
2728
};
2829

2930
struct CNodeStateStats {

src/validation.cpp

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2414,6 +2414,11 @@ static void NotifyHeaderTip() {
24142414
* that is already loaded (to avoid loading it again from disk).
24152415
*/
24162416
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
2417+
// Note that while we're often called here from ProcessNewBlock, this is
2418+
// far from a guarantee. Things in the P2P/RPC will often end up calling
2419+
// us in the middle of ProcessNewBlock - do not assume pblock is set
2420+
// sanely for performance or correctness!
2421+
24172422
CBlockIndex *pindexMostWork = NULL;
24182423
CBlockIndex *pindexNewTip = NULL;
24192424
do {
@@ -3056,23 +3061,29 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
30563061
}
30573062

30583063
// Exposed wrapper for AcceptBlockHeader
3059-
bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex)
3064+
bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex)
30603065
{
30613066
{
30623067
LOCK(cs_main);
30633068
for (const CBlockHeader& header : headers) {
3064-
if (!AcceptBlockHeader(header, state, chainparams, ppindex)) {
3069+
CBlockIndex *pindex = NULL; // Use a temp pindex instead of ppindex to avoid a const_cast
3070+
if (!AcceptBlockHeader(header, state, chainparams, &pindex)) {
30653071
return false;
30663072
}
3073+
if (ppindex) {
3074+
*ppindex = pindex;
3075+
}
30673076
}
30683077
}
30693078
NotifyHeaderTip();
30703079
return true;
30713080
}
30723081

30733082
/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */
3074-
static bool AcceptBlock(const CBlock& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock)
3083+
static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock)
30753084
{
3085+
const CBlock& block = *pblock;
3086+
30763087
if (fNewBlock) *fNewBlock = false;
30773088
AssertLockHeld(cs_main);
30783089

@@ -3118,6 +3129,11 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
31183129
return error("%s: %s", __func__, FormatStateMessage(state));
31193130
}
31203131

3132+
// Header is valid/has work, merkle tree and segwit merkle tree are good...RELAY NOW
3133+
// (but if it does not build on our best tip, let the SendMessages loop relay it)
3134+
if (!IsInitialBlockDownload() && chainActive.Tip() == pindex->pprev)
3135+
GetMainSignals().NewPoWValidBlock(pindex, pblock);
3136+
31213137
int nHeight = pindex->nHeight;
31223138

31233139
// Write block to history file
@@ -3152,7 +3168,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
31523168
CBlockIndex *pindex = NULL;
31533169
if (fNewBlock) *fNewBlock = false;
31543170
CValidationState state;
3155-
bool ret = AcceptBlock(*pblock, state, chainparams, &pindex, fForceProcessing, NULL, fNewBlock);
3171+
bool ret = AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, NULL, fNewBlock);
31563172
CheckBlockIndex(chainparams.GetConsensus());
31573173
if (!ret) {
31583174
GetMainSignals().BlockChecked(*pblock, state);
@@ -3808,7 +3824,8 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
38083824
dbp->nPos = nBlockPos;
38093825
blkdat.SetLimit(nBlockPos + nSize);
38103826
blkdat.SetPos(nBlockPos);
3811-
CBlock block;
3827+
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
3828+
CBlock& block = *pblock;
38123829
blkdat >> block;
38133830
nRewind = blkdat.GetPos();
38143831

@@ -3826,7 +3843,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
38263843
if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) {
38273844
LOCK(cs_main);
38283845
CValidationState state;
3829-
if (AcceptBlock(block, state, chainparams, NULL, true, dbp, NULL))
3846+
if (AcceptBlock(pblock, state, chainparams, NULL, true, dbp, NULL))
38303847
nLoaded++;
38313848
if (state.IsError())
38323849
break;
@@ -3853,16 +3870,17 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
38533870
std::pair<std::multimap<uint256, CDiskBlockPos>::iterator, std::multimap<uint256, CDiskBlockPos>::iterator> range = mapBlocksUnknownParent.equal_range(head);
38543871
while (range.first != range.second) {
38553872
std::multimap<uint256, CDiskBlockPos>::iterator it = range.first;
3856-
if (ReadBlockFromDisk(block, it->second, chainparams.GetConsensus()))
3873+
std::shared_ptr<CBlock> pblockrecursive = std::make_shared<CBlock>();
3874+
if (ReadBlockFromDisk(*pblockrecursive, it->second, chainparams.GetConsensus()))
38573875
{
3858-
LogPrint("reindex", "%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(),
3876+
LogPrint("reindex", "%s: Processing out of order child %s of %s\n", __func__, pblockrecursive->GetHash().ToString(),
38593877
head.ToString());
38603878
LOCK(cs_main);
38613879
CValidationState dummy;
3862-
if (AcceptBlock(block, dummy, chainparams, NULL, true, &it->second, NULL))
3880+
if (AcceptBlock(pblockrecursive, dummy, chainparams, NULL, true, &it->second, NULL))
38633881
{
38643882
nLoaded++;
3865-
queue.push_back(block.GetHash());
3883+
queue.push_back(pblockrecursive->GetHash());
38663884
}
38673885
}
38683886
range.first++;

src/validation.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
246246
* @param[in] chainparams The params for the chain we want to connect to
247247
* @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers
248248
*/
249-
bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex=NULL);
249+
bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex=NULL);
250250

251251
/** Check whether enough disk space is available for an incoming block */
252252
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);

src/validationinterface.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
2222
g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
2323
g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
2424
g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
25+
g_signals.NewPoWValidBlock.connect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
2526
}
2627

2728
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
@@ -34,6 +35,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
3435
g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
3536
g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3));
3637
g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
38+
g_signals.NewPoWValidBlock.disconnect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
3739
}
3840

3941
void UnregisterAllValidationInterfaces() {
@@ -46,4 +48,5 @@ void UnregisterAllValidationInterfaces() {
4648
g_signals.UpdatedTransaction.disconnect_all_slots();
4749
g_signals.SyncTransaction.disconnect_all_slots();
4850
g_signals.UpdatedBlockTip.disconnect_all_slots();
51+
g_signals.NewPoWValidBlock.disconnect_all_slots();
4952
}

src/validationinterface.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <boost/signals2/signal.hpp>
1010
#include <boost/shared_ptr.hpp>
11+
#include <memory>
1112

1213
class CBlock;
1314
class CBlockIndex;
@@ -40,6 +41,7 @@ class CValidationInterface {
4041
virtual void BlockChecked(const CBlock&, const CValidationState&) {}
4142
virtual void GetScriptForMining(boost::shared_ptr<CReserveScript>&) {};
4243
virtual void ResetRequestCount(const uint256 &hash) {};
44+
virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& block) {};
4345
friend void ::RegisterValidationInterface(CValidationInterface*);
4446
friend void ::UnregisterValidationInterface(CValidationInterface*);
4547
friend void ::UnregisterAllValidationInterfaces();
@@ -66,6 +68,10 @@ struct CMainSignals {
6668
boost::signals2::signal<void (boost::shared_ptr<CReserveScript>&)> ScriptForMining;
6769
/** Notifies listeners that a block has been successfully mined */
6870
boost::signals2::signal<void (const uint256 &)> BlockFound;
71+
/**
72+
* Notifies listeners that a block which builds directly on our current tip
73+
* has been received and connected to the headers tree, though not validated yet */
74+
boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
6975
};
7076

7177
CMainSignals& GetMainSignals();

0 commit comments

Comments
 (0)