mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 20:12:57 +01:00
Use cmpctblock type 2 for segwit-enabled transfer
Contains version negotiation logic by Matt Corallo and bugfixes by Suhas Daftuar.
This commit is contained in:
parent
be7555f0c0
commit
6aa28abf53
@ -17,7 +17,7 @@
|
||||
|
||||
#define MIN_TRANSACTION_BASE_SIZE (::GetSerializeSize(CTransaction(), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS))
|
||||
|
||||
CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block) :
|
||||
CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block, bool fUseWTXID) :
|
||||
nonce(GetRand(std::numeric_limits<uint64_t>::max())),
|
||||
shorttxids(block.vtx.size() - 1), prefilledtxn(1), header(block) {
|
||||
FillShortTxIDSelector();
|
||||
@ -25,7 +25,7 @@ CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block) :
|
||||
prefilledtxn[0] = {0, block.vtx[0]};
|
||||
for (size_t i = 1; i < block.vtx.size(); i++) {
|
||||
const CTransaction& tx = block.vtx[i];
|
||||
shorttxids[i - 1] = GetShortID(tx.GetHash());
|
||||
shorttxids[i - 1] = GetShortID(fUseWTXID ? tx.GetWitnessHash() : tx.GetHash());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ public:
|
||||
// Dummy for deserialization
|
||||
CBlockHeaderAndShortTxIDs() {}
|
||||
|
||||
CBlockHeaderAndShortTxIDs(const CBlock& block);
|
||||
CBlockHeaderAndShortTxIDs(const CBlock& block, bool fUseWTXID);
|
||||
|
||||
uint64_t GetShortID(const uint256& txhash) const;
|
||||
|
||||
|
78
src/main.cpp
78
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) {
|
||||
|
@ -64,7 +64,7 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
|
||||
|
||||
// Do a simple ShortTxIDs RT
|
||||
{
|
||||
CBlockHeaderAndShortTxIDs shortIDs(block);
|
||||
CBlockHeaderAndShortTxIDs shortIDs(block, true);
|
||||
|
||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
|
||||
stream << shortIDs;
|
||||
@ -116,7 +116,7 @@ public:
|
||||
stream >> *this;
|
||||
}
|
||||
TestHeaderAndShortIDs(const CBlock& block) :
|
||||
TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs(block)) {}
|
||||
TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs(block, true)) {}
|
||||
|
||||
uint64_t GetShortID(const uint256& txhash) const {
|
||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
|
||||
@ -267,7 +267,7 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
|
||||
|
||||
// Test simple header round-trip with only coinbase
|
||||
{
|
||||
CBlockHeaderAndShortTxIDs shortIDs(block);
|
||||
CBlockHeaderAndShortTxIDs shortIDs(block, false);
|
||||
|
||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
|
||||
stream << shortIDs;
|
||||
|
@ -444,7 +444,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
|
||||
totalTxSize += entry.GetTxSize();
|
||||
minerPolicyEstimator->processTransaction(entry, fCurrentEstimate);
|
||||
|
||||
vTxHashes.emplace_back(hash, newit);
|
||||
vTxHashes.emplace_back(tx.GetWitnessHash(), newit);
|
||||
newit->vTxHashesIdx = vTxHashes.size() - 1;
|
||||
|
||||
return true;
|
||||
|
@ -465,7 +465,7 @@ public:
|
||||
indexed_transaction_set mapTx;
|
||||
|
||||
typedef indexed_transaction_set::nth_index<0>::type::iterator txiter;
|
||||
std::vector<std::pair<uint256, txiter> > vTxHashes; //!< All tx hashes/entries in mapTx, in random order
|
||||
std::vector<std::pair<uint256, txiter> > vTxHashes; //!< All tx witness hashes/entries in mapTx, in random order
|
||||
|
||||
struct CompareIteratorByHash {
|
||||
bool operator()(const txiter &a, const txiter &b) const {
|
||||
|
Loading…
Reference in New Issue
Block a user