|
|
@ -292,10 +292,21 @@ struct CNodeState { |
|
|
|
bool fPreferHeaders; |
|
|
|
bool fPreferHeaders; |
|
|
|
//! Whether this peer wants invs or cmpctblocks (when possible) for block announcements.
|
|
|
|
//! Whether this peer wants invs or cmpctblocks (when possible) for block announcements.
|
|
|
|
bool fPreferHeaderAndIDs; |
|
|
|
bool fPreferHeaderAndIDs; |
|
|
|
//! Whether this peer will send us cmpctblocks if we request them
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Whether this peer will send us cmpctblocks if we request them. |
|
|
|
|
|
|
|
* This is not used to gate request logic, as we really only care about fSupportsDesiredCmpctVersion, |
|
|
|
|
|
|
|
* but is used as a flag to "lock in" the version of compact blocks (fWantsCmpctWitness) we send. |
|
|
|
|
|
|
|
*/ |
|
|
|
bool fProvidesHeaderAndIDs; |
|
|
|
bool fProvidesHeaderAndIDs; |
|
|
|
//! Whether this peer can give us witnesses
|
|
|
|
//! Whether this peer can give us witnesses
|
|
|
|
bool fHaveWitness; |
|
|
|
bool fHaveWitness; |
|
|
|
|
|
|
|
//! Whether this peer wants witnesses in cmpctblocks/blocktxns
|
|
|
|
|
|
|
|
bool fWantsCmpctWitness; |
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 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. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
bool fSupportsDesiredCmpctVersion; |
|
|
|
|
|
|
|
|
|
|
|
CNodeState() { |
|
|
|
CNodeState() { |
|
|
|
fCurrentlyConnected = false; |
|
|
|
fCurrentlyConnected = false; |
|
|
@ -316,6 +327,8 @@ struct CNodeState { |
|
|
|
fPreferHeaderAndIDs = false; |
|
|
|
fPreferHeaderAndIDs = false; |
|
|
|
fProvidesHeaderAndIDs = false; |
|
|
|
fProvidesHeaderAndIDs = false; |
|
|
|
fHaveWitness = false; |
|
|
|
fHaveWitness = false; |
|
|
|
|
|
|
|
fWantsCmpctWitness = false; |
|
|
|
|
|
|
|
fSupportsDesiredCmpctVersion = false; |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
@ -475,8 +488,8 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pfrom) { |
|
|
|
void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pfrom) { |
|
|
|
if (nLocalServices & NODE_WITNESS) { |
|
|
|
if (!nodestate->fSupportsDesiredCmpctVersion) { |
|
|
|
// Don't ever request compact blocks when segwit is enabled.
|
|
|
|
// Never ask from peers who can't provide witnesses.
|
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
if (nodestate->fProvidesHeaderAndIDs) { |
|
|
|
if (nodestate->fProvidesHeaderAndIDs) { |
|
|
@ -484,7 +497,7 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pf |
|
|
|
if (nodeid == pfrom->GetId()) |
|
|
|
if (nodeid == pfrom->GetId()) |
|
|
|
return; |
|
|
|
return; |
|
|
|
bool fAnnounceUsingCMPCTBLOCK = false; |
|
|
|
bool fAnnounceUsingCMPCTBLOCK = false; |
|
|
|
uint64_t nCMPCTBLOCKVersion = 1; |
|
|
|
uint64_t nCMPCTBLOCKVersion = (pfrom->GetLocalServices() & NODE_WITNESS) ? 2 : 1; |
|
|
|
if (lNodesAnnouncingHeaderAndIDs.size() >= 3) { |
|
|
|
if (lNodesAnnouncingHeaderAndIDs.size() >= 3) { |
|
|
|
// As per BIP152, we only get 3 of our peers to announce
|
|
|
|
// As per BIP152, we only get 3 of our peers to announce
|
|
|
|
// blocks using compact encodings.
|
|
|
|
// blocks using compact encodings.
|
|
|
@ -4832,11 +4845,12 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam |
|
|
|
// they wont have a useful mempool to match against a compact block,
|
|
|
|
// they wont have a useful mempool to match against a compact block,
|
|
|
|
// and we don't feel like constructing the object for them, so
|
|
|
|
// and we don't feel like constructing the object for them, so
|
|
|
|
// instead we respond with the full, non-compact block.
|
|
|
|
// instead we respond with the full, non-compact block.
|
|
|
|
|
|
|
|
bool fPeerWantsWitness = State(pfrom->GetId())->fWantsCmpctWitness; |
|
|
|
if (mi->second->nHeight >= chainActive.Height() - 10) { |
|
|
|
if (mi->second->nHeight >= chainActive.Height() - 10) { |
|
|
|
CBlockHeaderAndShortTxIDs cmpctblock(block); |
|
|
|
CBlockHeaderAndShortTxIDs cmpctblock(block, fPeerWantsWitness); |
|
|
|
pfrom->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock); |
|
|
|
pfrom->PushMessageWithFlag(fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock); |
|
|
|
} else |
|
|
|
} else |
|
|
|
pfrom->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block); |
|
|
|
pfrom->PushMessageWithFlag(fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
@ -5102,13 +5116,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
|
|
|
pfrom->PushMessage(NetMsgType::SENDHEADERS); |
|
|
|
pfrom->PushMessage(NetMsgType::SENDHEADERS); |
|
|
|
} |
|
|
|
} |
|
|
|
if (pfrom->nVersion >= SHORT_IDS_BLOCKS_VERSION) { |
|
|
|
if (pfrom->nVersion >= SHORT_IDS_BLOCKS_VERSION) { |
|
|
|
// Tell our peer we are willing to provide version-1 cmpctblocks
|
|
|
|
// Tell our peer we are willing to provide version 1 or 2 cmpctblocks
|
|
|
|
// However, we do not request new block announcements using
|
|
|
|
// However, we do not request new block announcements using
|
|
|
|
// cmpctblock messages.
|
|
|
|
// cmpctblock messages.
|
|
|
|
// We send this to non-NODE NETWORK peers as well, because
|
|
|
|
// We send this to non-NODE NETWORK peers as well, because
|
|
|
|
// they may wish to request compact blocks from us
|
|
|
|
// they may wish to request compact blocks from us
|
|
|
|
bool fAnnounceUsingCMPCTBLOCK = false; |
|
|
|
bool fAnnounceUsingCMPCTBLOCK = false; |
|
|
|
uint64_t nCMPCTBLOCKVersion = 1; |
|
|
|
uint64_t nCMPCTBLOCKVersion = 2; |
|
|
|
|
|
|
|
if (pfrom->GetLocalServices() & NODE_WITNESS) |
|
|
|
|
|
|
|
pfrom->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion); |
|
|
|
|
|
|
|
nCMPCTBLOCKVersion = 1; |
|
|
|
pfrom->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion); |
|
|
|
pfrom->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -5188,12 +5205,23 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
|
|
|
else if (strCommand == NetMsgType::SENDCMPCT) |
|
|
|
else if (strCommand == NetMsgType::SENDCMPCT) |
|
|
|
{ |
|
|
|
{ |
|
|
|
bool fAnnounceUsingCMPCTBLOCK = false; |
|
|
|
bool fAnnounceUsingCMPCTBLOCK = false; |
|
|
|
uint64_t nCMPCTBLOCKVersion = 1; |
|
|
|
uint64_t nCMPCTBLOCKVersion = 0; |
|
|
|
vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion; |
|
|
|
vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion; |
|
|
|
if (nCMPCTBLOCKVersion == 1) { |
|
|
|
if (nCMPCTBLOCKVersion == 1 || ((pfrom->GetLocalServices() & NODE_WITNESS) && nCMPCTBLOCKVersion == 2)) { |
|
|
|
LOCK(cs_main); |
|
|
|
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())->fProvidesHeaderAndIDs = true; |
|
|
|
|
|
|
|
State(pfrom->GetId())->fWantsCmpctWitness = nCMPCTBLOCKVersion == 2; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (State(pfrom->GetId())->fWantsCmpctWitness == (nCMPCTBLOCKVersion == 2)) // ignore later version announces
|
|
|
|
State(pfrom->GetId())->fPreferHeaderAndIDs = fAnnounceUsingCMPCTBLOCK; |
|
|
|
State(pfrom->GetId())->fPreferHeaderAndIDs = fAnnounceUsingCMPCTBLOCK; |
|
|
|
|
|
|
|
if (!State(pfrom->GetId())->fSupportsDesiredCmpctVersion) { |
|
|
|
|
|
|
|
if (pfrom->GetLocalServices() & NODE_WITNESS) |
|
|
|
|
|
|
|
State(pfrom->GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 2); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
State(pfrom->GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 1); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -5251,7 +5279,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
|
|
|
nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER && |
|
|
|
nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER && |
|
|
|
(!IsWitnessEnabled(chainActive.Tip(), chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) { |
|
|
|
(!IsWitnessEnabled(chainActive.Tip(), chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) { |
|
|
|
inv.type |= nFetchFlags; |
|
|
|
inv.type |= nFetchFlags; |
|
|
|
if (nodestate->fProvidesHeaderAndIDs && !(nLocalServices & NODE_WITNESS)) |
|
|
|
if (nodestate->fSupportsDesiredCmpctVersion) |
|
|
|
vToFetch.push_back(CInv(MSG_CMPCT_BLOCK, inv.hash)); |
|
|
|
vToFetch.push_back(CInv(MSG_CMPCT_BLOCK, inv.hash)); |
|
|
|
else |
|
|
|
else |
|
|
|
vToFetch.push_back(inv); |
|
|
|
vToFetch.push_back(inv); |
|
|
@ -5379,7 +5407,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
|
|
|
} |
|
|
|
} |
|
|
|
resp.txn[i] = block.vtx[req.indexes[i]]; |
|
|
|
resp.txn[i] = block.vtx[req.indexes[i]]; |
|
|
|
} |
|
|
|
} |
|
|
|
pfrom->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCKTXN, resp); |
|
|
|
pfrom->PushMessageWithFlag(State(pfrom->GetId())->fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCKTXN, resp); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -5643,7 +5671,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
|
|
|
// We requested this block for some reason, but our mempool will probably be useless
|
|
|
|
// We requested this block for some reason, but our mempool will probably be useless
|
|
|
|
// so we just grab the block via normal getdata
|
|
|
|
// so we just grab the block via normal getdata
|
|
|
|
std::vector<CInv> vInv(1); |
|
|
|
std::vector<CInv> vInv(1); |
|
|
|
vInv[0] = CInv(MSG_BLOCK, cmpctblock.header.GetHash()); |
|
|
|
vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom, pindex->pprev, chainparams.GetConsensus()), cmpctblock.header.GetHash()); |
|
|
|
pfrom->PushMessage(NetMsgType::GETDATA, vInv); |
|
|
|
pfrom->PushMessage(NetMsgType::GETDATA, vInv); |
|
|
|
} |
|
|
|
} |
|
|
|
return true; |
|
|
|
return true; |
|
|
@ -5655,6 +5683,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
|
|
|
|
|
|
|
|
|
|
|
CNodeState *nodestate = State(pfrom->GetId()); |
|
|
|
CNodeState *nodestate = State(pfrom->GetId()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (IsWitnessEnabled(pindex->pprev, chainparams.GetConsensus()) && !nodestate->fSupportsDesiredCmpctVersion) { |
|
|
|
|
|
|
|
// Don't bother trying to process compact blocks from v1 peers
|
|
|
|
|
|
|
|
// after segwit activates.
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// We want to be a bit conservative just to be extra careful about DoS
|
|
|
|
// We want to be a bit conservative just to be extra careful about DoS
|
|
|
|
// possibilities in compact block processing...
|
|
|
|
// possibilities in compact block processing...
|
|
|
|
if (pindex->nHeight <= chainActive.Height() + 2) { |
|
|
|
if (pindex->nHeight <= chainActive.Height() + 2) { |
|
|
@ -5681,7 +5715,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
|
|
|
} else if (status == READ_STATUS_FAILED) { |
|
|
|
} else if (status == READ_STATUS_FAILED) { |
|
|
|
// Duplicate txindexes, the block is now in-flight, so just request it
|
|
|
|
// Duplicate txindexes, the block is now in-flight, so just request it
|
|
|
|
std::vector<CInv> vInv(1); |
|
|
|
std::vector<CInv> vInv(1); |
|
|
|
vInv[0] = CInv(MSG_BLOCK, cmpctblock.header.GetHash()); |
|
|
|
vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom, pindex->pprev, chainparams.GetConsensus()), cmpctblock.header.GetHash()); |
|
|
|
pfrom->PushMessage(NetMsgType::GETDATA, vInv); |
|
|
|
pfrom->PushMessage(NetMsgType::GETDATA, vInv); |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
@ -5708,7 +5742,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
|
|
|
// We requested this block, but its far into the future, so our
|
|
|
|
// We requested this block, but its far into the future, so our
|
|
|
|
// mempool will probably be useless - request the block normally
|
|
|
|
// mempool will probably be useless - request the block normally
|
|
|
|
std::vector<CInv> vInv(1); |
|
|
|
std::vector<CInv> vInv(1); |
|
|
|
vInv[0] = CInv(MSG_BLOCK, cmpctblock.header.GetHash()); |
|
|
|
vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom, pindex->pprev, chainparams.GetConsensus()), cmpctblock.header.GetHash()); |
|
|
|
pfrom->PushMessage(NetMsgType::GETDATA, vInv); |
|
|
|
pfrom->PushMessage(NetMsgType::GETDATA, vInv); |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -5750,7 +5784,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
|
|
|
} else if (status == READ_STATUS_FAILED) { |
|
|
|
} else if (status == READ_STATUS_FAILED) { |
|
|
|
// Might have collided, fall back to getdata now :(
|
|
|
|
// Might have collided, fall back to getdata now :(
|
|
|
|
std::vector<CInv> invs; |
|
|
|
std::vector<CInv> invs; |
|
|
|
invs.push_back(CInv(MSG_BLOCK, resp.blockhash)); |
|
|
|
invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus()), resp.blockhash)); |
|
|
|
pfrom->PushMessage(NetMsgType::GETDATA, invs); |
|
|
|
pfrom->PushMessage(NetMsgType::GETDATA, invs); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
CValidationState state; |
|
|
|
CValidationState state; |
|
|
@ -5899,7 +5933,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
|
|
|
pindexLast->GetBlockHash().ToString(), pindexLast->nHeight); |
|
|
|
pindexLast->GetBlockHash().ToString(), pindexLast->nHeight); |
|
|
|
} |
|
|
|
} |
|
|
|
if (vGetData.size() > 0) { |
|
|
|
if (vGetData.size() > 0) { |
|
|
|
if (nodestate->fProvidesHeaderAndIDs && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN) && !(nLocalServices & NODE_WITNESS)) { |
|
|
|
if (nodestate->fSupportsDesiredCmpctVersion && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN)) { |
|
|
|
// We seem to be rather well-synced, so it appears pfrom was the first to provide us
|
|
|
|
// We seem to be rather well-synced, so it appears pfrom was the first to provide us
|
|
|
|
// with this block! Let's get them to announce using compact blocks in the future.
|
|
|
|
// with this block! Let's get them to announce using compact blocks in the future.
|
|
|
|
MaybeSetPeerAsAnnouncingHeaderAndIDs(nodestate, pfrom); |
|
|
|
MaybeSetPeerAsAnnouncingHeaderAndIDs(nodestate, pfrom); |
|
|
@ -6527,8 +6561,8 @@ bool SendMessages(CNode* pto) |
|
|
|
//TODO: Shouldn't need to reload block from disk, but requires refactor
|
|
|
|
//TODO: Shouldn't need to reload block from disk, but requires refactor
|
|
|
|
CBlock block; |
|
|
|
CBlock block; |
|
|
|
assert(ReadBlockFromDisk(block, pBestIndex, consensusParams)); |
|
|
|
assert(ReadBlockFromDisk(block, pBestIndex, consensusParams)); |
|
|
|
CBlockHeaderAndShortTxIDs cmpctblock(block); |
|
|
|
CBlockHeaderAndShortTxIDs cmpctblock(block, state.fWantsCmpctWitness); |
|
|
|
pto->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock); |
|
|
|
pto->PushMessageWithFlag(state.fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, 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) { |
|
|
|