Skip to content

Commit 93380c5

Browse files
committed
Use replaced transactions in compact block reconstruction
1 parent 1531652 commit 93380c5

File tree

4 files changed

+41
-8
lines changed

4 files changed

+41
-8
lines changed

src/blockencodings.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const uint256& txhash) const {
4747

4848

4949

50-
ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& cmpctblock) {
50+
ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, std::vector<std::pair<uint256, CTransactionRef>>& extra_txn) {
5151
if (cmpctblock.header.IsNull() || (cmpctblock.shorttxids.empty() && cmpctblock.prefilledtxn.empty()))
5252
return READ_STATUS_INVALID;
5353
if (cmpctblock.shorttxids.size() + cmpctblock.prefilledtxn.size() > MAX_BLOCK_BASE_SIZE / MIN_TRANSACTION_BASE_SIZE)
@@ -104,6 +104,7 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
104104
return READ_STATUS_FAILED; // Short ID collision
105105

106106
std::vector<bool> have_txn(txn_available.size());
107+
{
107108
LOCK(pool->cs);
108109
const std::vector<std::pair<uint256, CTxMemPool::txiter> >& vTxHashes = pool->vTxHashes;
109110
for (size_t i = 0; i < vTxHashes.size(); i++) {
@@ -130,6 +131,35 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
130131
if (mempool_count == shorttxids.size())
131132
break;
132133
}
134+
}
135+
136+
for (size_t i = 0; i < extra_txn.size(); i++) {
137+
uint64_t shortid = cmpctblock.GetShortID(extra_txn[i].first);
138+
std::unordered_map<uint64_t, uint16_t>::iterator idit = shorttxids.find(shortid);
139+
if (idit != shorttxids.end()) {
140+
if (!have_txn[idit->second]) {
141+
txn_available[idit->second] = extra_txn[i].second;
142+
have_txn[idit->second] = true;
143+
mempool_count++;
144+
} else {
145+
// If we find two mempool txn that match the short id, just request it.
146+
// This should be rare enough that the extra bandwidth doesn't matter,
147+
// but eating a round-trip due to FillBlock failure would be annoying
148+
// Note that we dont want duplication between extra_txn and mempool to
149+
// trigger this case, so we compare witness hashes first
150+
if (txn_available[idit->second] &&
151+
txn_available[idit->second]->GetWitnessHash() != extra_txn[i].second->GetWitnessHash()) {
152+
txn_available[idit->second].reset();
153+
mempool_count--;
154+
}
155+
}
156+
}
157+
// Though ideally we'd continue scanning for the two-txn-match-shortid case,
158+
// the performance win of an early exit here is too good to pass up and worth
159+
// the extra risk.
160+
if (mempool_count == shorttxids.size())
161+
break;
162+
}
133163

134164
LogPrint("cmpctblock", "Initialized PartiallyDownloadedBlock for block %s using a cmpctblock of size %lu\n", cmpctblock.header.GetHash().ToString(), GetSerializeSize(cmpctblock, SER_NETWORK, PROTOCOL_VERSION));
135165

src/blockencodings.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,8 @@ class PartiallyDownloadedBlock {
200200
CBlockHeader header;
201201
PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
202202

203-
ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock);
203+
// extra_txn is a list of extra transactions to look at, in <witness hash, reference> form
204+
ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, std::vector<std::pair<uint256, CTransactionRef>>& extra_txn);
204205
bool IsTxAvailable(size_t index) const;
205206
ReadStatus FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing);
206207
};

src/net_processing.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1879,7 +1879,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
18791879
}
18801880

18811881
PartiallyDownloadedBlock& partialBlock = *(*queuedBlockIt)->partialBlock;
1882-
ReadStatus status = partialBlock.InitData(cmpctblock);
1882+
ReadStatus status = partialBlock.InitData(cmpctblock, vExtraTxnForCompact);
18831883
if (status == READ_STATUS_INVALID) {
18841884
MarkBlockAsReceived(pindex->GetBlockHash()); // Reset in-flight state in case of whitelist
18851885
Misbehaving(pfrom->GetId(), 100);
@@ -1921,7 +1921,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
19211921
// Optimistically try to reconstruct anyway since we might be
19221922
// able to without any round trips.
19231923
PartiallyDownloadedBlock tempBlock(&mempool);
1924-
ReadStatus status = tempBlock.InitData(cmpctblock);
1924+
ReadStatus status = tempBlock.InitData(cmpctblock, vExtraTxnForCompact);
19251925
if (status != READ_STATUS_OK) {
19261926
// TODO: don't ignore failures
19271927
return true;

src/test/blockencodings_tests.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
#include <boost/test/unit_test.hpp>
1313

14+
std::vector<std::pair<uint256, CTransactionRef>> extra_txn;
15+
1416
struct RegtestingSetup : public TestingSetup {
1517
RegtestingSetup() : TestingSetup(CBaseChainParams::REGTEST) {}
1618
};
@@ -73,7 +75,7 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
7375
stream >> shortIDs2;
7476

7577
PartiallyDownloadedBlock partialBlock(&pool);
76-
BOOST_CHECK(partialBlock.InitData(shortIDs2) == READ_STATUS_OK);
78+
BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);
7779
BOOST_CHECK( partialBlock.IsTxAvailable(0));
7880
BOOST_CHECK(!partialBlock.IsTxAvailable(1));
7981
BOOST_CHECK( partialBlock.IsTxAvailable(2));
@@ -179,7 +181,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
179181
stream >> shortIDs2;
180182

181183
PartiallyDownloadedBlock partialBlock(&pool);
182-
BOOST_CHECK(partialBlock.InitData(shortIDs2) == READ_STATUS_OK);
184+
BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);
183185
BOOST_CHECK(!partialBlock.IsTxAvailable(0));
184186
BOOST_CHECK( partialBlock.IsTxAvailable(1));
185187
BOOST_CHECK( partialBlock.IsTxAvailable(2));
@@ -245,7 +247,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
245247
stream >> shortIDs2;
246248

247249
PartiallyDownloadedBlock partialBlock(&pool);
248-
BOOST_CHECK(partialBlock.InitData(shortIDs2) == READ_STATUS_OK);
250+
BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);
249251
BOOST_CHECK( partialBlock.IsTxAvailable(0));
250252
BOOST_CHECK( partialBlock.IsTxAvailable(1));
251253
BOOST_CHECK( partialBlock.IsTxAvailable(2));
@@ -300,7 +302,7 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
300302
stream >> shortIDs2;
301303

302304
PartiallyDownloadedBlock partialBlock(&pool);
303-
BOOST_CHECK(partialBlock.InitData(shortIDs2) == READ_STATUS_OK);
305+
BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);
304306
BOOST_CHECK(partialBlock.IsTxAvailable(0));
305307

306308
CBlock block2;

0 commit comments

Comments
 (0)