From fae2c8bc54e6c0fe69a82bd1b232c52edd1acd34 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 28 Apr 2021 20:36:36 +0200 Subject: fuzz: Allow to pass min/max to ConsumeTime --- src/test/fuzz/util.cpp | 9 +++++++++ src/test/fuzz/util.h | 9 +-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp index b8d846a995..6966c9b3ae 100644 --- a/src/test/fuzz/util.cpp +++ b/src/test/fuzz/util.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include 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& min, const std::optional& 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(min.value_or(time_min), max.value_or(time_max)); +} + CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional>& prevout_txids, const int max_num_in, const int max_num_out) noexcept { CMutableTransaction tx_mut; diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h index 8f4f87fbdc..6dfb35a7d4 100644 --- a/src/test/fuzz/util.h +++ b/src/test/fuzz/util.h @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -127,13 +126,7 @@ template return fuzzed_data_provider.ConsumeIntegralInRange(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(time_min, time_max); -} +[[nodiscard]] int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider, const std::optional& min = std::nullopt, const std::optional& max = std::nullopt) noexcept; [[nodiscard]] CMutableTransaction ConsumeTransaction(FuzzedDataProvider& fuzzed_data_provider, const std::optional>& prevout_txids, const int max_num_in = 10, const int max_num_out = 10) noexcept; -- cgit v1.2.3 From fab646b8ea293bb2b03707c6ef6790982625e492 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 28 Apr 2021 20:48:10 +0200 Subject: fuzz: Use correct variant of ConsumeRandomLengthString instead of hardcoding a maximum size This is technically a breaking change. This allows the fuzz engine to pick the right size, also larger sizes, if needed. --- src/test/fuzz/util.cpp | 2 +- src/test/fuzz/util.h | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp index 6966c9b3ae..dc89f25e26 100644 --- a/src/test/fuzz/util.cpp +++ b/src/test/fuzz/util.cpp @@ -276,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& max_length, const bool maybe_p2wsh) noexcept { const std::vector b = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length); CScript r_script{b.begin(), b.end()}; diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h index 6dfb35a7d4..1a83f7a57a 100644 --- a/src/test/fuzz/util.h +++ b/src/test/fuzz/util.h @@ -57,18 +57,20 @@ auto& PickValue(FuzzedDataProvider& fuzzed_data_provider, Collection& col) return *it; } -[[nodiscard]] inline std::vector ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept +[[nodiscard]] inline std::vector ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const std::optional& 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 ConsumeRandomLengthBitVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept +[[nodiscard]] inline std::vector ConsumeRandomLengthBitVector(FuzzedDataProvider& fuzzed_data_provider, const std::optional& 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& max_length = std::nullopt) noexcept { return CDataStream{ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length), SER_NETWORK, INIT_PROTO_VERSION}; } @@ -95,7 +97,7 @@ template } template -[[nodiscard]] inline std::optional ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept +[[nodiscard]] inline std::optional ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const std::optional& max_length = std::nullopt) noexcept { const std::vector buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length); CDataStream ds{buffer, SER_NETWORK, INIT_PROTO_VERSION}; @@ -132,7 +134,7 @@ template [[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& max_length = std::nullopt, const bool maybe_p2wsh = false) noexcept; [[nodiscard]] uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept; -- cgit v1.2.3 From fa61ce5cf5c1d73d352173806571bcd7799ed2ee Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 28 Apr 2021 20:53:18 +0200 Subject: fuzz: Limit mocktime to MTP in tx_pool targets This is needed for the next commit to generate blocks. Also, apply the same mocking strategies to both targets. --- src/test/fuzz/tx_pool.cpp | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp index fe8d17b24a..a74734494f 100644 --- a/src/test/fuzz/tx_pool.cpp +++ b/src/test/fuzz/tx_pool.cpp @@ -77,13 +77,21 @@ void SetMempoolConstraints(ArgsManager& args, FuzzedDataProvider& fuzzed_data_pr ToString(fuzzed_data_provider.ConsumeIntegralInRange(0, 999))); } +void MockTime(FuzzedDataProvider& fuzzed_data_provider, const CChainState& chainstate) +{ + const auto time = ConsumeTime(fuzzed_data_provider, + chainstate.m_chain.Tip()->GetMedianTimePast() + 1, + std::numeric_limitsnTime)>::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 +171,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); @@ -254,6 +262,10 @@ 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 txids; for (const auto& outpoint : g_outpoints_coinbase_init_mature) { @@ -265,11 +277,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(&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(-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(); -- cgit v1.2.3 From fa03d0acd6bd8bb6d3d5227512f042ff537ad993 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 28 Apr 2021 21:04:14 +0200 Subject: fuzz: Create a block template in tx_pool targets --- src/test/fuzz/tx_pool.cpp | 39 ++++++++++++++++++++++++++------------- test/sanitizer_suppressions/ubsan | 2 ++ 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp index a74734494f..59229987ba 100644 --- a/src/test/fuzz/tx_pool.cpp +++ b/src/test/fuzz/tx_pool.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include #include @@ -77,6 +78,29 @@ void SetMempoolConstraints(ArgsManager& args, FuzzedDataProvider& fuzzed_data_pr ToString(fuzzed_data_provider.ConsumeIntegralInRange(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(&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 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, @@ -245,17 +269,7 @@ 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 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) @@ -308,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 diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan index 27885b094e..6603897c27 100644 --- a/test/sanitizer_suppressions/ubsan +++ b/test/sanitizer_suppressions/ubsan @@ -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 # =============================== -- cgit v1.2.3