mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-02-01 19:21:10 +00:00
c58c249a5b694c88122589fedbef4e2f13f08bb4 net_processing: indicate more work to do when orphans are ready to reconsider (Anthony Towns) ecb0a3e4259b81d6bb74d59a58eb65552c17d8d8 net_processing: Don't process tx after processing orphans (Anthony Towns) c5837757068bf8ea3e5b6fdad82f69d1deb81545 net_processing: only process orphans before messages (Anthony Towns) be2304676bedcd15debcdc694549fdd2b255ba62 txorphange: Drop redundant originator arg from GetTxToReconsider (Anthony Towns) a4fe09973aa82210b98dcb4e4e9f11ef59780f9b txorphanage: index workset by originating peer (Anthony Towns) Pull request description: We currently process orphans by assigning them to the peer that provided a missing parent; instead assign them to the peer that provided the orphan in the first place. This prevents a peer from being able to marginally delay another peer's transactions and also simplifies the internal API slightly. Because we're now associating orphan processing with the peer that provided the orphan originally, we no longer process orphans immediately after receiving the parent, but defer until a future call to `ProcessMessage`. Based on #26295 ACKs for top commit: naumenkogs: utACK c58c249a5b694c88122589fedbef4e2f13f08bb4 glozow: ACK c58c249a5b694c88122589fedbef4e2f13f08bb4 mzumsande: Code Review ACK c58c249a5b694c88122589fedbef4e2f13f08bb4 Tree-SHA512: 3186c346f21e60440266a2a80a9d23d7b96071414e14b2b3bfe50457c04c18b1eab109c3d8c2a7726a6b10a2eda1f0512510a52c102da112820a26f5d96f12de
141 lines
5.8 KiB
C++
141 lines
5.8 KiB
C++
// Copyright (c) 2022 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include <consensus/amount.h>
|
|
#include <consensus/validation.h>
|
|
#include <net_processing.h>
|
|
#include <node/eviction.h>
|
|
#include <policy/policy.h>
|
|
#include <primitives/transaction.h>
|
|
#include <script/script.h>
|
|
#include <sync.h>
|
|
#include <test/fuzz/FuzzedDataProvider.h>
|
|
#include <test/fuzz/fuzz.h>
|
|
#include <test/fuzz/util.h>
|
|
#include <test/util/setup_common.h>
|
|
#include <txorphanage.h>
|
|
#include <uint256.h>
|
|
#include <util/check.h>
|
|
#include <util/time.h>
|
|
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <set>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
void initialize_orphanage()
|
|
{
|
|
static const auto testing_setup = MakeNoLogFileContext();
|
|
}
|
|
|
|
FUZZ_TARGET_INIT(txorphan, initialize_orphanage)
|
|
{
|
|
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
|
|
SetMockTime(ConsumeTime(fuzzed_data_provider));
|
|
|
|
TxOrphanage orphanage;
|
|
std::vector<COutPoint> outpoints;
|
|
// initial outpoints used to construct transactions later
|
|
for (uint8_t i = 0; i < 4; i++) {
|
|
outpoints.emplace_back(uint256{i}, 0);
|
|
}
|
|
// if true, allow duplicate input when constructing tx
|
|
const bool duplicate_input = fuzzed_data_provider.ConsumeBool();
|
|
|
|
LIMITED_WHILE(outpoints.size() < 200'000 && fuzzed_data_provider.ConsumeBool(), 10 * DEFAULT_MAX_ORPHAN_TRANSACTIONS)
|
|
{
|
|
// construct transaction
|
|
const CTransactionRef tx = [&] {
|
|
CMutableTransaction tx_mut;
|
|
const auto num_in = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(1, outpoints.size());
|
|
const auto num_out = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(1, outpoints.size());
|
|
// pick unique outpoints from outpoints as input
|
|
for (uint32_t i = 0; i < num_in; i++) {
|
|
auto& prevout = PickValue(fuzzed_data_provider, outpoints);
|
|
tx_mut.vin.emplace_back(prevout);
|
|
// pop the picked outpoint if duplicate input is not allowed
|
|
if (!duplicate_input) {
|
|
std::swap(prevout, outpoints.back());
|
|
outpoints.pop_back();
|
|
}
|
|
}
|
|
// output amount will not affect txorphanage
|
|
for (uint32_t i = 0; i < num_out; i++) {
|
|
tx_mut.vout.emplace_back(CAmount{0}, CScript{});
|
|
}
|
|
// restore previously popped outpoints
|
|
for (auto& in : tx_mut.vin) {
|
|
outpoints.push_back(in.prevout);
|
|
}
|
|
auto new_tx = MakeTransactionRef(tx_mut);
|
|
// add newly constructed transaction to outpoints
|
|
for (uint32_t i = 0; i < num_out; i++) {
|
|
outpoints.emplace_back(new_tx->GetHash(), i);
|
|
}
|
|
return new_tx;
|
|
}();
|
|
|
|
// trigger orphanage functions
|
|
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10 * DEFAULT_MAX_ORPHAN_TRANSACTIONS)
|
|
{
|
|
NodeId peer_id = fuzzed_data_provider.ConsumeIntegral<NodeId>();
|
|
|
|
CallOneOf(
|
|
fuzzed_data_provider,
|
|
[&] {
|
|
orphanage.AddChildrenToWorkSet(*tx);
|
|
},
|
|
[&] {
|
|
{
|
|
CTransactionRef ref = orphanage.GetTxToReconsider(peer_id);
|
|
if (ref) {
|
|
bool have_tx = orphanage.HaveTx(GenTxid::Txid(ref->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(ref->GetHash()));
|
|
Assert(have_tx);
|
|
}
|
|
}
|
|
},
|
|
[&] {
|
|
bool have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
|
|
// AddTx should return false if tx is too big or already have it
|
|
// tx weight is unknown, we only check when tx is already in orphanage
|
|
{
|
|
bool add_tx = orphanage.AddTx(tx, peer_id);
|
|
// have_tx == true -> add_tx == false
|
|
Assert(!have_tx || !add_tx);
|
|
}
|
|
have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
|
|
{
|
|
bool add_tx = orphanage.AddTx(tx, peer_id);
|
|
// if have_tx is still false, it must be too big
|
|
Assert(!have_tx == (GetTransactionWeight(*tx) > MAX_STANDARD_TX_WEIGHT));
|
|
Assert(!have_tx || !add_tx);
|
|
}
|
|
},
|
|
[&] {
|
|
bool have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
|
|
// EraseTx should return 0 if m_orphans doesn't have the tx
|
|
{
|
|
Assert(have_tx == orphanage.EraseTx(tx->GetHash()));
|
|
}
|
|
have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
|
|
// have_tx should be false and EraseTx should fail
|
|
{
|
|
Assert(!have_tx && !orphanage.EraseTx(tx->GetHash()));
|
|
}
|
|
},
|
|
[&] {
|
|
orphanage.EraseForPeer(peer_id);
|
|
},
|
|
[&] {
|
|
// test mocktime and expiry
|
|
SetMockTime(ConsumeTime(fuzzed_data_provider));
|
|
auto limit = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
|
|
orphanage.LimitOrphans(limit);
|
|
Assert(orphanage.Size() <= limit);
|
|
});
|
|
}
|
|
}
|
|
}
|