|
|
|
@ -331,6 +331,8 @@ struct CNodeState {
|
|
|
|
|
bool fHaveMWEB;
|
|
|
|
|
//! Whether this peer wants witnesses in cmpctblocks/blocktxns
|
|
|
|
|
bool fWantsCmpctWitness;
|
|
|
|
|
//! Whether this peer wants MWEB transactions in cmpctblocks/blocktxns
|
|
|
|
|
bool fWantsCmpctMWEB;
|
|
|
|
|
/**
|
|
|
|
|
* If we've announced NODE_WITNESS to this peer: whether the peer sends witnesses in cmpctblocks/blocktxns,
|
|
|
|
|
* otherwise: whether this peer sends non-witnesses in cmpctblocks/blocktxns.
|
|
|
|
@ -411,6 +413,7 @@ struct CNodeState {
|
|
|
|
|
fHaveWitness = false;
|
|
|
|
|
fHaveMWEB = false;
|
|
|
|
|
fWantsCmpctWitness = false;
|
|
|
|
|
fWantsCmpctMWEB = false;
|
|
|
|
|
fSupportsDesiredCmpctVersion = false;
|
|
|
|
|
m_chain_sync = { 0, nullptr, false, false };
|
|
|
|
|
m_last_block_announcement = 0;
|
|
|
|
@ -558,9 +561,12 @@ static bool MarkBlockAsInFlight(CTxMemPool& mempool, NodeId nodeid, const uint25
|
|
|
|
|
|
|
|
|
|
// Make sure it's not listed somewhere already.
|
|
|
|
|
MarkBlockAsReceived(hash);
|
|
|
|
|
|
|
|
|
|
MWEB::Block mweb_block;
|
|
|
|
|
if (pit && (*pit)) {
|
|
|
|
|
mweb_block = (*(*pit))->partialBlock->mweb_block;
|
|
|
|
|
}
|
|
|
|
|
std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(),
|
|
|
|
|
{hash, pindex, pindex != nullptr, std::unique_ptr<PartiallyDownloadedBlock>(pit ? new PartiallyDownloadedBlock(&mempool) : nullptr)});
|
|
|
|
|
{hash, pindex, pindex != nullptr, std::unique_ptr<PartiallyDownloadedBlock>(pit ? new PartiallyDownloadedBlock(&mempool, mweb_block) : nullptr)});
|
|
|
|
|
state->nBlocksInFlight++;
|
|
|
|
|
state->nBlocksInFlightValidHeaders += it->fValidatedHeaders;
|
|
|
|
|
if (state->nBlocksInFlight == 1) {
|
|
|
|
@ -635,7 +641,7 @@ static void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman& connma
|
|
|
|
|
}
|
|
|
|
|
connman.ForNode(nodeid, [&connman](CNode* pfrom) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
|
|
|
|
|
AssertLockHeld(::cs_main);
|
|
|
|
|
uint64_t nCMPCTBLOCKVersion = (pfrom->GetLocalServices() & NODE_WITNESS) ? 2 : 1;
|
|
|
|
|
uint64_t nCMPCTBLOCKVersion = pfrom->GetCmpctBlockVersion();
|
|
|
|
|
if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
|
|
|
|
|
// As per BIP152, we only get 3 of our peers to announce
|
|
|
|
|
// blocks using compact encodings.
|
|
|
|
@ -1278,6 +1284,7 @@ static std::shared_ptr<const CBlock> most_recent_block GUARDED_BY(cs_most_recent
|
|
|
|
|
static std::shared_ptr<const CBlockHeaderAndShortTxIDs> most_recent_compact_block GUARDED_BY(cs_most_recent_block);
|
|
|
|
|
static uint256 most_recent_block_hash GUARDED_BY(cs_most_recent_block);
|
|
|
|
|
static bool fWitnessesPresentInMostRecentCompactBlock GUARDED_BY(cs_most_recent_block);
|
|
|
|
|
static bool fMWEBPresentInMostRecentCompactBlock GUARDED_BY(cs_most_recent_block);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Maintain state about the best-seen block and fast-announce a compact block
|
|
|
|
@ -1295,6 +1302,7 @@ void PeerManager::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_
|
|
|
|
|
nHighestFastAnnounce = pindex->nHeight;
|
|
|
|
|
|
|
|
|
|
bool fWitnessEnabled = IsWitnessEnabled(pindex->pprev, m_chainparams.GetConsensus());
|
|
|
|
|
bool mweb_enabled = IsMWEBEnabled(pindex->pprev, m_chainparams.GetConsensus());
|
|
|
|
|
uint256 hashBlock(pblock->GetHash());
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
@ -1303,9 +1311,10 @@ void PeerManager::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_
|
|
|
|
|
most_recent_block = pblock;
|
|
|
|
|
most_recent_compact_block = pcmpctblock;
|
|
|
|
|
fWitnessesPresentInMostRecentCompactBlock = fWitnessEnabled;
|
|
|
|
|
fMWEBPresentInMostRecentCompactBlock = mweb_enabled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_connman.ForEachNode([this, &pcmpctblock, pindex, &msgMaker, fWitnessEnabled, &hashBlock](CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
|
|
|
|
|
m_connman.ForEachNode([this, &pcmpctblock, pindex, &msgMaker, fWitnessEnabled, mweb_enabled, &hashBlock](CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
|
|
|
|
|
AssertLockHeld(::cs_main);
|
|
|
|
|
|
|
|
|
|
// TODO: Avoid the repeated-serialization here
|
|
|
|
@ -1316,11 +1325,17 @@ void PeerManager::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_
|
|
|
|
|
// 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) &&
|
|
|
|
|
(!mweb_enabled || state.fWantsCmpctMWEB) &&
|
|
|
|
|
!PeerHasHeader(&state, pindex) && PeerHasHeader(&state, pindex->pprev)) {
|
|
|
|
|
|
|
|
|
|
bool fPeerWantsWitness = State(pnode->GetId())->fWantsCmpctWitness;
|
|
|
|
|
bool fPeerWantsMWEB = State(pnode->GetId())->fWantsCmpctMWEB;
|
|
|
|
|
int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
|
|
|
|
|
nSendFlags |= fPeerWantsMWEB ? 0 : SERIALIZE_NO_MWEB;
|
|
|
|
|
|
|
|
|
|
LogPrint(BCLog::NET, "%s sending header-and-ids %s to peer=%d\n", "PeerManager::NewPoWValidBlock",
|
|
|
|
|
hashBlock.ToString(), pnode->GetId());
|
|
|
|
|
m_connman.PushMessage(pnode, msgMaker.Make(NetMsgType::CMPCTBLOCK, *pcmpctblock));
|
|
|
|
|
m_connman.PushMessage(pnode, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *pcmpctblock));
|
|
|
|
|
state.pindexBestHeaderSent = pindex;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
@ -1497,12 +1512,14 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
|
|
|
|
|
std::shared_ptr<const CBlock> a_recent_block;
|
|
|
|
|
std::shared_ptr<const CBlockHeaderAndShortTxIDs> a_recent_compact_block;
|
|
|
|
|
bool fWitnessesPresentInARecentCompactBlock;
|
|
|
|
|
bool fMWEBPresentInARecentCompactBlock;
|
|
|
|
|
const Consensus::Params& consensusParams = chainparams.GetConsensus();
|
|
|
|
|
{
|
|
|
|
|
LOCK(cs_most_recent_block);
|
|
|
|
|
a_recent_block = most_recent_block;
|
|
|
|
|
a_recent_compact_block = most_recent_compact_block;
|
|
|
|
|
fWitnessesPresentInARecentCompactBlock = fWitnessesPresentInMostRecentCompactBlock;
|
|
|
|
|
fMWEBPresentInARecentCompactBlock = fMWEBPresentInMostRecentCompactBlock;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool need_activate_chain = false;
|
|
|
|
@ -1617,9 +1634,12 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
|
|
|
|
|
// and we don't feel like constructing the object for them, so
|
|
|
|
|
// instead we respond with the full, non-compact block.
|
|
|
|
|
bool fPeerWantsWitness = State(pfrom.GetId())->fWantsCmpctWitness;
|
|
|
|
|
bool fPeerWantsMWEB = State(pfrom.GetId())->fWantsCmpctMWEB;
|
|
|
|
|
int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
|
|
|
|
|
nSendFlags |= fPeerWantsMWEB ? 0 : SERIALIZE_NO_MWEB;
|
|
|
|
|
|
|
|
|
|
if (CanDirectFetch(consensusParams) && pindex->nHeight >= ::ChainActive().Height() - MAX_CMPCTBLOCK_DEPTH) {
|
|
|
|
|
if ((fPeerWantsWitness || !fWitnessesPresentInARecentCompactBlock) && a_recent_compact_block && a_recent_compact_block->header.GetHash() == pindex->GetBlockHash()) {
|
|
|
|
|
if ((fPeerWantsWitness || !fWitnessesPresentInARecentCompactBlock) && (fPeerWantsMWEB || !fMWEBPresentInARecentCompactBlock) && a_recent_compact_block && a_recent_compact_block->header.GetHash() == pindex->GetBlockHash()) {
|
|
|
|
|
connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block));
|
|
|
|
|
} else {
|
|
|
|
|
CBlockHeaderAndShortTxIDs cmpctblock(*pblock, fPeerWantsWitness);
|
|
|
|
@ -1787,6 +1807,8 @@ void PeerManager::SendBlockTransactions(CNode& pfrom, const CBlock& block, const
|
|
|
|
|
LOCK(cs_main);
|
|
|
|
|
const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
|
|
|
|
|
int nSendFlags = State(pfrom.GetId())->fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
|
|
|
|
|
nSendFlags |= State(pfrom.GetId())->fWantsCmpctMWEB ? 0 : SERIALIZE_NO_MWEB;
|
|
|
|
|
|
|
|
|
|
m_connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2532,7 +2554,10 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
|
|
|
|
|
// We send this to non-NODE NETWORK peers as well, because
|
|
|
|
|
// they may wish to request compact blocks from us
|
|
|
|
|
bool fAnnounceUsingCMPCTBLOCK = false;
|
|
|
|
|
uint64_t nCMPCTBLOCKVersion = 2;
|
|
|
|
|
uint64_t nCMPCTBLOCKVersion = 3;
|
|
|
|
|
if (pfrom.GetLocalServices() & NODE_MWEB)
|
|
|
|
|
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
|
|
|
|
|
nCMPCTBLOCKVersion = 2;
|
|
|
|
|
if (pfrom.GetLocalServices() & NODE_WITNESS)
|
|
|
|
|
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
|
|
|
|
|
nCMPCTBLOCKVersion = 1;
|
|
|
|
@ -2649,17 +2674,20 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
|
|
|
|
|
bool fAnnounceUsingCMPCTBLOCK = false;
|
|
|
|
|
uint64_t nCMPCTBLOCKVersion = 0;
|
|
|
|
|
vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion;
|
|
|
|
|
if (nCMPCTBLOCKVersion == 1 || ((pfrom.GetLocalServices() & NODE_WITNESS) && nCMPCTBLOCKVersion == 2)) {
|
|
|
|
|
if (nCMPCTBLOCKVersion == 1 || ((pfrom.GetLocalServices() & NODE_WITNESS) && nCMPCTBLOCKVersion == 2) || ((pfrom.GetLocalServices() & NODE_MWEB) && nCMPCTBLOCKVersion == 3)) {
|
|
|
|
|
LOCK(cs_main);
|
|
|
|
|
// fProvidesHeaderAndIDs is used to "lock in" version of compact blocks we send (fWantsCmpctWitness)
|
|
|
|
|
if (!State(pfrom.GetId())->fProvidesHeaderAndIDs) {
|
|
|
|
|
State(pfrom.GetId())->fProvidesHeaderAndIDs = true;
|
|
|
|
|
State(pfrom.GetId())->fWantsCmpctWitness = nCMPCTBLOCKVersion == 2;
|
|
|
|
|
State(pfrom.GetId())->fWantsCmpctWitness = nCMPCTBLOCKVersion >= 2;
|
|
|
|
|
State(pfrom.GetId())->fWantsCmpctMWEB = nCMPCTBLOCKVersion >= 3;
|
|
|
|
|
}
|
|
|
|
|
if (State(pfrom.GetId())->fWantsCmpctWitness == (nCMPCTBLOCKVersion == 2)) // ignore later version announces
|
|
|
|
|
if (State(pfrom.GetId())->fWantsCmpctWitness == (nCMPCTBLOCKVersion >= 2) && State(pfrom.GetId())->fWantsCmpctMWEB == (nCMPCTBLOCKVersion >= 3))
|
|
|
|
|
State(pfrom.GetId())->fPreferHeaderAndIDs = fAnnounceUsingCMPCTBLOCK;
|
|
|
|
|
if (!State(pfrom.GetId())->fSupportsDesiredCmpctVersion) {
|
|
|
|
|
if (pfrom.GetLocalServices() & NODE_WITNESS)
|
|
|
|
|
if (pfrom.GetLocalServices() & NODE_MWEB)
|
|
|
|
|
State(pfrom.GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 3);
|
|
|
|
|
else if (pfrom.GetLocalServices() & NODE_WITNESS)
|
|
|
|
|
State(pfrom.GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 2);
|
|
|
|
|
else
|
|
|
|
|
State(pfrom.GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 1);
|
|
|
|
@ -2879,6 +2907,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
|
|
|
|
|
LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block > %i deep\n", pfrom.GetId(), MAX_BLOCKTXN_DEPTH);
|
|
|
|
|
CInv inv;
|
|
|
|
|
WITH_LOCK(cs_main, inv.type = State(pfrom.GetId())->fWantsCmpctWitness ? MSG_WITNESS_BLOCK : MSG_BLOCK);
|
|
|
|
|
WITH_LOCK(cs_main, inv.type = State(pfrom.GetId())->fWantsCmpctMWEB ? MSG_MWEB_BLOCK : inv.type);
|
|
|
|
|
inv.hash = req.blockhash;
|
|
|
|
|
WITH_LOCK(peer->m_getdata_requests_mutex, peer->m_getdata_requests.push_back(inv));
|
|
|
|
|
// The message processing loop will go around again (without pausing) and we'll respond then
|
|
|
|
@ -3175,6 +3204,15 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
|
|
|
|
|
LogPrint(BCLog::NET, "Unexpected cmpctblock message received from peer %d\n", pfrom.GetId());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
LOCK(cs_main);
|
|
|
|
|
CBlockIndex* pTip = ::ChainActive().Tip();
|
|
|
|
|
assert(pTip);
|
|
|
|
|
if (!IsMWEBEnabled(pTip->pprev, m_chainparams.GetConsensus()) && !State(pfrom.GetId())->fWantsCmpctMWEB) {
|
|
|
|
|
vRecv.SetVersion(vRecv.GetVersion() | SERIALIZE_NO_MWEB);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CBlockHeaderAndShortTxIDs cmpctblock;
|
|
|
|
|
vRecv >> cmpctblock;
|
|
|
|
@ -3263,6 +3301,12 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsMWEBEnabled(pindex->pprev, m_chainparams.GetConsensus()) && !nodestate->fWantsCmpctMWEB) {
|
|
|
|
|
// Don't bother trying to process compact blocks from v1/v2 peers
|
|
|
|
|
// after MWEB activates.
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We want to be a bit conservative just to be extra careful about DoS
|
|
|
|
|
// possibilities in compact block processing...
|
|
|
|
|
if (pindex->nHeight <= ::ChainActive().Height() + 2) {
|
|
|
|
@ -3271,7 +3315,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
|
|
|
|
|
std::list<QueuedBlock>::iterator* queuedBlockIt = nullptr;
|
|
|
|
|
if (!MarkBlockAsInFlight(m_mempool, pfrom.GetId(), pindex->GetBlockHash(), pindex, &queuedBlockIt)) {
|
|
|
|
|
if (!(*queuedBlockIt)->partialBlock)
|
|
|
|
|
(*queuedBlockIt)->partialBlock.reset(new PartiallyDownloadedBlock(&m_mempool));
|
|
|
|
|
(*queuedBlockIt)->partialBlock.reset(new PartiallyDownloadedBlock(&m_mempool, cmpctblock.mweb_block));
|
|
|
|
|
else {
|
|
|
|
|
// The block was already in flight using compact blocks from the same peer
|
|
|
|
|
LogPrint(BCLog::NET, "Peer sent us compact block we were already syncing!\n");
|
|
|
|
@ -3314,7 +3358,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
|
|
|
|
|
// download from.
|
|
|
|
|
// Optimistically try to reconstruct anyway since we might be
|
|
|
|
|
// able to without any round trips.
|
|
|
|
|
PartiallyDownloadedBlock tempBlock(&m_mempool);
|
|
|
|
|
PartiallyDownloadedBlock tempBlock(&m_mempool, cmpctblock.mweb_block);
|
|
|
|
|
ReadStatus status = tempBlock.InitData(cmpctblock, vExtraTxnForCompact);
|
|
|
|
|
if (status != READ_STATUS_OK) {
|
|
|
|
|
// TODO: don't ignore failures
|
|
|
|
@ -4250,6 +4294,7 @@ bool PeerManager::SendMessages(CNode* pto)
|
|
|
|
|
vHeaders.front().GetHash().ToString(), pto->GetId());
|
|
|
|
|
|
|
|
|
|
int nSendFlags = state.fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
|
|
|
|
|
nSendFlags |= state.fWantsCmpctMWEB ? 0 : SERIALIZE_NO_MWEB;
|
|
|
|
|
|
|
|
|
|
bool fGotBlockFromCache = false;
|
|
|
|
|
{
|
|
|
|
|