mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-03 09:56:38 -05:00
Use replaced transactions in compact block reconstruction
This commit is contained in:
parent
1531652e02
commit
93380c5247
4 changed files with 41 additions and 8 deletions
|
@ -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()))
|
if (cmpctblock.header.IsNull() || (cmpctblock.shorttxids.empty() && cmpctblock.prefilledtxn.empty()))
|
||||||
return READ_STATUS_INVALID;
|
return READ_STATUS_INVALID;
|
||||||
if (cmpctblock.shorttxids.size() + cmpctblock.prefilledtxn.size() > MAX_BLOCK_BASE_SIZE / MIN_TRANSACTION_BASE_SIZE)
|
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
|
return READ_STATUS_FAILED; // Short ID collision
|
||||||
|
|
||||||
std::vector<bool> have_txn(txn_available.size());
|
std::vector<bool> have_txn(txn_available.size());
|
||||||
|
{
|
||||||
LOCK(pool->cs);
|
LOCK(pool->cs);
|
||||||
const std::vector<std::pair<uint256, CTxMemPool::txiter> >& vTxHashes = pool->vTxHashes;
|
const std::vector<std::pair<uint256, CTxMemPool::txiter> >& vTxHashes = pool->vTxHashes;
|
||||||
for (size_t i = 0; i < vTxHashes.size(); i++) {
|
for (size_t i = 0; i < vTxHashes.size(); i++) {
|
||||||
|
@ -130,6 +131,35 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
|
||||||
if (mempool_count == shorttxids.size())
|
if (mempool_count == shorttxids.size())
|
||||||
break;
|
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));
|
LogPrint("cmpctblock", "Initialized PartiallyDownloadedBlock for block %s using a cmpctblock of size %lu\n", cmpctblock.header.GetHash().ToString(), GetSerializeSize(cmpctblock, SER_NETWORK, PROTOCOL_VERSION));
|
||||||
|
|
||||||
|
|
|
@ -200,7 +200,8 @@ public:
|
||||||
CBlockHeader header;
|
CBlockHeader header;
|
||||||
PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
|
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;
|
bool IsTxAvailable(size_t index) const;
|
||||||
ReadStatus FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing);
|
ReadStatus FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1879,7 +1879,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||||
}
|
}
|
||||||
|
|
||||||
PartiallyDownloadedBlock& partialBlock = *(*queuedBlockIt)->partialBlock;
|
PartiallyDownloadedBlock& partialBlock = *(*queuedBlockIt)->partialBlock;
|
||||||
ReadStatus status = partialBlock.InitData(cmpctblock);
|
ReadStatus status = partialBlock.InitData(cmpctblock, vExtraTxnForCompact);
|
||||||
if (status == READ_STATUS_INVALID) {
|
if (status == READ_STATUS_INVALID) {
|
||||||
MarkBlockAsReceived(pindex->GetBlockHash()); // Reset in-flight state in case of whitelist
|
MarkBlockAsReceived(pindex->GetBlockHash()); // Reset in-flight state in case of whitelist
|
||||||
Misbehaving(pfrom->GetId(), 100);
|
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
|
// Optimistically try to reconstruct anyway since we might be
|
||||||
// able to without any round trips.
|
// able to without any round trips.
|
||||||
PartiallyDownloadedBlock tempBlock(&mempool);
|
PartiallyDownloadedBlock tempBlock(&mempool);
|
||||||
ReadStatus status = tempBlock.InitData(cmpctblock);
|
ReadStatus status = tempBlock.InitData(cmpctblock, vExtraTxnForCompact);
|
||||||
if (status != READ_STATUS_OK) {
|
if (status != READ_STATUS_OK) {
|
||||||
// TODO: don't ignore failures
|
// TODO: don't ignore failures
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
std::vector<std::pair<uint256, CTransactionRef>> extra_txn;
|
||||||
|
|
||||||
struct RegtestingSetup : public TestingSetup {
|
struct RegtestingSetup : public TestingSetup {
|
||||||
RegtestingSetup() : TestingSetup(CBaseChainParams::REGTEST) {}
|
RegtestingSetup() : TestingSetup(CBaseChainParams::REGTEST) {}
|
||||||
};
|
};
|
||||||
|
@ -73,7 +75,7 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
|
||||||
stream >> shortIDs2;
|
stream >> shortIDs2;
|
||||||
|
|
||||||
PartiallyDownloadedBlock partialBlock(&pool);
|
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(0));
|
||||||
BOOST_CHECK(!partialBlock.IsTxAvailable(1));
|
BOOST_CHECK(!partialBlock.IsTxAvailable(1));
|
||||||
BOOST_CHECK( partialBlock.IsTxAvailable(2));
|
BOOST_CHECK( partialBlock.IsTxAvailable(2));
|
||||||
|
@ -179,7 +181,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
|
||||||
stream >> shortIDs2;
|
stream >> shortIDs2;
|
||||||
|
|
||||||
PartiallyDownloadedBlock partialBlock(&pool);
|
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(0));
|
||||||
BOOST_CHECK( partialBlock.IsTxAvailable(1));
|
BOOST_CHECK( partialBlock.IsTxAvailable(1));
|
||||||
BOOST_CHECK( partialBlock.IsTxAvailable(2));
|
BOOST_CHECK( partialBlock.IsTxAvailable(2));
|
||||||
|
@ -245,7 +247,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
|
||||||
stream >> shortIDs2;
|
stream >> shortIDs2;
|
||||||
|
|
||||||
PartiallyDownloadedBlock partialBlock(&pool);
|
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(0));
|
||||||
BOOST_CHECK( partialBlock.IsTxAvailable(1));
|
BOOST_CHECK( partialBlock.IsTxAvailable(1));
|
||||||
BOOST_CHECK( partialBlock.IsTxAvailable(2));
|
BOOST_CHECK( partialBlock.IsTxAvailable(2));
|
||||||
|
@ -300,7 +302,7 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
|
||||||
stream >> shortIDs2;
|
stream >> shortIDs2;
|
||||||
|
|
||||||
PartiallyDownloadedBlock partialBlock(&pool);
|
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(0));
|
||||||
|
|
||||||
CBlock block2;
|
CBlock block2;
|
||||||
|
|
Loading…
Add table
Reference in a new issue