aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMatt Corallo <git@bluematt.me>2016-12-04 20:44:37 -0800
committerMatt Corallo <git@bluematt.me>2017-01-10 14:48:42 -0500
commit93380c5247526e2248248a7d539233ec48d11bdd (patch)
tree6e174a66769400485cebf2b2b8dcee1dd1202e3f /src
parent1531652e02d856c1b8c3ba6f6e51e1983ac0540c (diff)
Use replaced transactions in compact block reconstruction
Diffstat (limited to 'src')
-rw-r--r--src/blockencodings.cpp32
-rw-r--r--src/blockencodings.h3
-rw-r--r--src/net_processing.cpp4
-rw-r--r--src/test/blockencodings_tests.cpp10
4 files changed, 41 insertions, 8 deletions
diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp
index 72fe17bdc7..43b4cb9b86 100644
--- a/src/blockencodings.cpp
+++ b/src/blockencodings.cpp
@@ -47,7 +47,7 @@ uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const uint256& txhash) const {
-ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& cmpctblock) {
+ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, std::vector<std::pair<uint256, CTransactionRef>>& extra_txn) {
if (cmpctblock.header.IsNull() || (cmpctblock.shorttxids.empty() && cmpctblock.prefilledtxn.empty()))
return READ_STATUS_INVALID;
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
return READ_STATUS_FAILED; // Short ID collision
std::vector<bool> have_txn(txn_available.size());
+ {
LOCK(pool->cs);
const std::vector<std::pair<uint256, CTxMemPool::txiter> >& vTxHashes = pool->vTxHashes;
for (size_t i = 0; i < vTxHashes.size(); i++) {
@@ -130,6 +131,35 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
if (mempool_count == shorttxids.size())
break;
}
+ }
+
+ for (size_t i = 0; i < extra_txn.size(); i++) {
+ uint64_t shortid = cmpctblock.GetShortID(extra_txn[i].first);
+ std::unordered_map<uint64_t, uint16_t>::iterator idit = shorttxids.find(shortid);
+ if (idit != shorttxids.end()) {
+ if (!have_txn[idit->second]) {
+ txn_available[idit->second] = extra_txn[i].second;
+ have_txn[idit->second] = true;
+ mempool_count++;
+ } else {
+ // If we find two mempool txn that match the short id, just request it.
+ // This should be rare enough that the extra bandwidth doesn't matter,
+ // but eating a round-trip due to FillBlock failure would be annoying
+ // Note that we dont want duplication between extra_txn and mempool to
+ // trigger this case, so we compare witness hashes first
+ if (txn_available[idit->second] &&
+ txn_available[idit->second]->GetWitnessHash() != extra_txn[i].second->GetWitnessHash()) {
+ txn_available[idit->second].reset();
+ mempool_count--;
+ }
+ }
+ }
+ // Though ideally we'd continue scanning for the two-txn-match-shortid case,
+ // the performance win of an early exit here is too good to pass up and worth
+ // the extra risk.
+ if (mempool_count == shorttxids.size())
+ break;
+ }
LogPrint("cmpctblock", "Initialized PartiallyDownloadedBlock for block %s using a cmpctblock of size %lu\n", cmpctblock.header.GetHash().ToString(), GetSerializeSize(cmpctblock, SER_NETWORK, PROTOCOL_VERSION));
diff --git a/src/blockencodings.h b/src/blockencodings.h
index 809ccbf936..7bbd9c6610 100644
--- a/src/blockencodings.h
+++ b/src/blockencodings.h
@@ -200,7 +200,8 @@ public:
CBlockHeader header;
PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
- ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock);
+ // extra_txn is a list of extra transactions to look at, in <witness hash, reference> form
+ ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, std::vector<std::pair<uint256, CTransactionRef>>& extra_txn);
bool IsTxAvailable(size_t index) const;
ReadStatus FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing);
};
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index c549b9eb9e..8e23e54e06 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -1879,7 +1879,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
PartiallyDownloadedBlock& partialBlock = *(*queuedBlockIt)->partialBlock;
- ReadStatus status = partialBlock.InitData(cmpctblock);
+ ReadStatus status = partialBlock.InitData(cmpctblock, vExtraTxnForCompact);
if (status == READ_STATUS_INVALID) {
MarkBlockAsReceived(pindex->GetBlockHash()); // Reset in-flight state in case of whitelist
Misbehaving(pfrom->GetId(), 100);
@@ -1921,7 +1921,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Optimistically try to reconstruct anyway since we might be
// able to without any round trips.
PartiallyDownloadedBlock tempBlock(&mempool);
- ReadStatus status = tempBlock.InitData(cmpctblock);
+ ReadStatus status = tempBlock.InitData(cmpctblock, vExtraTxnForCompact);
if (status != READ_STATUS_OK) {
// TODO: don't ignore failures
return true;
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index e3876e9695..311ac024f3 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.cpp
@@ -11,6 +11,8 @@
#include <boost/test/unit_test.hpp>
+std::vector<std::pair<uint256, CTransactionRef>> extra_txn;
+
struct RegtestingSetup : public TestingSetup {
RegtestingSetup() : TestingSetup(CBaseChainParams::REGTEST) {}
};
@@ -73,7 +75,7 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
stream >> shortIDs2;
PartiallyDownloadedBlock partialBlock(&pool);
- BOOST_CHECK(partialBlock.InitData(shortIDs2) == READ_STATUS_OK);
+ BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);
BOOST_CHECK( partialBlock.IsTxAvailable(0));
BOOST_CHECK(!partialBlock.IsTxAvailable(1));
BOOST_CHECK( partialBlock.IsTxAvailable(2));
@@ -179,7 +181,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
stream >> shortIDs2;
PartiallyDownloadedBlock partialBlock(&pool);
- BOOST_CHECK(partialBlock.InitData(shortIDs2) == READ_STATUS_OK);
+ BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);
BOOST_CHECK(!partialBlock.IsTxAvailable(0));
BOOST_CHECK( partialBlock.IsTxAvailable(1));
BOOST_CHECK( partialBlock.IsTxAvailable(2));
@@ -245,7 +247,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
stream >> shortIDs2;
PartiallyDownloadedBlock partialBlock(&pool);
- BOOST_CHECK(partialBlock.InitData(shortIDs2) == READ_STATUS_OK);
+ BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);
BOOST_CHECK( partialBlock.IsTxAvailable(0));
BOOST_CHECK( partialBlock.IsTxAvailable(1));
BOOST_CHECK( partialBlock.IsTxAvailable(2));
@@ -300,7 +302,7 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
stream >> shortIDs2;
PartiallyDownloadedBlock partialBlock(&pool);
- BOOST_CHECK(partialBlock.InitData(shortIDs2) == READ_STATUS_OK);
+ BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK);
BOOST_CHECK(partialBlock.IsTxAvailable(0));
CBlock block2;