mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-13 11:25:02 -05:00
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)
This commit is contained in:
commit
3908fc4728
8 changed files with 225 additions and 65 deletions
|
@ -310,6 +310,9 @@ class CompactBlocksTest(BitcoinTestFramework):
|
||||||
tip = int(node.getbestblockhash(), 16)
|
tip = int(node.getbestblockhash(), 16)
|
||||||
assert(test_node.wait_for_block_announcement(tip))
|
assert(test_node.wait_for_block_announcement(tip))
|
||||||
|
|
||||||
|
# Make sure we will receive a fast-announce compact block
|
||||||
|
self.request_cb_announcements(test_node, node, version)
|
||||||
|
|
||||||
# Now mine a block, and look at the resulting compact block.
|
# Now mine a block, and look at the resulting compact block.
|
||||||
test_node.clear_block_announcement()
|
test_node.clear_block_announcement()
|
||||||
block_hash = int(node.generate(1)[0], 16)
|
block_hash = int(node.generate(1)[0], 16)
|
||||||
|
@ -319,27 +322,36 @@ class CompactBlocksTest(BitcoinTestFramework):
|
||||||
[tx.calc_sha256() for tx in block.vtx]
|
[tx.calc_sha256() for tx in block.vtx]
|
||||||
block.rehash()
|
block.rehash()
|
||||||
|
|
||||||
# Don't care which type of announcement came back for this test; just
|
# Wait until the block was announced (via compact blocks)
|
||||||
# request the compact block if we didn't get one yet.
|
|
||||||
wait_until(test_node.received_block_announcement, timeout=30)
|
wait_until(test_node.received_block_announcement, timeout=30)
|
||||||
assert(test_node.received_block_announcement())
|
assert(test_node.received_block_announcement())
|
||||||
|
|
||||||
with mininode_lock:
|
# Now fetch and check the compact block
|
||||||
if test_node.last_cmpctblock is None:
|
|
||||||
test_node.clear_block_announcement()
|
|
||||||
inv = CInv(4, block_hash) # 4 == "CompactBlock"
|
|
||||||
test_node.send_message(msg_getdata([inv]))
|
|
||||||
|
|
||||||
wait_until(test_node.received_block_announcement, timeout=30)
|
|
||||||
assert(test_node.received_block_announcement())
|
|
||||||
|
|
||||||
# Now we should have the compactblock
|
|
||||||
header_and_shortids = None
|
header_and_shortids = None
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
assert(test_node.last_cmpctblock is not None)
|
assert(test_node.last_cmpctblock is not None)
|
||||||
# Convert the on-the-wire representation to absolute indexes
|
# Convert the on-the-wire representation to absolute indexes
|
||||||
header_and_shortids = HeaderAndShortIDs(test_node.last_cmpctblock.header_and_shortids)
|
header_and_shortids = HeaderAndShortIDs(test_node.last_cmpctblock.header_and_shortids)
|
||||||
|
self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)
|
||||||
|
|
||||||
|
# Now fetch the compact block using a normal non-announce getdata
|
||||||
|
with mininode_lock:
|
||||||
|
test_node.clear_block_announcement()
|
||||||
|
inv = CInv(4, block_hash) # 4 == "CompactBlock"
|
||||||
|
test_node.send_message(msg_getdata([inv]))
|
||||||
|
|
||||||
|
wait_until(test_node.received_block_announcement, timeout=30)
|
||||||
|
assert(test_node.received_block_announcement())
|
||||||
|
|
||||||
|
# Now fetch and check the compact block
|
||||||
|
header_and_shortids = None
|
||||||
|
with mininode_lock:
|
||||||
|
assert(test_node.last_cmpctblock is not None)
|
||||||
|
# Convert the on-the-wire representation to absolute indexes
|
||||||
|
header_and_shortids = HeaderAndShortIDs(test_node.last_cmpctblock.header_and_shortids)
|
||||||
|
self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)
|
||||||
|
|
||||||
|
def check_compactblock_construction_from_block(self, version, header_and_shortids, block_hash, block):
|
||||||
# Check that we got the right block!
|
# Check that we got the right block!
|
||||||
header_and_shortids.header.calc_sha256()
|
header_and_shortids.header.calc_sha256()
|
||||||
assert_equal(header_and_shortids.header.sha256, block_hash)
|
assert_equal(header_and_shortids.header.sha256, block_hash)
|
||||||
|
|
|
@ -102,7 +102,7 @@ class PreciousTest(BitcoinTestFramework):
|
||||||
assert_equal(self.nodes[2].getblockcount(), 6)
|
assert_equal(self.nodes[2].getblockcount(), 6)
|
||||||
hashL = self.nodes[2].getbestblockhash()
|
hashL = self.nodes[2].getbestblockhash()
|
||||||
print("Connect nodes and check no reorg occurs")
|
print("Connect nodes and check no reorg occurs")
|
||||||
node_sync_via_rpc(self.nodes[0:3])
|
node_sync_via_rpc(self.nodes[1:3])
|
||||||
connect_nodes_bi(self.nodes,1,2)
|
connect_nodes_bi(self.nodes,1,2)
|
||||||
connect_nodes_bi(self.nodes,0,2)
|
connect_nodes_bi(self.nodes,0,2)
|
||||||
assert_equal(self.nodes[0].getbestblockhash(), hashH)
|
assert_equal(self.nodes[0].getbestblockhash(), hashH)
|
||||||
|
|
|
@ -101,7 +101,7 @@ namespace {
|
||||||
/** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
|
/** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
|
||||||
struct QueuedBlock {
|
struct QueuedBlock {
|
||||||
uint256 hash;
|
uint256 hash;
|
||||||
CBlockIndex* pindex; //!< Optional.
|
const CBlockIndex* pindex; //!< Optional.
|
||||||
bool fValidatedHeaders; //!< Whether this block has validated headers at the time of request.
|
bool fValidatedHeaders; //!< Whether this block has validated headers at the time of request.
|
||||||
std::unique_ptr<PartiallyDownloadedBlock> partialBlock; //!< Optional, used for CMPCTBLOCK downloads
|
std::unique_ptr<PartiallyDownloadedBlock> partialBlock; //!< Optional, used for CMPCTBLOCK downloads
|
||||||
};
|
};
|
||||||
|
@ -156,13 +156,13 @@ struct CNodeState {
|
||||||
//! List of asynchronously-determined block rejections to notify this peer about.
|
//! List of asynchronously-determined block rejections to notify this peer about.
|
||||||
std::vector<CBlockReject> rejects;
|
std::vector<CBlockReject> rejects;
|
||||||
//! The best known block we know this peer has announced.
|
//! The best known block we know this peer has announced.
|
||||||
CBlockIndex *pindexBestKnownBlock;
|
const CBlockIndex *pindexBestKnownBlock;
|
||||||
//! The hash of the last unknown block this peer has announced.
|
//! The hash of the last unknown block this peer has announced.
|
||||||
uint256 hashLastUnknownBlock;
|
uint256 hashLastUnknownBlock;
|
||||||
//! The last full block we both have.
|
//! The last full block we both have.
|
||||||
CBlockIndex *pindexLastCommonBlock;
|
const CBlockIndex *pindexLastCommonBlock;
|
||||||
//! The best header we have sent our peer.
|
//! The best header we have sent our peer.
|
||||||
CBlockIndex *pindexBestHeaderSent;
|
const CBlockIndex *pindexBestHeaderSent;
|
||||||
//! Length of current-streak of unconnecting headers announcements
|
//! Length of current-streak of unconnecting headers announcements
|
||||||
int nUnconnectingHeaders;
|
int nUnconnectingHeaders;
|
||||||
//! Whether we've started headers synchronization with this peer.
|
//! Whether we've started headers synchronization with this peer.
|
||||||
|
@ -331,7 +331,7 @@ bool MarkBlockAsReceived(const uint256& hash) {
|
||||||
// Requires cs_main.
|
// Requires cs_main.
|
||||||
// returns false, still setting pit, if the block was already in flight from the same peer
|
// returns false, still setting pit, if the block was already in flight from the same peer
|
||||||
// pit will only be valid as long as the same cs_main lock is being held
|
// pit will only be valid as long as the same cs_main lock is being held
|
||||||
bool MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Params& consensusParams, CBlockIndex *pindex = NULL, list<QueuedBlock>::iterator **pit = NULL) {
|
bool MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Params& consensusParams, const CBlockIndex *pindex = NULL, list<QueuedBlock>::iterator **pit = NULL) {
|
||||||
CNodeState *state = State(nodeid);
|
CNodeState *state = State(nodeid);
|
||||||
assert(state != NULL);
|
assert(state != NULL);
|
||||||
|
|
||||||
|
@ -432,7 +432,7 @@ bool CanDirectFetch(const Consensus::Params &consensusParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Requires cs_main
|
// Requires cs_main
|
||||||
bool PeerHasHeader(CNodeState *state, CBlockIndex *pindex)
|
bool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex)
|
||||||
{
|
{
|
||||||
if (state->pindexBestKnownBlock && pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight))
|
if (state->pindexBestKnownBlock && pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight))
|
||||||
return true;
|
return true;
|
||||||
|
@ -443,7 +443,7 @@ bool PeerHasHeader(CNodeState *state, CBlockIndex *pindex)
|
||||||
|
|
||||||
/** Find the last common ancestor two blocks have.
|
/** Find the last common ancestor two blocks have.
|
||||||
* Both pa and pb must be non-NULL. */
|
* Both pa and pb must be non-NULL. */
|
||||||
CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) {
|
const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex* pb) {
|
||||||
if (pa->nHeight > pb->nHeight) {
|
if (pa->nHeight > pb->nHeight) {
|
||||||
pa = pa->GetAncestor(pb->nHeight);
|
pa = pa->GetAncestor(pb->nHeight);
|
||||||
} else if (pb->nHeight > pa->nHeight) {
|
} else if (pb->nHeight > pa->nHeight) {
|
||||||
|
@ -462,7 +462,7 @@ CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) {
|
||||||
|
|
||||||
/** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has
|
/** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has
|
||||||
* at most count entries. */
|
* at most count entries. */
|
||||||
void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBlockIndex*>& vBlocks, NodeId& nodeStaller, const Consensus::Params& consensusParams) {
|
void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller, const Consensus::Params& consensusParams) {
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -490,8 +490,8 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBl
|
||||||
if (state->pindexLastCommonBlock == state->pindexBestKnownBlock)
|
if (state->pindexLastCommonBlock == state->pindexBestKnownBlock)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::vector<CBlockIndex*> vToFetch;
|
std::vector<const CBlockIndex*> vToFetch;
|
||||||
CBlockIndex *pindexWalk = state->pindexLastCommonBlock;
|
const CBlockIndex *pindexWalk = state->pindexLastCommonBlock;
|
||||||
// Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last
|
// Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last
|
||||||
// linked block we have in common with this peer. The +1 is so we can detect stalling, namely if we would be able to
|
// linked block we have in common with this peer. The +1 is so we can detect stalling, namely if we would be able to
|
||||||
// download that next block if the window were 1 larger.
|
// download that next block if the window were 1 larger.
|
||||||
|
@ -514,7 +514,7 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBl
|
||||||
// are not yet downloaded and not in flight to vBlocks. In the mean time, update
|
// are not yet downloaded and not in flight to vBlocks. In the mean time, update
|
||||||
// pindexLastCommonBlock as long as all ancestors are already downloaded, or if it's
|
// pindexLastCommonBlock as long as all ancestors are already downloaded, or if it's
|
||||||
// already part of our chain (and therefore don't need it even if pruned).
|
// already part of our chain (and therefore don't need it even if pruned).
|
||||||
BOOST_FOREACH(CBlockIndex* pindex, vToFetch) {
|
BOOST_FOREACH(const CBlockIndex* pindex, vToFetch) {
|
||||||
if (!pindex->IsValid(BLOCK_VALID_TREE)) {
|
if (!pindex->IsValid(BLOCK_VALID_TREE)) {
|
||||||
// We consider the chain that this peer is on invalid.
|
// We consider the chain that this peer is on invalid.
|
||||||
return;
|
return;
|
||||||
|
@ -752,6 +752,51 @@ void PeerLogicValidation::SyncTransaction(const CTransaction& tx, const CBlockIn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CCriticalSection cs_most_recent_block;
|
||||||
|
static std::shared_ptr<const CBlock> most_recent_block;
|
||||||
|
static std::shared_ptr<const CBlockHeaderAndShortTxIDs> most_recent_compact_block;
|
||||||
|
static uint256 most_recent_block_hash;
|
||||||
|
|
||||||
|
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);
|
||||||
|
CNetMsgMaker msgMaker(PROTOCOL_VERSION);
|
||||||
|
|
||||||
|
LOCK(cs_main);
|
||||||
|
|
||||||
|
static int nHighestFastAnnounce = 0;
|
||||||
|
if (pindex->nHeight <= nHighestFastAnnounce)
|
||||||
|
return;
|
||||||
|
nHighestFastAnnounce = pindex->nHeight;
|
||||||
|
|
||||||
|
bool fWitnessEnabled = IsWitnessEnabled(pindex->pprev, Params().GetConsensus());
|
||||||
|
uint256 hashBlock(pblock->GetHash());
|
||||||
|
|
||||||
|
{
|
||||||
|
LOCK(cs_most_recent_block);
|
||||||
|
most_recent_block_hash = hashBlock;
|
||||||
|
most_recent_block = pblock;
|
||||||
|
most_recent_compact_block = pcmpctblock;
|
||||||
|
}
|
||||||
|
|
||||||
|
connman->ForEachNode([this, &pcmpctblock, pindex, &msgMaker, fWitnessEnabled, &hashBlock](CNode* pnode) {
|
||||||
|
// TODO: Avoid the repeated-serialization here
|
||||||
|
if (pnode->nVersion < INVALID_CB_NO_BAN_VERSION || pnode->fDisconnect)
|
||||||
|
return;
|
||||||
|
ProcessBlockAvailability(pnode->GetId());
|
||||||
|
CNodeState &state = *State(pnode->GetId());
|
||||||
|
// If the peer has, or we announced to them the previous block already,
|
||||||
|
// but we don't think they have this one, go ahead and announce it
|
||||||
|
if (state.fPreferHeaderAndIDs && (!fWitnessEnabled || state.fWantsCmpctWitness) &&
|
||||||
|
!PeerHasHeader(&state, pindex) && PeerHasHeader(&state, pindex->pprev)) {
|
||||||
|
|
||||||
|
LogPrint("net", "%s sending header-and-ids %s to peer %d\n", "PeerLogicValidation::NewPoWValidBlock",
|
||||||
|
hashBlock.ToString(), pnode->id);
|
||||||
|
connman->PushMessage(pnode, msgMaker.Make(NetMsgType::CMPCTBLOCK, *pcmpctblock));
|
||||||
|
state.pindexBestHeaderSent = pindex;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
|
void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
|
||||||
const int nNewHeight = pindexNew->nHeight;
|
const int nNewHeight = pindexNew->nHeight;
|
||||||
connman->SetBestHeight(nNewHeight);
|
connman->SetBestHeight(nNewHeight);
|
||||||
|
@ -911,6 +956,21 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
|
||||||
BlockMap::iterator mi = mapBlockIndex.find(inv.hash);
|
BlockMap::iterator mi = mapBlockIndex.find(inv.hash);
|
||||||
if (mi != mapBlockIndex.end())
|
if (mi != mapBlockIndex.end())
|
||||||
{
|
{
|
||||||
|
if (mi->second->nChainTx && !mi->second->IsValid(BLOCK_VALID_SCRIPTS) &&
|
||||||
|
mi->second->IsValid(BLOCK_VALID_TREE)) {
|
||||||
|
// If we have the block and all of its parents, but have not yet validated it,
|
||||||
|
// we might be in the middle of connecting it (ie in the unlock of cs_main
|
||||||
|
// before ActivateBestChain but after AcceptBlock).
|
||||||
|
// In this case, we need to run ActivateBestChain prior to checking the relay
|
||||||
|
// conditions below.
|
||||||
|
std::shared_ptr<const CBlock> a_recent_block;
|
||||||
|
{
|
||||||
|
LOCK(cs_most_recent_block);
|
||||||
|
a_recent_block = most_recent_block;
|
||||||
|
}
|
||||||
|
CValidationState dummy;
|
||||||
|
ActivateBestChain(dummy, Params(), a_recent_block);
|
||||||
|
}
|
||||||
if (chainActive.Contains(mi->second)) {
|
if (chainActive.Contains(mi->second)) {
|
||||||
send = true;
|
send = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1048,7 +1108,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t GetFetchFlags(CNode* pfrom, CBlockIndex* pprev, const Consensus::Params& chainparams) {
|
uint32_t GetFetchFlags(CNode* pfrom, const CBlockIndex* pprev, const Consensus::Params& chainparams) {
|
||||||
uint32_t nFetchFlags = 0;
|
uint32_t nFetchFlags = 0;
|
||||||
if ((pfrom->GetLocalServices() & NODE_WITNESS) && State(pfrom->GetId())->fHaveWitness) {
|
if ((pfrom->GetLocalServices() & NODE_WITNESS) && State(pfrom->GetId())->fHaveWitness) {
|
||||||
nFetchFlags |= MSG_WITNESS_FLAG;
|
nFetchFlags |= MSG_WITNESS_FLAG;
|
||||||
|
@ -1056,6 +1116,23 @@ uint32_t GetFetchFlags(CNode* pfrom, CBlockIndex* pprev, const Consensus::Params
|
||||||
return nFetchFlags;
|
return nFetchFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void static SendBlockTransactions(const CBlock& block, const BlockTransactionsRequest& req, CNode* pfrom, CConnman& connman) {
|
||||||
|
BlockTransactions resp(req);
|
||||||
|
for (size_t i = 0; i < req.indexes.size(); i++) {
|
||||||
|
if (req.indexes[i] >= block.vtx.size()) {
|
||||||
|
LOCK(cs_main);
|
||||||
|
Misbehaving(pfrom->GetId(), 100);
|
||||||
|
LogPrintf("Peer %d sent us a getblocktxn with out-of-bounds tx indices", pfrom->id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resp.txn[i] = block.vtx[req.indexes[i]];
|
||||||
|
}
|
||||||
|
LOCK(cs_main);
|
||||||
|
CNetMsgMaker msgMaker(pfrom->GetSendVersion());
|
||||||
|
int nSendFlags = State(pfrom->GetId())->fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
|
||||||
|
connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp));
|
||||||
|
}
|
||||||
|
|
||||||
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman& connman, std::atomic<bool>& interruptMsgProc)
|
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman& connman, std::atomic<bool>& interruptMsgProc)
|
||||||
{
|
{
|
||||||
LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id);
|
LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id);
|
||||||
|
@ -1445,10 +1522,27 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||||
uint256 hashStop;
|
uint256 hashStop;
|
||||||
vRecv >> locator >> hashStop;
|
vRecv >> locator >> hashStop;
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
// To avoid this situation we simply verify that we are on our best
|
||||||
|
// known chain now. This is super overkill, but we handle it better
|
||||||
|
// for getheaders requests, and there are no known nodes which support
|
||||||
|
// compact blocks but still use getblocks to request blocks.
|
||||||
|
{
|
||||||
|
std::shared_ptr<const CBlock> a_recent_block;
|
||||||
|
{
|
||||||
|
LOCK(cs_most_recent_block);
|
||||||
|
a_recent_block = most_recent_block;
|
||||||
|
}
|
||||||
|
CValidationState dummy;
|
||||||
|
ActivateBestChain(dummy, Params(), a_recent_block);
|
||||||
|
}
|
||||||
|
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
// Find the last block the caller has in the main chain
|
// Find the last block the caller has in the main chain
|
||||||
CBlockIndex* pindex = FindForkInGlobalIndex(chainActive, locator);
|
const CBlockIndex* pindex = FindForkInGlobalIndex(chainActive, locator);
|
||||||
|
|
||||||
// Send the rest of the chain
|
// Send the rest of the chain
|
||||||
if (pindex)
|
if (pindex)
|
||||||
|
@ -1488,6 +1582,18 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||||
BlockTransactionsRequest req;
|
BlockTransactionsRequest req;
|
||||||
vRecv >> req;
|
vRecv >> req;
|
||||||
|
|
||||||
|
std::shared_ptr<const CBlock> recent_block;
|
||||||
|
{
|
||||||
|
LOCK(cs_most_recent_block);
|
||||||
|
if (most_recent_block_hash == req.blockhash)
|
||||||
|
recent_block = most_recent_block;
|
||||||
|
// Unlock cs_most_recent_block to avoid cs_main lock inversion
|
||||||
|
}
|
||||||
|
if (recent_block) {
|
||||||
|
SendBlockTransactions(*recent_block, req, pfrom, connman);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
BlockMap::iterator it = mapBlockIndex.find(req.blockhash);
|
BlockMap::iterator it = mapBlockIndex.find(req.blockhash);
|
||||||
|
@ -1517,17 +1623,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||||
bool ret = ReadBlockFromDisk(block, it->second, chainparams.GetConsensus());
|
bool ret = ReadBlockFromDisk(block, it->second, chainparams.GetConsensus());
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
BlockTransactions resp(req);
|
SendBlockTransactions(block, req, pfrom, connman);
|
||||||
for (size_t i = 0; i < req.indexes.size(); i++) {
|
|
||||||
if (req.indexes[i] >= block.vtx.size()) {
|
|
||||||
Misbehaving(pfrom->GetId(), 100);
|
|
||||||
LogPrintf("Peer %d sent us a getblocktxn with out-of-bounds tx indices", pfrom->id);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
resp.txn[i] = block.vtx[req.indexes[i]];
|
|
||||||
}
|
|
||||||
int nSendFlags = State(pfrom->GetId())->fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
|
|
||||||
connman.PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1544,7 +1640,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||||
}
|
}
|
||||||
|
|
||||||
CNodeState *nodestate = State(pfrom->GetId());
|
CNodeState *nodestate = State(pfrom->GetId());
|
||||||
CBlockIndex* pindex = NULL;
|
const CBlockIndex* pindex = NULL;
|
||||||
if (locator.IsNull())
|
if (locator.IsNull())
|
||||||
{
|
{
|
||||||
// If locator is null, return the hashStop block
|
// If locator is null, return the hashStop block
|
||||||
|
@ -1575,6 +1671,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||||
// if our peer has chainActive.Tip() (and thus we are sending an empty
|
// if our peer has chainActive.Tip() (and thus we are sending an empty
|
||||||
// headers message). In both cases it's safe to update
|
// headers message). In both cases it's safe to update
|
||||||
// pindexBestHeaderSent to be our tip.
|
// pindexBestHeaderSent to be our tip.
|
||||||
|
//
|
||||||
|
// It is important that we simply reset the BestHeaderSent value here,
|
||||||
|
// and not max(BestHeaderSent, newHeaderSent). We might have announced
|
||||||
|
// the currently-being-connected tip using a compact block, which
|
||||||
|
// resulted in the peer sending a headers request, which we respond to
|
||||||
|
// without the new block. By resetting the BestHeaderSent, we ensure we
|
||||||
|
// will re-announce the new block via headers (or compact blocks again)
|
||||||
|
// in the SendMessages logic.
|
||||||
nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip();
|
nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip();
|
||||||
connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
|
connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
|
||||||
}
|
}
|
||||||
|
@ -1770,7 +1874,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CBlockIndex *pindex = NULL;
|
const CBlockIndex *pindex = NULL;
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
if (!ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) {
|
if (!ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) {
|
||||||
int nDoS;
|
int nDoS;
|
||||||
|
@ -2046,7 +2150,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CBlockIndex *pindexLast = NULL;
|
const CBlockIndex *pindexLast = NULL;
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
CNodeState *nodestate = State(pfrom->GetId());
|
CNodeState *nodestate = State(pfrom->GetId());
|
||||||
|
@ -2123,8 +2227,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||||
// If this set of headers is valid and ends in a block with at least as
|
// If this set of headers is valid and ends in a block with at least as
|
||||||
// much work as our tip, download as much as possible.
|
// much work as our tip, download as much as possible.
|
||||||
if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork) {
|
if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork) {
|
||||||
vector<CBlockIndex *> vToFetch;
|
vector<const CBlockIndex *> vToFetch;
|
||||||
CBlockIndex *pindexWalk = pindexLast;
|
const CBlockIndex *pindexWalk = pindexLast;
|
||||||
// Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
|
// Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
|
||||||
while (pindexWalk && !chainActive.Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
|
while (pindexWalk && !chainActive.Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
|
||||||
if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
|
if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
|
||||||
|
@ -2146,7 +2250,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||||
} else {
|
} else {
|
||||||
vector<CInv> vGetData;
|
vector<CInv> vGetData;
|
||||||
// Download as much as possible, from earliest to latest.
|
// Download as much as possible, from earliest to latest.
|
||||||
BOOST_REVERSE_FOREACH(CBlockIndex *pindex, vToFetch) {
|
BOOST_REVERSE_FOREACH(const CBlockIndex *pindex, vToFetch) {
|
||||||
if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
|
if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
|
||||||
// Can't download any more from this peer
|
// Can't download any more from this peer
|
||||||
break;
|
break;
|
||||||
|
@ -2727,7 +2831,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
|
||||||
bool fRevertToInv = ((!state.fPreferHeaders &&
|
bool fRevertToInv = ((!state.fPreferHeaders &&
|
||||||
(!state.fPreferHeaderAndIDs || pto->vBlockHashesToAnnounce.size() > 1)) ||
|
(!state.fPreferHeaderAndIDs || pto->vBlockHashesToAnnounce.size() > 1)) ||
|
||||||
pto->vBlockHashesToAnnounce.size() > MAX_BLOCKS_TO_ANNOUNCE);
|
pto->vBlockHashesToAnnounce.size() > MAX_BLOCKS_TO_ANNOUNCE);
|
||||||
CBlockIndex *pBestIndex = NULL; // last header queued for delivery
|
const CBlockIndex *pBestIndex = NULL; // last header queued for delivery
|
||||||
ProcessBlockAvailability(pto->id); // ensure pindexBestKnownBlock is up-to-date
|
ProcessBlockAvailability(pto->id); // ensure pindexBestKnownBlock is up-to-date
|
||||||
|
|
||||||
if (!fRevertToInv) {
|
if (!fRevertToInv) {
|
||||||
|
@ -2738,7 +2842,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
|
||||||
BOOST_FOREACH(const uint256 &hash, pto->vBlockHashesToAnnounce) {
|
BOOST_FOREACH(const uint256 &hash, pto->vBlockHashesToAnnounce) {
|
||||||
BlockMap::iterator mi = mapBlockIndex.find(hash);
|
BlockMap::iterator mi = mapBlockIndex.find(hash);
|
||||||
assert(mi != mapBlockIndex.end());
|
assert(mi != mapBlockIndex.end());
|
||||||
CBlockIndex *pindex = mi->second;
|
const CBlockIndex *pindex = mi->second;
|
||||||
if (chainActive[pindex->nHeight] != pindex) {
|
if (chainActive[pindex->nHeight] != pindex) {
|
||||||
// Bail out if we reorged away from this block
|
// Bail out if we reorged away from this block
|
||||||
fRevertToInv = true;
|
fRevertToInv = true;
|
||||||
|
@ -2784,13 +2888,29 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
|
||||||
// probably means we're doing an initial-ish-sync or they're slow
|
// probably means we're doing an initial-ish-sync or they're slow
|
||||||
LogPrint("net", "%s sending header-and-ids %s to peer %d\n", __func__,
|
LogPrint("net", "%s sending header-and-ids %s to peer %d\n", __func__,
|
||||||
vHeaders.front().GetHash().ToString(), pto->id);
|
vHeaders.front().GetHash().ToString(), pto->id);
|
||||||
//TODO: Shouldn't need to reload block from disk, but requires refactor
|
|
||||||
CBlock block;
|
|
||||||
bool ret = ReadBlockFromDisk(block, pBestIndex, consensusParams);
|
|
||||||
assert(ret);
|
|
||||||
CBlockHeaderAndShortTxIDs cmpctblock(block, state.fWantsCmpctWitness);
|
|
||||||
int nSendFlags = state.fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
|
int nSendFlags = state.fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
|
||||||
connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
|
|
||||||
|
bool fGotBlockFromCache = false;
|
||||||
|
{
|
||||||
|
LOCK(cs_most_recent_block);
|
||||||
|
if (most_recent_block_hash == pBestIndex->GetBlockHash()) {
|
||||||
|
if (state.fWantsCmpctWitness)
|
||||||
|
connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *most_recent_compact_block));
|
||||||
|
else {
|
||||||
|
CBlockHeaderAndShortTxIDs cmpctblock(*most_recent_block, state.fWantsCmpctWitness);
|
||||||
|
connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
|
||||||
|
}
|
||||||
|
fGotBlockFromCache = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!fGotBlockFromCache) {
|
||||||
|
CBlock block;
|
||||||
|
bool ret = ReadBlockFromDisk(block, pBestIndex, consensusParams);
|
||||||
|
assert(ret);
|
||||||
|
CBlockHeaderAndShortTxIDs cmpctblock(block, state.fWantsCmpctWitness);
|
||||||
|
connman.PushMessage(pto, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, cmpctblock));
|
||||||
|
}
|
||||||
state.pindexBestHeaderSent = pBestIndex;
|
state.pindexBestHeaderSent = pBestIndex;
|
||||||
} else if (state.fPreferHeaders) {
|
} else if (state.fPreferHeaders) {
|
||||||
if (vHeaders.size() > 1) {
|
if (vHeaders.size() > 1) {
|
||||||
|
@ -2815,7 +2935,7 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
|
||||||
const uint256 &hashToAnnounce = pto->vBlockHashesToAnnounce.back();
|
const uint256 &hashToAnnounce = pto->vBlockHashesToAnnounce.back();
|
||||||
BlockMap::iterator mi = mapBlockIndex.find(hashToAnnounce);
|
BlockMap::iterator mi = mapBlockIndex.find(hashToAnnounce);
|
||||||
assert(mi != mapBlockIndex.end());
|
assert(mi != mapBlockIndex.end());
|
||||||
CBlockIndex *pindex = mi->second;
|
const CBlockIndex *pindex = mi->second;
|
||||||
|
|
||||||
// Warn if we're announcing a block that is not on the main chain.
|
// Warn if we're announcing a block that is not on the main chain.
|
||||||
// This should be very rare and could be optimized out.
|
// This should be very rare and could be optimized out.
|
||||||
|
@ -3000,10 +3120,10 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
|
||||||
//
|
//
|
||||||
vector<CInv> vGetData;
|
vector<CInv> vGetData;
|
||||||
if (!pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
|
if (!pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
|
||||||
vector<CBlockIndex*> vToDownload;
|
vector<const CBlockIndex*> vToDownload;
|
||||||
NodeId staller = -1;
|
NodeId staller = -1;
|
||||||
FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams);
|
FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams);
|
||||||
BOOST_FOREACH(CBlockIndex *pindex, vToDownload) {
|
BOOST_FOREACH(const CBlockIndex *pindex, vToDownload) {
|
||||||
uint32_t nFetchFlags = GetFetchFlags(pto, pindex->pprev, consensusParams);
|
uint32_t nFetchFlags = GetFetchFlags(pto, pindex->pprev, consensusParams);
|
||||||
vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
|
vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
|
||||||
MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex);
|
MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex);
|
||||||
|
|
|
@ -24,6 +24,7 @@ public:
|
||||||
virtual void SyncTransaction(const CTransaction& tx, const CBlockIndex* pindex, int nPosInBlock);
|
virtual void SyncTransaction(const CTransaction& tx, const CBlockIndex* pindex, int nPosInBlock);
|
||||||
virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload);
|
virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload);
|
||||||
virtual void BlockChecked(const CBlock& block, const CValidationState& state);
|
virtual void BlockChecked(const CBlock& block, const CValidationState& state);
|
||||||
|
virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CNodeStateStats {
|
struct CNodeStateStats {
|
||||||
|
|
|
@ -2414,6 +2414,11 @@ static void NotifyHeaderTip() {
|
||||||
* that is already loaded (to avoid loading it again from disk).
|
* that is already loaded (to avoid loading it again from disk).
|
||||||
*/
|
*/
|
||||||
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
|
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
|
||||||
|
// Note that while we're often called here from ProcessNewBlock, this is
|
||||||
|
// far from a guarantee. Things in the P2P/RPC will often end up calling
|
||||||
|
// us in the middle of ProcessNewBlock - do not assume pblock is set
|
||||||
|
// sanely for performance or correctness!
|
||||||
|
|
||||||
CBlockIndex *pindexMostWork = NULL;
|
CBlockIndex *pindexMostWork = NULL;
|
||||||
CBlockIndex *pindexNewTip = NULL;
|
CBlockIndex *pindexNewTip = NULL;
|
||||||
do {
|
do {
|
||||||
|
@ -3056,14 +3061,18 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exposed wrapper for AcceptBlockHeader
|
// Exposed wrapper for AcceptBlockHeader
|
||||||
bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex)
|
bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
for (const CBlockHeader& header : headers) {
|
for (const CBlockHeader& header : headers) {
|
||||||
if (!AcceptBlockHeader(header, state, chainparams, ppindex)) {
|
CBlockIndex *pindex = NULL; // Use a temp pindex instead of ppindex to avoid a const_cast
|
||||||
|
if (!AcceptBlockHeader(header, state, chainparams, &pindex)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (ppindex) {
|
||||||
|
*ppindex = pindex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NotifyHeaderTip();
|
NotifyHeaderTip();
|
||||||
|
@ -3071,8 +3080,10 @@ bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidatio
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */
|
/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */
|
||||||
static bool AcceptBlock(const CBlock& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock)
|
static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock)
|
||||||
{
|
{
|
||||||
|
const CBlock& block = *pblock;
|
||||||
|
|
||||||
if (fNewBlock) *fNewBlock = false;
|
if (fNewBlock) *fNewBlock = false;
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
|
|
||||||
|
@ -3118,6 +3129,11 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
|
||||||
return error("%s: %s", __func__, FormatStateMessage(state));
|
return error("%s: %s", __func__, FormatStateMessage(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Header is valid/has work, merkle tree and segwit merkle tree are good...RELAY NOW
|
||||||
|
// (but if it does not build on our best tip, let the SendMessages loop relay it)
|
||||||
|
if (!IsInitialBlockDownload() && chainActive.Tip() == pindex->pprev)
|
||||||
|
GetMainSignals().NewPoWValidBlock(pindex, pblock);
|
||||||
|
|
||||||
int nHeight = pindex->nHeight;
|
int nHeight = pindex->nHeight;
|
||||||
|
|
||||||
// Write block to history file
|
// Write block to history file
|
||||||
|
@ -3152,7 +3168,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
|
||||||
CBlockIndex *pindex = NULL;
|
CBlockIndex *pindex = NULL;
|
||||||
if (fNewBlock) *fNewBlock = false;
|
if (fNewBlock) *fNewBlock = false;
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
bool ret = AcceptBlock(*pblock, state, chainparams, &pindex, fForceProcessing, NULL, fNewBlock);
|
bool ret = AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, NULL, fNewBlock);
|
||||||
CheckBlockIndex(chainparams.GetConsensus());
|
CheckBlockIndex(chainparams.GetConsensus());
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
GetMainSignals().BlockChecked(*pblock, state);
|
GetMainSignals().BlockChecked(*pblock, state);
|
||||||
|
@ -3808,7 +3824,8 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
|
||||||
dbp->nPos = nBlockPos;
|
dbp->nPos = nBlockPos;
|
||||||
blkdat.SetLimit(nBlockPos + nSize);
|
blkdat.SetLimit(nBlockPos + nSize);
|
||||||
blkdat.SetPos(nBlockPos);
|
blkdat.SetPos(nBlockPos);
|
||||||
CBlock block;
|
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
|
||||||
|
CBlock& block = *pblock;
|
||||||
blkdat >> block;
|
blkdat >> block;
|
||||||
nRewind = blkdat.GetPos();
|
nRewind = blkdat.GetPos();
|
||||||
|
|
||||||
|
@ -3826,7 +3843,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
|
||||||
if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) {
|
if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) {
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
if (AcceptBlock(block, state, chainparams, NULL, true, dbp, NULL))
|
if (AcceptBlock(pblock, state, chainparams, NULL, true, dbp, NULL))
|
||||||
nLoaded++;
|
nLoaded++;
|
||||||
if (state.IsError())
|
if (state.IsError())
|
||||||
break;
|
break;
|
||||||
|
@ -3853,16 +3870,17 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
|
||||||
std::pair<std::multimap<uint256, CDiskBlockPos>::iterator, std::multimap<uint256, CDiskBlockPos>::iterator> range = mapBlocksUnknownParent.equal_range(head);
|
std::pair<std::multimap<uint256, CDiskBlockPos>::iterator, std::multimap<uint256, CDiskBlockPos>::iterator> range = mapBlocksUnknownParent.equal_range(head);
|
||||||
while (range.first != range.second) {
|
while (range.first != range.second) {
|
||||||
std::multimap<uint256, CDiskBlockPos>::iterator it = range.first;
|
std::multimap<uint256, CDiskBlockPos>::iterator it = range.first;
|
||||||
if (ReadBlockFromDisk(block, it->second, chainparams.GetConsensus()))
|
std::shared_ptr<CBlock> pblockrecursive = std::make_shared<CBlock>();
|
||||||
|
if (ReadBlockFromDisk(*pblockrecursive, it->second, chainparams.GetConsensus()))
|
||||||
{
|
{
|
||||||
LogPrint("reindex", "%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(),
|
LogPrint("reindex", "%s: Processing out of order child %s of %s\n", __func__, pblockrecursive->GetHash().ToString(),
|
||||||
head.ToString());
|
head.ToString());
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
CValidationState dummy;
|
CValidationState dummy;
|
||||||
if (AcceptBlock(block, dummy, chainparams, NULL, true, &it->second, NULL))
|
if (AcceptBlock(pblockrecursive, dummy, chainparams, NULL, true, &it->second, NULL))
|
||||||
{
|
{
|
||||||
nLoaded++;
|
nLoaded++;
|
||||||
queue.push_back(block.GetHash());
|
queue.push_back(pblockrecursive->GetHash());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
range.first++;
|
range.first++;
|
||||||
|
|
|
@ -246,7 +246,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
|
||||||
* @param[in] chainparams The params for the chain we want to connect to
|
* @param[in] chainparams The params for the chain we want to connect to
|
||||||
* @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers
|
* @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers
|
||||||
*/
|
*/
|
||||||
bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex=NULL);
|
bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex=NULL);
|
||||||
|
|
||||||
/** Check whether enough disk space is available for an incoming block */
|
/** Check whether enough disk space is available for an incoming block */
|
||||||
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
|
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
|
||||||
|
|
|
@ -22,6 +22,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
|
||||||
g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
|
g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
|
||||||
g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
|
g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
|
||||||
g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
|
g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
|
||||||
|
g_signals.NewPoWValidBlock.connect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
|
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
|
||||||
|
@ -34,6 +35,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
|
||||||
g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
|
g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
|
||||||
g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3));
|
g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3));
|
||||||
g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
|
g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
|
||||||
|
g_signals.NewPoWValidBlock.disconnect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnregisterAllValidationInterfaces() {
|
void UnregisterAllValidationInterfaces() {
|
||||||
|
@ -46,4 +48,5 @@ void UnregisterAllValidationInterfaces() {
|
||||||
g_signals.UpdatedTransaction.disconnect_all_slots();
|
g_signals.UpdatedTransaction.disconnect_all_slots();
|
||||||
g_signals.SyncTransaction.disconnect_all_slots();
|
g_signals.SyncTransaction.disconnect_all_slots();
|
||||||
g_signals.UpdatedBlockTip.disconnect_all_slots();
|
g_signals.UpdatedBlockTip.disconnect_all_slots();
|
||||||
|
g_signals.NewPoWValidBlock.disconnect_all_slots();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <boost/signals2/signal.hpp>
|
#include <boost/signals2/signal.hpp>
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
class CBlock;
|
class CBlock;
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
|
@ -40,6 +41,7 @@ protected:
|
||||||
virtual void BlockChecked(const CBlock&, const CValidationState&) {}
|
virtual void BlockChecked(const CBlock&, const CValidationState&) {}
|
||||||
virtual void GetScriptForMining(boost::shared_ptr<CReserveScript>&) {};
|
virtual void GetScriptForMining(boost::shared_ptr<CReserveScript>&) {};
|
||||||
virtual void ResetRequestCount(const uint256 &hash) {};
|
virtual void ResetRequestCount(const uint256 &hash) {};
|
||||||
|
virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& block) {};
|
||||||
friend void ::RegisterValidationInterface(CValidationInterface*);
|
friend void ::RegisterValidationInterface(CValidationInterface*);
|
||||||
friend void ::UnregisterValidationInterface(CValidationInterface*);
|
friend void ::UnregisterValidationInterface(CValidationInterface*);
|
||||||
friend void ::UnregisterAllValidationInterfaces();
|
friend void ::UnregisterAllValidationInterfaces();
|
||||||
|
@ -66,6 +68,10 @@ struct CMainSignals {
|
||||||
boost::signals2::signal<void (boost::shared_ptr<CReserveScript>&)> ScriptForMining;
|
boost::signals2::signal<void (boost::shared_ptr<CReserveScript>&)> ScriptForMining;
|
||||||
/** Notifies listeners that a block has been successfully mined */
|
/** Notifies listeners that a block has been successfully mined */
|
||||||
boost::signals2::signal<void (const uint256 &)> BlockFound;
|
boost::signals2::signal<void (const uint256 &)> BlockFound;
|
||||||
|
/**
|
||||||
|
* Notifies listeners that a block which builds directly on our current tip
|
||||||
|
* has been received and connected to the headers tree, though not validated yet */
|
||||||
|
boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
|
||||||
};
|
};
|
||||||
|
|
||||||
CMainSignals& GetMainSignals();
|
CMainSignals& GetMainSignals();
|
||||||
|
|
Loading…
Add table
Reference in a new issue