aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2016-06-25 19:17:45 +0200
committerPieter Wuille <pieter.wuille@gmail.com>2016-10-04 19:10:41 +0200
commit6aa28abf53ef4694692474b4a3b0a8fa7559b50b (patch)
treedca0f5961ecf9a1ddc75e642b5e862183f434fb9 /src/main.cpp
parentbe7555f0c03057bb5537cc42ca9d4937389f0670 (diff)
Use cmpctblock type 2 for segwit-enabled transfer
Contains version negotiation logic by Matt Corallo and bugfixes by Suhas Daftuar.
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp78
1 files changed, 56 insertions, 22 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 40c31b6ca6..c92a38be98 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -289,10 +289,21 @@ struct CNodeState {
bool fPreferHeaders;
//! Whether this peer wants invs or cmpctblocks (when possible) for block announcements.
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;
//! Whether this peer can give us witnesses
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() {
fCurrentlyConnected = false;
@@ -313,6 +324,8 @@ struct CNodeState {
fPreferHeaderAndIDs = false;
fProvidesHeaderAndIDs = false;
fHaveWitness = false;
+ fWantsCmpctWitness = false;
+ fSupportsDesiredCmpctVersion = false;
}
};
@@ -467,8 +480,8 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) {
}
void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pfrom, CConnman& connman) {
- if (pfrom->GetLocalServices() & NODE_WITNESS) {
- // Don't ever request compact blocks when segwit is enabled.
+ if (!nodestate->fSupportsDesiredCmpctVersion) {
+ // Never ask from peers who can't provide witnesses.
return;
}
if (nodestate->fProvidesHeaderAndIDs) {
@@ -476,7 +489,7 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pf
if (nodeid == pfrom->GetId())
return;
bool fAnnounceUsingCMPCTBLOCK = false;
- uint64_t nCMPCTBLOCKVersion = 1;
+ uint64_t nCMPCTBLOCKVersion = (pfrom->GetLocalServices() & NODE_WITNESS) ? 2 : 1;
if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
// As per BIP152, we only get 3 of our peers to announce
// blocks using compact encodings.
@@ -4856,11 +4869,12 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// they wont have a useful mempool to match against a compact block,
// 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;
if (mi->second->nHeight >= chainActive.Height() - 10) {
- CBlockHeaderAndShortTxIDs cmpctblock(block);
- pfrom->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock);
+ CBlockHeaderAndShortTxIDs cmpctblock(block, fPeerWantsWitness);
+ pfrom->PushMessageWithFlag(fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock);
} 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
@@ -5128,13 +5142,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->PushMessage(NetMsgType::SENDHEADERS);
}
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
// cmpctblock messages.
// 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 = 1;
+ uint64_t nCMPCTBLOCKVersion = 2;
+ if (pfrom->GetLocalServices() & NODE_WITNESS)
+ pfrom->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
+ nCMPCTBLOCKVersion = 1;
pfrom->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
}
}
@@ -5195,12 +5212,23 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
else if (strCommand == NetMsgType::SENDCMPCT)
{
bool fAnnounceUsingCMPCTBLOCK = false;
- uint64_t nCMPCTBLOCKVersion = 1;
+ uint64_t nCMPCTBLOCKVersion = 0;
vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion;
- if (nCMPCTBLOCKVersion == 1) {
+ if (nCMPCTBLOCKVersion == 1 || ((pfrom->GetLocalServices() & NODE_WITNESS) && nCMPCTBLOCKVersion == 2)) {
LOCK(cs_main);
- State(pfrom->GetId())->fProvidesHeaderAndIDs = true;
- State(pfrom->GetId())->fPreferHeaderAndIDs = fAnnounceUsingCMPCTBLOCK;
+ // 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;
+ }
+ if (State(pfrom->GetId())->fWantsCmpctWitness == (nCMPCTBLOCKVersion == 2)) // ignore later version announces
+ 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);
+ }
}
}
@@ -5258,7 +5286,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER &&
(!IsWitnessEnabled(chainActive.Tip(), chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) {
inv.type |= nFetchFlags;
- if (nodestate->fProvidesHeaderAndIDs && !(pfrom->GetLocalServices() & NODE_WITNESS))
+ if (nodestate->fSupportsDesiredCmpctVersion)
vToFetch.push_back(CInv(MSG_CMPCT_BLOCK, inv.hash));
else
vToFetch.push_back(inv);
@@ -5386,7 +5414,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
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);
}
@@ -5650,7 +5678,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// We requested this block for some reason, but our mempool will probably be useless
// so we just grab the block via normal getdata
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);
}
return true;
@@ -5662,6 +5690,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
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
// possibilities in compact block processing...
if (pindex->nHeight <= chainActive.Height() + 2) {
@@ -5688,7 +5722,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
} else if (status == READ_STATUS_FAILED) {
// Duplicate txindexes, the block is now in-flight, so just request it
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);
return true;
}
@@ -5715,7 +5749,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// We requested this block, but its far into the future, so our
// mempool will probably be useless - request the block normally
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);
return true;
} else {
@@ -5757,7 +5791,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
} else if (status == READ_STATUS_FAILED) {
// Might have collided, fall back to getdata now :(
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);
} else {
CValidationState state;
@@ -5906,7 +5940,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pindexLast->GetBlockHash().ToString(), pindexLast->nHeight);
}
if (vGetData.size() > 0) {
- if (nodestate->fProvidesHeaderAndIDs && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN) && !(pfrom->GetLocalServices() & 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
// with this block! Let's get them to announce using compact blocks in the future.
MaybeSetPeerAsAnnouncingHeaderAndIDs(nodestate, pfrom, connman);
@@ -6536,8 +6570,8 @@ bool SendMessages(CNode* pto, CConnman& connman)
//TODO: Shouldn't need to reload block from disk, but requires refactor
CBlock block;
assert(ReadBlockFromDisk(block, pBestIndex, consensusParams));
- CBlockHeaderAndShortTxIDs cmpctblock(block);
- pto->PushMessageWithFlag(SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock);
+ CBlockHeaderAndShortTxIDs cmpctblock(block, state.fWantsCmpctWitness);
+ pto->PushMessageWithFlag(state.fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock);
state.pindexBestHeaderSent = pBestIndex;
} else if (state.fPreferHeaders) {
if (vHeaders.size() > 1) {