mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-10 11:57:28 -03:00
Merge bitcoin/bitcoin#21798: fuzz: Create a block template in tx_pool targets
fa03d0acd6
fuzz: Create a block template in tx_pool targets (MarcoFalke)fa61ce5cf5
fuzz: Limit mocktime to MTP in tx_pool targets (MarcoFalke)fab646b8ea
fuzz: Use correct variant of ConsumeRandomLengthString instead of hardcoding a maximum size (MarcoFalke)fae2c8bc54
fuzz: Allow to pass min/max to ConsumeTime (MarcoFalke) Pull request description: Relatively simple check to ensure a block can always be created from the mempool ACKs for top commit: practicalswift: Tested ACKfa03d0acd6
Tree-SHA512: e613376ccc88591cbe594db14ea21ebc9b2b191f6325b3aa4ee0cd379695352ad3b480e286134ef6ee30f043d486cf9792a1bc7e44445c41045ac8c3b931c7ff
This commit is contained in:
commit
1fcf66af68
4 changed files with 80 additions and 31 deletions
|
@ -3,6 +3,7 @@
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <consensus/validation.h>
|
||||
#include <miner.h>
|
||||
#include <test/fuzz/FuzzedDataProvider.h>
|
||||
#include <test/fuzz/fuzz.h>
|
||||
#include <test/fuzz/util.h>
|
||||
|
@ -77,13 +78,44 @@ void SetMempoolConstraints(ArgsManager& args, FuzzedDataProvider& fuzzed_data_pr
|
|||
ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 999)));
|
||||
}
|
||||
|
||||
void Finish(FuzzedDataProvider& fuzzed_data_provider, MockedTxPool& tx_pool, CChainState& chainstate)
|
||||
{
|
||||
WITH_LOCK(::cs_main, tx_pool.check(chainstate));
|
||||
{
|
||||
BlockAssembler::Options options;
|
||||
options.nBlockMaxWeight = fuzzed_data_provider.ConsumeIntegralInRange(0U, MAX_BLOCK_WEIGHT);
|
||||
options.blockMinFeeRate = CFeeRate{ConsumeMoney(fuzzed_data_provider)};
|
||||
auto assembler = BlockAssembler{chainstate, *static_cast<CTxMemPool*>(&tx_pool), ::Params(), options};
|
||||
auto block_template = assembler.CreateNewBlock(CScript{} << OP_TRUE);
|
||||
Assert(block_template->block.vtx.size() >= 1);
|
||||
}
|
||||
const auto info_all = tx_pool.infoAll();
|
||||
if (!info_all.empty()) {
|
||||
const auto& tx_to_remove = *PickValue(fuzzed_data_provider, info_all).tx;
|
||||
WITH_LOCK(tx_pool.cs, tx_pool.removeRecursive(tx_to_remove, /* dummy */ MemPoolRemovalReason::BLOCK));
|
||||
std::vector<uint256> all_txids;
|
||||
tx_pool.queryHashes(all_txids);
|
||||
assert(all_txids.size() < info_all.size());
|
||||
WITH_LOCK(::cs_main, tx_pool.check(chainstate));
|
||||
}
|
||||
SyncWithValidationInterfaceQueue();
|
||||
}
|
||||
|
||||
void MockTime(FuzzedDataProvider& fuzzed_data_provider, const CChainState& chainstate)
|
||||
{
|
||||
const auto time = ConsumeTime(fuzzed_data_provider,
|
||||
chainstate.m_chain.Tip()->GetMedianTimePast() + 1,
|
||||
std::numeric_limits<decltype(chainstate.m_chain.Tip()->nTime)>::max());
|
||||
SetMockTime(time);
|
||||
}
|
||||
|
||||
FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
|
||||
{
|
||||
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
|
||||
const auto& node = g_setup->m_node;
|
||||
auto& chainstate = node.chainman->ActiveChainstate();
|
||||
|
||||
SetMockTime(ConsumeTime(fuzzed_data_provider));
|
||||
MockTime(fuzzed_data_provider, chainstate);
|
||||
SetMempoolConstraints(*node.args, fuzzed_data_provider);
|
||||
|
||||
// All RBF-spendable outpoints
|
||||
|
@ -163,7 +195,7 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
|
|||
}();
|
||||
|
||||
if (fuzzed_data_provider.ConsumeBool()) {
|
||||
SetMockTime(ConsumeTime(fuzzed_data_provider));
|
||||
MockTime(fuzzed_data_provider, chainstate);
|
||||
}
|
||||
if (fuzzed_data_provider.ConsumeBool()) {
|
||||
SetMempoolConstraints(*node.args, fuzzed_data_provider);
|
||||
|
@ -237,23 +269,17 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
|
|||
}
|
||||
}
|
||||
}
|
||||
WITH_LOCK(::cs_main, tx_pool.check(chainstate));
|
||||
const auto info_all = tx_pool.infoAll();
|
||||
if (!info_all.empty()) {
|
||||
const auto& tx_to_remove = *PickValue(fuzzed_data_provider, info_all).tx;
|
||||
WITH_LOCK(tx_pool.cs, tx_pool.removeRecursive(tx_to_remove, /* dummy */ MemPoolRemovalReason::BLOCK));
|
||||
std::vector<uint256> all_txids;
|
||||
tx_pool.queryHashes(all_txids);
|
||||
assert(all_txids.size() < info_all.size());
|
||||
WITH_LOCK(::cs_main, tx_pool.check(chainstate));
|
||||
}
|
||||
SyncWithValidationInterfaceQueue();
|
||||
Finish(fuzzed_data_provider, tx_pool, chainstate);
|
||||
}
|
||||
|
||||
FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
|
||||
{
|
||||
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
|
||||
const auto& node = g_setup->m_node;
|
||||
auto& chainstate = node.chainman->ActiveChainstate();
|
||||
|
||||
MockTime(fuzzed_data_provider, chainstate);
|
||||
SetMempoolConstraints(*node.args, fuzzed_data_provider);
|
||||
|
||||
std::vector<uint256> txids;
|
||||
for (const auto& outpoint : g_outpoints_coinbase_init_mature) {
|
||||
|
@ -265,11 +291,29 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
|
|||
txids.push_back(ConsumeUInt256(fuzzed_data_provider));
|
||||
}
|
||||
|
||||
CTxMemPool tx_pool{/* estimator */ nullptr, /* check_ratio */ 1};
|
||||
CTxMemPool tx_pool_{/* estimator */ nullptr, /* check_ratio */ 1};
|
||||
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_);
|
||||
|
||||
while (fuzzed_data_provider.ConsumeBool()) {
|
||||
const auto mut_tx = ConsumeTransaction(fuzzed_data_provider, txids);
|
||||
|
||||
if (fuzzed_data_provider.ConsumeBool()) {
|
||||
MockTime(fuzzed_data_provider, chainstate);
|
||||
}
|
||||
if (fuzzed_data_provider.ConsumeBool()) {
|
||||
SetMempoolConstraints(*node.args, fuzzed_data_provider);
|
||||
}
|
||||
if (fuzzed_data_provider.ConsumeBool()) {
|
||||
tx_pool.RollingFeeUpdate();
|
||||
}
|
||||
if (fuzzed_data_provider.ConsumeBool()) {
|
||||
const auto& txid = fuzzed_data_provider.ConsumeBool() ?
|
||||
mut_tx.GetHash() :
|
||||
PickValue(fuzzed_data_provider, txids);
|
||||
const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
|
||||
tx_pool.PrioritiseTransaction(txid, delta);
|
||||
}
|
||||
|
||||
const auto tx = MakeTransactionRef(mut_tx);
|
||||
const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
|
||||
::fRequireStandard = fuzzed_data_provider.ConsumeBool();
|
||||
|
@ -278,8 +322,7 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
|
|||
if (accepted) {
|
||||
txids.push_back(tx->GetHash());
|
||||
}
|
||||
|
||||
SyncWithValidationInterfaceQueue();
|
||||
}
|
||||
Finish(fuzzed_data_provider, tx_pool, chainstate);
|
||||
}
|
||||
} // namespace
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <test/fuzz/util.h>
|
||||
#include <test/util/script.h>
|
||||
#include <util/rbf.h>
|
||||
#include <util/time.h>
|
||||
#include <version.h>
|
||||
|
||||
FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider)
|
||||
|
@ -216,6 +217,14 @@ void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, bool init_v
|
|||
}
|
||||
}
|
||||
|
||||
int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider, const std::optional<int64_t>& min, const std::optional<int64_t>& max) noexcept
|
||||
{
|
||||
// Avoid t=0 (1970-01-01T00:00:00Z) since SetMockTime(0) disables mocktime.
|
||||
static const int64_t time_min = ParseISO8601DateTime("1970-01-01T00:00:01Z");
|
||||
static const int64_t time_max = ParseISO8601DateTime("9999-12-31T23:59:59Z");
|
||||
return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(min.value_or(time_min), max.value_or(time_max));
|
||||
}
|
||||
|
||||
CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<uint256>>& prevout_txids, const int max_num_in, const int max_num_out) noexcept
|
||||
{
|
||||
CMutableTransaction tx_mut;
|
||||
|
@ -267,7 +276,7 @@ CScriptWitness ConsumeScriptWitness(FuzzedDataProvider& fuzzed_data_provider, co
|
|||
return ret;
|
||||
}
|
||||
|
||||
CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length, const bool maybe_p2wsh) noexcept
|
||||
CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length, const bool maybe_p2wsh) noexcept
|
||||
{
|
||||
const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length);
|
||||
CScript r_script{b.begin(), b.end()};
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include <test/util/net.h>
|
||||
#include <txmempool.h>
|
||||
#include <uint256.h>
|
||||
#include <util/time.h>
|
||||
#include <version.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
@ -58,18 +57,20 @@ auto& PickValue(FuzzedDataProvider& fuzzed_data_provider, Collection& col)
|
|||
return *it;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::vector<uint8_t> ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
|
||||
[[nodiscard]] inline std::vector<uint8_t> ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept
|
||||
{
|
||||
const std::string s = fuzzed_data_provider.ConsumeRandomLengthString(max_length);
|
||||
const std::string s = max_length ?
|
||||
fuzzed_data_provider.ConsumeRandomLengthString(*max_length) :
|
||||
fuzzed_data_provider.ConsumeRandomLengthString();
|
||||
return {s.begin(), s.end()};
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::vector<bool> ConsumeRandomLengthBitVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
|
||||
[[nodiscard]] inline std::vector<bool> ConsumeRandomLengthBitVector(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept
|
||||
{
|
||||
return BytesToBits(ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline CDataStream ConsumeDataStream(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
|
||||
[[nodiscard]] inline CDataStream ConsumeDataStream(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept
|
||||
{
|
||||
return CDataStream{ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length), SER_NETWORK, INIT_PROTO_VERSION};
|
||||
}
|
||||
|
@ -96,7 +97,7 @@ template <typename T>
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] inline std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
|
||||
[[nodiscard]] inline std::optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt) noexcept
|
||||
{
|
||||
const std::vector<uint8_t> buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length);
|
||||
CDataStream ds{buffer, SER_NETWORK, INIT_PROTO_VERSION};
|
||||
|
@ -127,19 +128,13 @@ template <typename WeakEnumType, size_t size>
|
|||
return fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, MAX_MONEY);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider) noexcept
|
||||
{
|
||||
// Avoid t=0 (1970-01-01T00:00:00Z) since SetMockTime(0) is a no-op.
|
||||
static const int64_t time_min = ParseISO8601DateTime("1970-01-01T00:00:01Z");
|
||||
static const int64_t time_max = ParseISO8601DateTime("9999-12-31T23:59:59Z");
|
||||
return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(time_min, time_max);
|
||||
}
|
||||
[[nodiscard]] int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider, const std::optional<int64_t>& min = std::nullopt, const std::optional<int64_t>& max = std::nullopt) noexcept;
|
||||
|
||||
[[nodiscard]] CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional<std::vector<uint256>>& prevout_txids, const int max_num_in = 10, const int max_num_out = 10) noexcept;
|
||||
|
||||
[[nodiscard]] CScriptWitness ConsumeScriptWitness(FuzzedDataProvider& fuzzed_data_provider, const size_t max_stack_elem_size = 32) noexcept;
|
||||
|
||||
[[nodiscard]] CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096, const bool maybe_p2wsh = false) noexcept;
|
||||
[[nodiscard]] CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider, const std::optional<size_t>& max_length = std::nullopt, const bool maybe_p2wsh = false) noexcept;
|
||||
|
||||
[[nodiscard]] uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept;
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
# names can be used.
|
||||
# See https://github.com/google/sanitizers/issues/1364
|
||||
signed-integer-overflow:txmempool.cpp
|
||||
# https://github.com/bitcoin/bitcoin/pull/21798#issuecomment-829180719
|
||||
signed-integer-overflow:policy/feerate.cpp
|
||||
|
||||
# -fsanitize=integer suppressions
|
||||
# ===============================
|
||||
|
|
Loading…
Reference in a new issue