Merge bitcoin/bitcoin#20295: rpc: getblockfrompeer

dce8c4c381 rpc: getblockfrompeer (Sjors Provoost)
b884ababc2 rpc: move Ensure* helpers to server_util.h (Sjors Provoost)

Pull request description:

  This adds an RPC method to fetch a block directly from a peer. This can used to fetch stale blocks with lower proof of work that are normally ignored by the node (`headers-only` in `getchaintips`).

  Usage:
  ```
  bitcoin-cli getblockfrompeer HASH peer_n
  ```

  Closes #20155

  Limitations:
  * you have to specify which peer to fetch the block from
  * the node must already have the header

ACKs for top commit:
  jnewbery:
    ACK dce8c4c381
  fjahr:
     re-ACK dce8c4c381

Tree-SHA512: 843ba2b7a308f640770d624d0aa3265fdc5c6ea48e8db32269b96a082b7420f7953d1d8d1ef2e6529392c7172dded9d15639fbc9c24e7bfa5cfb79e13a5498c8
This commit is contained in:
MarcoFalke
2021-12-08 10:38:10 +01:00
18 changed files with 296 additions and 93 deletions

View File

@@ -312,6 +312,7 @@ public:
/** Implement PeerManager */
void StartScheduledTasks(CScheduler& scheduler) override;
void CheckForStaleTipAndEvictPeers() override;
bool FetchBlock(NodeId id, const uint256& hash, const CBlockIndex& index) override;
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const override;
bool IgnoresIncomingTxs() override { return m_ignore_incoming_txs; }
void SendPings() override;
@@ -1427,6 +1428,41 @@ bool PeerManagerImpl::BlockRequestAllowed(const CBlockIndex* pindex)
(GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, m_chainparams.GetConsensus()) < STALE_RELAY_AGE_LIMIT);
}
bool PeerManagerImpl::FetchBlock(NodeId id, const uint256& hash, const CBlockIndex& index)
{
if (fImporting || fReindex) return false;
LOCK(cs_main);
// Ensure this peer exists and hasn't been disconnected
CNodeState* state = State(id);
if (state == nullptr) return false;
// Ignore pre-segwit peers
if (!state->fHaveWitness) return false;
// Mark block as in-flight unless it already is
if (!BlockRequested(id, index)) return false;
// Construct message to request the block
std::vector<CInv> invs{CInv(MSG_BLOCK | MSG_WITNESS_FLAG, hash)};
// Send block request message to the peer
bool success = m_connman.ForNode(id, [this, &invs](CNode* node) {
const CNetMsgMaker msgMaker(node->GetCommonVersion());
this->m_connman.PushMessage(node, msgMaker.Make(NetMsgType::GETDATA, invs));
return true;
});
if (success) {
LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n",
hash.ToString(), id);
} else {
RemoveBlockRequest(hash);
LogPrint(BCLog::NET, "Failed to request block %s from peer=%d\n",
hash.ToString(), id);
}
return success;
}
std::unique_ptr<PeerManager> PeerManager::make(const CChainParams& chainparams, CConnman& connman, AddrMan& addrman,
BanMan* banman, ChainstateManager& chainman,
CTxMemPool& pool, bool ignore_incoming_txs)