Merge pull request #5548 from kwvg/fuzz6

backport: merge bitcoin#19143, #20377, #20946, #20936, #21226, #21264, #19259, #21380, #21489, #19288, #19055, #20882, #21185, #21115, partial bitcoin#11389 (fuzzing harness backports: part 6)
This commit is contained in:
PastaPastaPasta 2023-08-29 21:56:14 -05:00 committed by GitHub
commit 2b32dd6394
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 948 additions and 210 deletions

View File

@ -14,4 +14,4 @@ export DEP_OPTS="NO_UPNP=1 DEBUG=1"
export RUN_UNIT_TESTS_SEQUENTIAL="true"
export RUN_UNIT_TESTS="false"
export GOAL="install"
export BITCOIN_CONFIG="--enable-zmq --enable-reduce-exports LDFLAGS=-static-libstdc++"
export BITCOIN_CONFIG="--enable-zmq --enable-reduce-exports --disable-fuzz-binary LDFLAGS=-static-libstdc++"

View File

@ -178,10 +178,16 @@ AC_ARG_ENABLE([extended-functional-tests],
AC_ARG_ENABLE([fuzz],
AS_HELP_STRING([--enable-fuzz],
[enable building of fuzz targets (default no). enabling this will disable all other targets]),
[build for fuzzing (default no). enabling this will disable all other targets and override --{enable,disable}-fuzz-binary]),
[enable_fuzz=$enableval],
[enable_fuzz=no])
AC_ARG_ENABLE([fuzz-binary],
AS_HELP_STRING([--enable-fuzz-binary],
[enable building of fuzz binary (default yes).]),
[enable_fuzz_binary=$enableval],
[enable_fuzz_binary=yes])
AC_ARG_ENABLE([danger_fuzz_link_all],
AS_HELP_STRING([--enable-danger-fuzz-link-all],
[Danger! Modifies source code. Needs git and gnu sed installed. Link each fuzz target (default no).]),
@ -1275,7 +1281,7 @@ AC_DEFUN([SUPPRESS_WARNINGS],
dnl enable-fuzz should disable all other targets
if test "x$enable_fuzz" = "xyes"; then
AC_MSG_WARN(enable-fuzz will disable all other targets)
AC_MSG_WARN(enable-fuzz will disable all other targets and force --enable-fuzz-binary=yes)
build_bitcoin_utils=no
build_bitcoin_cli=no
build_bitcoin_tx=no
@ -1290,15 +1296,16 @@ if test "x$enable_fuzz" = "xyes"; then
use_upnp=no
use_natpmp=no
use_zmq=no
enable_fuzz_binary=yes
AX_CHECK_PREPROC_FLAG([-DABORT_ON_FAILED_ASSUME],[[DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DABORT_ON_FAILED_ASSUME"]],,[[$CXXFLAG_WERROR]])
AC_MSG_CHECKING([whether main function is needed])
AC_MSG_CHECKING([whether main function is needed for fuzz binary])
AX_CHECK_LINK_FLAG(
[[-fsanitize=$use_sanitizers]],
[AC_MSG_RESULT([no])],
[AC_MSG_RESULT([yes])
CPPFLAGS="$CPPFLAGS -DPROVIDE_MAIN_FUNCTION"],
CPPFLAGS="$CPPFLAGS -DPROVIDE_FUZZ_MAIN_FUNCTION"],
[],
[AC_LANG_PROGRAM([[
#include <cstdint>
@ -1321,6 +1328,8 @@ else
QT_DBUS_INCLUDES=SUPPRESS_WARNINGS($QT_DBUS_INCLUDES)
QT_TEST_INCLUDES=SUPPRESS_WARNINGS($QT_TEST_INCLUDES)
fi
CPPFLAGS="$CPPFLAGS -DPROVIDE_FUZZ_MAIN_FUNCTION"
fi
if test x$enable_wallet != xno; then
@ -1733,6 +1742,7 @@ AM_CONDITIONAL([USE_SQLITE], [test "x$use_sqlite" = "xyes"])
AM_CONDITIONAL([USE_BDB], [test "x$use_bdb" = "xyes"])
AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes])
AM_CONDITIONAL([ENABLE_FUZZ],[test x$enable_fuzz = xyes])
AM_CONDITIONAL([ENABLE_FUZZ_BINARY],[test x$enable_fuzz_binary = xyes])
AM_CONDITIONAL([ENABLE_FUZZ_LINK_ALL],[test x$enable_danger_fuzz_link_all = xyes])
AM_CONDITIONAL([ENABLE_QT],[test x$bitcoin_enable_qt = xyes])
AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$BUILD_TEST_QT = xyes])
@ -1748,6 +1758,8 @@ AM_CONDITIONAL([ENABLE_ARM_CRC],[test x$enable_arm_crc = xyes])
AM_CONDITIONAL([ENABLE_ARM_SHANI], [test "$enable_arm_shani" = "yes"])
AM_CONDITIONAL([USE_ASM],[test x$use_asm = xyes])
AM_CONDITIONAL([WORDS_BIGENDIAN],[test x$ac_cv_c_bigendian = xyes])
AM_CONDITIONAL([USE_NATPMP],[test x$use_natpmp = xyes])
AM_CONDITIONAL([USE_UPNP],[test x$use_upnp = xyes])
AC_DEFINE(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR, [Major version])
AC_DEFINE(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR, [Minor version])

View File

@ -508,6 +508,7 @@ libbitcoin_wallet_a_SOURCES = \
coinjoin/client.cpp \
coinjoin/options.cpp \
coinjoin/util.cpp \
hdchain.cpp \
wallet/coincontrol.cpp \
wallet/context.cpp \
wallet/crypter.cpp \
@ -682,7 +683,6 @@ libbitcoin_common_a_SOURCES = \
compressor.cpp \
core_read.cpp \
core_write.cpp \
hdchain.cpp \
key.cpp \
key_io.cpp \
merkleblock.cpp \

View File

@ -3,9 +3,11 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
if ENABLE_FUZZ
if ENABLE_FUZZ_BINARY
noinst_PROGRAMS += test/fuzz/fuzz
else
endif
if !ENABLE_FUZZ
bin_PROGRAMS += test/test_dash
endif
@ -61,6 +63,14 @@ FUZZ_SUITE_LD_COMMON = \
$(GMP_LIBS) \
$(BACKTRACE_LIB)
if USE_UPNP
FUZZ_SUITE_LD_COMMON += $(MINIUPNPC_LIBS)
endif
if USE_NATPMP
FUZZ_SUITE_LD_COMMON += $(NATPMP_LIBS)
endif
# test_dash binary #
BITCOIN_TESTS =\
test/arith_uint256_tests.cpp \
@ -178,10 +188,16 @@ BITCOIN_TESTS += \
wallet/test/ismine_tests.cpp \
wallet/test/scriptpubkeyman_tests.cpp
FUZZ_SUITE_LD_COMMON +=\
$(LIBBITCOIN_WALLET) \
$(SQLITE_LIBS) \
$(BDB_LIBS)
if USE_BDB
BITCOIN_TESTS += wallet/test/db_tests.cpp
endif
BITCOIN_TEST_SUITE += \
wallet/test/wallet_test_fixture.cpp \
wallet/test/wallet_test_fixture.h \
@ -204,11 +220,12 @@ test_test_dash_LDFLAGS = $(LDFLAGS_WRAP_EXCEPTIONS) $(RELDFLAGS) $(AM_LDFLAGS) $
if ENABLE_ZMQ
test_test_dash_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
FUZZ_SUITE_LD_COMMON += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
if ENABLE_FUZZ
FUZZ_SUITE_LDFLAGS_COMMON = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(LDFLAGS_WRAP_EXCEPTIONS) $(PTHREAD_FLAGS)
if ENABLE_FUZZ_BINARY
test_fuzz_fuzz_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_fuzz_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_fuzz_LDADD = $(FUZZ_SUITE_LD_COMMON)
@ -240,6 +257,7 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp \
test/fuzz/crypto_poly1305.cpp \
test/fuzz/cuckoocache.cpp \
test/fuzz/data_stream.cpp \
test/fuzz/decode_tx.cpp \
test/fuzz/descriptor_parse.cpp \
test/fuzz/deserialize.cpp \
@ -260,6 +278,7 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/locale.cpp \
test/fuzz/merkleblock.cpp \
test/fuzz/message.cpp \
test/fuzz/muhash.cpp \
test/fuzz/multiplication_overflow.cpp \
test/fuzz/net.cpp \
test/fuzz/net_permissions.cpp \
@ -272,6 +291,7 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/parse_script.cpp \
test/fuzz/parse_univalue.cpp \
test/fuzz/policy_estimator.cpp \
test/fuzz/policy_estimator_io.cpp \
test/fuzz/pow.cpp \
test/fuzz/prevector.cpp \
test/fuzz/primitives_transaction.cpp \
@ -300,11 +320,13 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/strprintf.cpp \
test/fuzz/system.cpp \
test/fuzz/timedata.cpp \
test/fuzz/torcontrol.cpp \
test/fuzz/transaction.cpp \
test/fuzz/tx_in.cpp \
test/fuzz/tx_out.cpp
endif # ENABLE_FUZZ
test/fuzz/tx_out.cpp \
test/fuzz/validation_load_mempool.cpp \
test/fuzz/versionbits.cpp
endif # ENABLE_FUZZ_BINARY
nodist_test_test_dash_SOURCES = $(GENERATED_TEST_FILES)

View File

@ -136,6 +136,7 @@ public:
CMainParams() {
strNetworkID = CBaseChainParams::MAIN;
consensus.nSubsidyHalvingInterval = 210240; // Note: actual number of blocks per calendar year with DGW v3 is ~200700 (for example 449750 - 249050)
consensus.BIP16Height = 0;
consensus.nMasternodePaymentsStartBlock = 100000; // not true, but it's ok as long as it's less then nMasternodePaymentsIncreaseBlock
consensus.nMasternodePaymentsIncreaseBlock = 158000; // actual historical value
consensus.nMasternodePaymentsIncreasePeriod = 576*30; // 17280 - actual historical value
@ -182,7 +183,7 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_V20].bit = 9;
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nStartTime = 19999999999; // TODO: To be determined later
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nTimeout = 999999999999ULL;
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nWindowSize = 4032;
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nThresholdStart = 3226; // 80% of 4032
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nThresholdMin = 2420; // 60% of 4032
@ -190,7 +191,7 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].bit = 10;
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nStartTime = 19999999999; // TODO: To be determined later
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nTimeout = 999999999999ULL;
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nWindowSize = 4032;
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nThresholdStart = 3226; // 80% of 4032
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nThresholdMin = 2420; // 60% of 4032
@ -332,6 +333,7 @@ public:
CTestNetParams() {
strNetworkID = CBaseChainParams::TESTNET;
consensus.nSubsidyHalvingInterval = 210240;
consensus.BIP16Height = 0;
consensus.nMasternodePaymentsStartBlock = 4010; // not true, but it's ok as long as it's less then nMasternodePaymentsIncreaseBlock
consensus.nMasternodePaymentsIncreaseBlock = 4030;
consensus.nMasternodePaymentsIncreasePeriod = 10;
@ -378,7 +380,7 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_V20].bit = 9;
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nStartTime = 19999999999; // TODO: To be determined later
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nTimeout = 999999999999ULL;
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nWindowSize = 100;
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nThresholdStart = 80; // 80% of 100
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nThresholdMin = 60; // 60% of 100
@ -386,7 +388,7 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].bit = 10;
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nStartTime = 19999999999; // TODO: To be determined later
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nTimeout = 999999999999ULL;
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nWindowSize = 100;
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nThresholdStart = 80; // 80% of 100
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nThresholdMin = 60; // 60% of 100
@ -503,6 +505,7 @@ public:
explicit CDevNetParams(const ArgsManager& args) {
strNetworkID = CBaseChainParams::DEVNET;
consensus.nSubsidyHalvingInterval = 210240;
consensus.BIP16Height = 0;
consensus.nMasternodePaymentsStartBlock = 4010; // not true, but it's ok as long as it's less then nMasternodePaymentsIncreaseBlock
consensus.nMasternodePaymentsIncreaseBlock = 4030;
consensus.nMasternodePaymentsIncreasePeriod = 10;
@ -548,7 +551,7 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_V20].bit = 9;
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nStartTime = 1661990400; // Sep 1st, 2022
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nTimeout = 999999999999ULL;
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nWindowSize = 120;
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nThresholdStart = 80; // 80% of 100
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nThresholdMin = 60; // 60% of 100
@ -556,7 +559,7 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].bit = 10;
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nStartTime = 1661990400; // Sep 1st, 2022
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nTimeout = 999999999999ULL;
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nWindowSize = 120;
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nThresholdStart = 80; // 80% of 100
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nThresholdMin = 60; // 60% of 100
@ -739,6 +742,7 @@ public:
explicit CRegTestParams(const ArgsManager& args) {
strNetworkID = CBaseChainParams::REGTEST;
consensus.nSubsidyHalvingInterval = 150;
consensus.BIP16Height = 0; // always enforce P2SH BIP16 on regtest
consensus.nMasternodePaymentsStartBlock = 240;
consensus.nMasternodePaymentsIncreaseBlock = 350;
consensus.nMasternodePaymentsIncreasePeriod = 10;
@ -781,11 +785,11 @@ public:
consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016)
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 999999999999ULL;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_V20].bit = 9;
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nTimeout = 999999999999ULL;
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nWindowSize = 480;
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nThresholdStart = 384; // 80% of 480
consensus.vDeployments[Consensus::DEPLOYMENT_V20].nThresholdMin = 288; // 60% of 480
@ -793,7 +797,7 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].bit = 10;
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nTimeout = 999999999999ULL;
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nWindowSize = 1030;
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nThresholdStart = 800; // 80% of 1000
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nThresholdMin = 600; // 60% of 1000

View File

@ -9,6 +9,7 @@
#include <uint256.h>
#include <llmq/params.h>
#include <limits>
#include <map>
namespace Consensus {
@ -39,6 +40,15 @@ struct BIP9Deployment {
int64_t nThresholdMin{0};
/** A coefficient which adjusts the speed a required number of signaling blocks is decreasing from nThresholdStart to nThresholdMin at with each period. */
int64_t nFalloffCoeff{0};
/** Constant for nTimeout very far in the future. */
static constexpr int64_t NO_TIMEOUT = std::numeric_limits<int64_t>::max();
/** Special value for nStartTime indicating that the deployment is always active.
* This is useful for testing, as it means tests don't need to deal with the activation
* process (which takes at least 3 BIP9 intervals). Only tests that specifically test the
* behaviour during activation cannot use this. */
static constexpr int64_t ALWAYS_ACTIVE = -1;
};
/**
@ -48,6 +58,8 @@ struct Params {
uint256 hashGenesisBlock;
uint256 hashDevnetGenesisBlock;
int nSubsidyHalvingInterval;
/** Block height at which BIP16 becomes active */
int BIP16Height;
int nMasternodePaymentsStartBlock;
int nMasternodePaymentsIncreaseBlock;
int nMasternodePaymentsIncreasePeriod; // in blocks

View File

@ -26,7 +26,7 @@ int64_t ConsumeBanTimeOffset(FuzzedDataProvider& fuzzed_data_provider) noexcept
void initialize_banman()
{
InitializeFuzzingContext();
static const auto testing_setup = MakeNoLogFileContext<>();
}
FUZZ_TARGET_INIT(banman, initialize_banman)

View File

@ -37,9 +37,7 @@ bool operator==(const Coin& a, const Coin& b)
void initialize_coins_view()
{
static const ECCVerifyHandle ecc_verify_handle;
ECC_Start();
SelectParams(CBaseChainParams::REGTEST);
static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
}
FUZZ_TARGET_INIT(coins_view, initialize_coins_view)

View File

@ -17,7 +17,7 @@
void initialize_connman()
{
InitializeFuzzingContext();
static const auto testing_setup = MakeNoLogFileContext<>();
}
FUZZ_TARGET_INIT(connman, initialize_connman)

View File

@ -0,0 +1,25 @@
// Copyright (c) 2020 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 <addrman.h>
#include <net.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <cstdint>
#include <vector>
void initialize_data_stream_addr_man()
{
static const auto testing_setup = MakeNoLogFileContext<>();
}
FUZZ_TARGET_INIT(data_stream_addr_man, initialize_data_stream_addr_man)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider);
CAddrMan addr_man;
CAddrDB::Read(addr_man, data_stream);
}

View File

@ -43,7 +43,7 @@ void initialize()
std::get<1>(it->second)();
}
#if defined(PROVIDE_MAIN_FUNCTION)
#if defined(PROVIDE_FUZZ_MAIN_FUNCTION)
static bool read_stdin(std::vector<uint8_t>& data)
{
uint8_t buffer[1024];
@ -71,8 +71,8 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
return 0;
}
#if defined(PROVIDE_MAIN_FUNCTION)
__attribute__((weak)) int main(int argc, char** argv)
#if defined(PROVIDE_FUZZ_MAIN_FUNCTION)
int main(int argc, char** argv)
{
initialize();
static const auto& test_one_input = *Assert(g_test_one_input);

View File

@ -14,7 +14,7 @@
void initialize_i2p()
{
InitializeFuzzingContext();
static const auto testing_setup = MakeNoLogFileContext<>();
}
FUZZ_TARGET_INIT(i2p, initialize_i2p)

View File

@ -2,6 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <merkleblock.h>
#include <policy/fees.h>
#include <rpc/util.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
@ -9,9 +11,31 @@
#include <util/error.h>
#include <util/translation.h>
#include <array>
#include <cstdint>
#include <vector>
namespace {
constexpr TransactionError ALL_TRANSACTION_ERROR[] = {
TransactionError::OK,
TransactionError::MISSING_INPUTS,
TransactionError::ALREADY_IN_CHAIN,
TransactionError::P2P_DISABLED,
TransactionError::MEMPOOL_REJECTED,
TransactionError::MEMPOOL_ERROR,
TransactionError::INVALID_PSBT,
TransactionError::PSBT_MISMATCH,
TransactionError::SIGHASH_MISMATCH,
TransactionError::MAX_FEE_EXCEEDED,
};
constexpr FeeEstimateHorizon ALL_FEE_EST_HORIZON[] = {
FeeEstimateHorizon::SHORT_HALFLIFE,
FeeEstimateHorizon::MED_HALFLIFE,
FeeEstimateHorizon::LONG_HALFLIFE,
};
}; // namespace
// The fuzzing kitchen sink: Fuzzing harness for functions that need to be
// fuzzed but a.) don't belong in any existing fuzzing harness file, and
// b.) are not important enough to warrant their own fuzzing harness file.
@ -19,8 +43,15 @@ FUZZ_TARGET(kitchen_sink)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const TransactionError transaction_error = fuzzed_data_provider.PickValueInArray<TransactionError>({TransactionError::OK, TransactionError::MISSING_INPUTS, TransactionError::ALREADY_IN_CHAIN, TransactionError::P2P_DISABLED, TransactionError::MEMPOOL_REJECTED, TransactionError::MEMPOOL_ERROR, TransactionError::INVALID_PSBT, TransactionError::PSBT_MISMATCH, TransactionError::SIGHASH_MISMATCH, TransactionError::MAX_FEE_EXCEEDED});
const TransactionError transaction_error = fuzzed_data_provider.PickValueInArray(ALL_TRANSACTION_ERROR);
(void)JSONRPCTransactionError(transaction_error);
(void)RPCErrorFromTransactionError(transaction_error);
(void)TransactionErrorString(transaction_error);
(void)StringForFeeEstimateHorizon(fuzzed_data_provider.PickValueInArray(ALL_FEE_EST_HORIZON));
const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
const std::vector<bool> bits = BytesToBits(bytes);
const std::vector<uint8_t> bytes_decoded = BitsToBytes(bits);
assert(bytes == bytes_decoded);
}

View File

@ -15,7 +15,7 @@
void initialize_load_external_block_file()
{
InitializeFuzzingContext();
static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
}
FUZZ_TARGET_INIT(load_external_block_file, initialize_load_external_block_file)

63
src/test/fuzz/muhash.cpp Normal file
View File

@ -0,0 +1,63 @@
// Copyright (c) 2020 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 <crypto/muhash.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <vector>
FUZZ_TARGET(muhash)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
std::vector<uint8_t> data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
std::vector<uint8_t> data2 = ConsumeRandomLengthByteVector(fuzzed_data_provider);
if (data.empty()) {
data.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>());
}
if (data2.empty()) {
data2.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>());
}
data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
data2 = ConsumeRandomLengthByteVector(fuzzed_data_provider);
MuHash3072 muhash;
// Test that MuHash result is consistent independent of order of operations
muhash.Insert(data);
muhash.Insert(data2);
uint256 out;
muhash.Finalize(out);
muhash = MuHash3072();
muhash.Insert(data2);
muhash.Insert(data);
uint256 out2;
muhash.Finalize(out2);
assert(out == out2);
MuHash3072 muhash3;
muhash3 *= muhash;
uint256 out3;
muhash3.Finalize(out3);
assert(out == out3);
// Test that removing all added elements brings the object back to it's initial state
muhash /= muhash;
muhash.Finalize(out);
MuHash3072 muhash2;
muhash2.Finalize(out2);
assert(out == out2);
muhash3.Remove(data);
muhash3.Remove(data2);
muhash3.Finalize(out3);
assert(out == out3);
}

View File

@ -22,7 +22,7 @@
void initialize_net()
{
static const BasicTestingSetup basic_testing_setup;
static const auto testing_setup = MakeNoLogFileContext<>(CBaseChainParams::MAIN);
}
FUZZ_TARGET_INIT(net, initialize_net)

View File

@ -9,7 +9,6 @@
#include <cassert>
#include <cstdint>
#include <netinet/in.h>
#include <vector>
FUZZ_TARGET(netaddress)

View File

@ -14,7 +14,12 @@
#include <string>
#include <vector>
FUZZ_TARGET(policy_estimator)
void initialize_policy_estimator()
{
static const auto testing_setup = MakeNoLogFileContext<>();
}
FUZZ_TARGET_INIT(policy_estimator, initialize_policy_estimator)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
CBlockPolicyEstimator block_policy_estimator;
@ -62,4 +67,10 @@ FUZZ_TARGET(policy_estimator)
(void)block_policy_estimator.estimateSmartFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeBool() ? &fee_calculation : nullptr, fuzzed_data_provider.ConsumeBool());
(void)block_policy_estimator.HighestTargetTracked(fuzzed_data_provider.PickValueInArray({FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}));
}
{
FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
CAutoFile fuzzed_auto_file = fuzzed_auto_file_provider.open();
block_policy_estimator.Write(fuzzed_auto_file);
block_policy_estimator.Read(fuzzed_auto_file);
}
}

View File

@ -0,0 +1,28 @@
// Copyright (c) 2020 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 <policy/fees.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <cstdint>
#include <vector>
void initialize_policy_estimator_io()
{
static const auto testing_setup = MakeNoLogFileContext<>();
}
FUZZ_TARGET_INIT(policy_estimator_io, initialize_policy_estimator_io)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
CAutoFile fuzzed_auto_file = fuzzed_auto_file_provider.open();
// Re-using block_policy_estimator across runs to avoid costly creation of CBlockPolicyEstimator object.
static CBlockPolicyEstimator block_policy_estimator;
if (block_policy_estimator.Read(fuzzed_auto_file)) {
block_policy_estimator.Write(fuzzed_auto_file);
}
}

View File

@ -44,14 +44,8 @@ const TestingSetup* g_setup;
void initialize_process_message()
{
static TestingSetup setup{
CBaseChainParams::REGTEST,
{
"-nodebuglogfile",
},
};
g_setup = &setup;
static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
g_setup = testing_setup.get();
for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
MineBlock(g_setup->m_node, CScript() << OP_TRUE);
}

View File

@ -15,18 +15,14 @@
#include <validation.h>
#include <validationinterface.h>
namespace {
const TestingSetup* g_setup;
} // namespace
void initialize_process_messages()
{
static TestingSetup setup{
CBaseChainParams::REGTEST,
{
"-nodebuglogfile",
},
};
g_setup = &setup;
static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
g_setup = testing_setup.get();
for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
MineBlock(g_setup->m_node, CScript() << OP_TRUE);
}

View File

@ -20,7 +20,7 @@ extern int g_socks5_recv_timeout;
void initialize_socks5()
{
InitializeFuzzingContext();
static const auto testing_setup = MakeNoLogFileContext<>();
default_socks5_recv_timeout = g_socks5_recv_timeout;
}

View File

@ -172,6 +172,9 @@ FUZZ_TARGET(string)
}
(void)SanitizeString(random_string_1);
(void)SanitizeString(random_string_1, fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 3));
#ifndef WIN32
(void)ShellEscape(random_string_1);
#endif // WIN32
uint16_t port_out;
std::string host_out;
SplitHostPort(random_string_1, port_out, host_out);

View File

@ -0,0 +1,79 @@
// Copyright (c) 2020 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 <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <torcontrol.h>
#include <cstdint>
#include <string>
#include <vector>
class DummyTorControlConnection : public TorControlConnection
{
public:
DummyTorControlConnection() : TorControlConnection{nullptr}
{
}
bool Connect(const std::string&, const ConnectionCB&, const ConnectionCB&)
{
return true;
}
void Disconnect()
{
}
bool Command(const std::string&, const ReplyHandlerCB&)
{
return true;
}
};
void initialize_torcontrol()
{
static const auto testing_setup = MakeNoLogFileContext<>();
}
FUZZ_TARGET_INIT(torcontrol, initialize_torcontrol)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
TorController tor_controller;
while (fuzzed_data_provider.ConsumeBool()) {
TorControlReply tor_control_reply;
CallOneOf(
fuzzed_data_provider,
[&] {
tor_control_reply.code = 250;
},
[&] {
tor_control_reply.code = 510;
},
[&] {
tor_control_reply.code = fuzzed_data_provider.ConsumeIntegral<int>();
});
tor_control_reply.lines = ConsumeRandomLengthStringVector(fuzzed_data_provider);
if (tor_control_reply.lines.empty()) {
break;
}
DummyTorControlConnection dummy_tor_control_connection;
CallOneOf(
fuzzed_data_provider,
[&] {
tor_controller.add_onion_cb(dummy_tor_control_connection, tor_control_reply);
},
[&] {
tor_controller.auth_cb(dummy_tor_control_connection, tor_control_reply);
},
[&] {
tor_controller.authchallenge_cb(dummy_tor_control_connection, tor_control_reply);
},
[&] {
tor_controller.protocolinfo_cb(dummy_tor_control_connection, tor_control_reply);
});
}
}

View File

@ -28,6 +28,7 @@
#include <txmempool.h>
#include <uint256.h>
#include <util/time.h>
#include <util/vector.h>
#include <version.h>
#include <algorithm>
@ -247,6 +248,16 @@ void SetFuzzedErrNo(FuzzedDataProvider& fuzzed_data_provider, const std::array<T
errno = fuzzed_data_provider.PickValueInArray(errnos);
}
/*
* Sets a fuzzed errno in the range [0, 133 (EHWPOISON)]. Can be used from functions emulating
* standard library functions that set errno, or in other contexts where the value of errno
* might be relevant for the execution path that will be taken.
*/
inline void SetFuzzedErrNo(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
errno = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 133);
}
/**
* Returns a byte vector of specified size regardless of the number of remaining bytes available
* from the fuzzer. Pads with zero value bytes if needed to achieve the specified size.
@ -321,9 +332,17 @@ inline std::unique_ptr<CNode> ConsumeNodeAsUniquePtr(FuzzedDataProvider& fdp, co
void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, bool init_version) noexcept;
inline void InitializeFuzzingContext(const std::string& chain_name = CBaseChainParams::REGTEST)
template <class T = const BasicTestingSetup>
std::unique_ptr<T> MakeNoLogFileContext(const std::string& chain_name = CBaseChainParams::REGTEST, const std::vector<const char*>& extra_args = {})
{
static const BasicTestingSetup basic_testing_setup{chain_name, {"-nodebuglogfile"}};
// Prepend default arguments for fuzzing
const std::vector<const char*> arguments = Cat(
{
"-nodebuglogfile",
},
extra_args);
return std::make_unique<T>(chain_name, arguments);
}
class FuzzedFileProvider
@ -338,6 +357,7 @@ public:
FILE* open()
{
SetFuzzedErrNo(m_fuzzed_data_provider);
if (m_fuzzed_data_provider.ConsumeBool()) {
return nullptr;
}
@ -379,6 +399,7 @@ public:
static ssize_t read(void* cookie, char* buf, size_t size)
{
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
if (buf == nullptr || size == 0 || fuzzed_file->m_fuzzed_data_provider.ConsumeBool()) {
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
}
@ -397,6 +418,7 @@ public:
static ssize_t write(void* cookie, const char* buf, size_t size)
{
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
const ssize_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<ssize_t>(0, size);
if (AdditionOverflow(static_cast<ssize_t>(fuzzed_file->m_offset), n)) {
return fuzzed_file->m_fuzzed_data_provider.ConsumeBool() ? 0 : -1;
@ -407,8 +429,9 @@ public:
static int seek(void* cookie, int64_t* offset, int whence)
{
assert(whence == SEEK_SET || whence == SEEK_CUR); // SEEK_END not implemented yet.
assert(whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END);
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
int64_t new_offset = 0;
if (whence == SEEK_SET) {
new_offset = *offset;
@ -417,6 +440,12 @@ public:
return -1;
}
new_offset = fuzzed_file->m_offset + *offset;
} else if (whence == SEEK_END) {
const int64_t n = fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 4096);
if (AdditionOverflow(n, *offset)) {
return -1;
}
new_offset = n + *offset;
}
if (new_offset < 0) {
return -1;
@ -429,6 +458,7 @@ public:
static int close(void* cookie)
{
FuzzedFileProvider* fuzzed_file = (FuzzedFileProvider*)cookie;
SetFuzzedErrNo(fuzzed_file->m_fuzzed_data_provider);
return fuzzed_file->m_fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, 0);
}
};

View File

@ -0,0 +1,34 @@
// Copyright (c) 2020 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 <chainparamsbase.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <test/util/setup_common.h>
#include <txmempool.h>
#include <util/time.h>
#include <validation.h>
#include <cstdint>
#include <vector>
void initialize_validation_load_mempool()
{
static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
}
FUZZ_TARGET_INIT(validation_load_mempool, initialize_validation_load_mempool)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
SetMockTime(ConsumeTime(fuzzed_data_provider));
FuzzedFileProvider fuzzed_file_provider = ConsumeFile(fuzzed_data_provider);
CTxMemPool pool{};
auto fuzzed_fopen = [&](const fs::path&, const char*) {
return fuzzed_file_provider.open();
};
(void)LoadMempool(pool, ::ChainstateActive(), fuzzed_fopen);
(void)DumpMempool(pool, fuzzed_fopen, true);
}

View File

@ -0,0 +1,352 @@
// Copyright (c) 2020-2021 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 <chain.h>
#include <chainparams.h>
#include <consensus/params.h>
#include <primitives/block.h>
#include <util/system.h>
#include <versionbits.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <cstdint>
#include <limits>
#include <memory>
#include <vector>
namespace {
class TestConditionChecker : public AbstractThresholdConditionChecker
{
private:
mutable ThresholdConditionCache m_cache;
const Consensus::Params dummy_params{};
public:
const int64_t m_begin;
const int64_t m_end;
const int m_period;
const int m_threshold;
const int m_bit;
TestConditionChecker(int64_t begin, int64_t end, int period, int threshold, int bit)
: m_begin{begin}, m_end{end}, m_period{period}, m_threshold{threshold}, m_bit{bit}
{
assert(m_period > 0);
assert(0 <= m_threshold && m_threshold <= m_period);
assert(0 <= m_bit && m_bit < 32 && m_bit < VERSIONBITS_NUM_BITS);
}
bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override { return Condition(pindex->nVersion); }
int64_t BeginTime(const Consensus::Params& params) const override { return m_begin; }
int64_t EndTime(const Consensus::Params& params) const override { return m_end; }
int Period(const Consensus::Params& params) const override { return m_period; }
int Threshold(const Consensus::Params& params, int nAttempt) const override { return m_threshold; }
ThresholdState GetStateFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateFor(pindexPrev, dummy_params, m_cache); }
int GetStateSinceHeightFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateSinceHeightFor(pindexPrev, dummy_params, m_cache); }
BIP9Stats GetStateStatisticsFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateStatisticsFor(pindexPrev, dummy_params, m_cache); }
bool Condition(int32_t version) const
{
uint32_t mask = ((uint32_t)1) << m_bit;
return (((version & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (version & mask) != 0);
}
bool Condition(const CBlockIndex* pindex) const { return Condition(pindex->nVersion); }
};
/** Track blocks mined for test */
class Blocks
{
private:
std::vector<std::unique_ptr<CBlockIndex>> m_blocks;
const uint32_t m_start_time;
const uint32_t m_interval;
const int32_t m_signal;
const int32_t m_no_signal;
public:
Blocks(uint32_t start_time, uint32_t interval, int32_t signal, int32_t no_signal)
: m_start_time{start_time}, m_interval{interval}, m_signal{signal}, m_no_signal{no_signal} {}
size_t size() const { return m_blocks.size(); }
CBlockIndex* tip() const
{
return m_blocks.empty() ? nullptr : m_blocks.back().get();
}
CBlockIndex* mine_block(bool signal)
{
CBlockHeader header;
header.nVersion = signal ? m_signal : m_no_signal;
header.nTime = m_start_time + m_blocks.size() * m_interval;
header.nBits = 0x1d00ffff;
auto current_block = std::make_unique<CBlockIndex>(header);
current_block->pprev = tip();
current_block->nHeight = m_blocks.size();
current_block->BuildSkip();
return m_blocks.emplace_back(std::move(current_block)).get();
}
};
std::unique_ptr<const CChainParams> g_params;
void initialize_versionbits()
{
// this is actually comparatively slow, so only do it once
g_params = CreateChainParams(CBaseChainParams::MAIN);
assert(g_params != nullptr);
}
constexpr uint32_t MAX_START_TIME = 4102444800; // 2100-01-01
FUZZ_TARGET_INIT(versionbits, initialize_versionbits)
{
const CChainParams& params = *g_params;
const int64_t interval = params.GetConsensus().nPowTargetSpacing;
assert(interval > 1); // need to be able to halve it
assert(interval < std::numeric_limits<int32_t>::max());
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
// making period/max_periods larger slows these tests down significantly
const int period = 32;
const size_t max_periods = 16;
const size_t max_blocks = 2 * period * max_periods;
const int threshold = fuzzed_data_provider.ConsumeIntegralInRange(1, period);
assert(0 < threshold && threshold <= period); // must be able to both pass and fail threshold!
// too many blocks at 10min each might cause uint32_t time to overflow if
// block_start_time is at the end of the range above
assert(std::numeric_limits<uint32_t>::max() - MAX_START_TIME > interval * max_blocks);
const int64_t block_start_time = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(params.GenesisBlock().nTime, MAX_START_TIME);
// what values for version will we use to signal / not signal?
const int32_t ver_signal = fuzzed_data_provider.ConsumeIntegral<int32_t>();
const int32_t ver_nosignal = fuzzed_data_provider.ConsumeIntegral<int32_t>();
// select deployment parameters: bit, start time, timeout
const int bit = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, VERSIONBITS_NUM_BITS - 1);
bool always_active_test = false;
bool never_active_test = false;
int64_t start_time;
int64_t timeout;
if (fuzzed_data_provider.ConsumeBool()) {
// pick the timestamp to switch based on a block
// note states will change *after* these blocks because mediantime lags
int start_block = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, period * (max_periods - 3));
int end_block = fuzzed_data_provider.ConsumeIntegralInRange<int>(start_block, period * (max_periods - 3));
start_time = block_start_time + start_block * interval;
timeout = block_start_time + end_block * interval;
assert(start_time <= timeout);
// allow for times to not exactly match a block
if (fuzzed_data_provider.ConsumeBool()) start_time += interval / 2;
if (fuzzed_data_provider.ConsumeBool()) timeout += interval / 2;
// this may make timeout too early; if so, don't run the test
if (start_time > timeout) return;
} else {
if (fuzzed_data_provider.ConsumeBool()) {
start_time = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
timeout = Consensus::BIP9Deployment::NO_TIMEOUT;
always_active_test = true;
} else {
start_time = 1199145601; // January 1, 2008
timeout = 1230767999; // December 31, 2008
never_active_test = true;
}
}
TestConditionChecker checker(start_time, timeout, period, threshold, bit);
// Early exit if the versions don't signal sensibly for the deployment
if (!checker.Condition(ver_signal)) return;
if (checker.Condition(ver_nosignal)) return;
if (ver_nosignal < 0) return;
// TOP_BITS should ensure version will be positive and meet min
// version requirement
assert(ver_signal > 0);
assert(ver_signal >= VERSIONBITS_LAST_OLD_BLOCK_VERSION);
// Now that we have chosen time and versions, setup to mine blocks
Blocks blocks(block_start_time, interval, ver_signal, ver_nosignal);
/* Strategy:
* * we will mine a final period worth of blocks, with
* randomised signalling according to a mask
* * but before we mine those blocks, we will mine some
* randomised number of prior periods; with either all
* or no blocks in the period signalling
*
* We establish the mask first, then consume "bools" until
* we run out of fuzz data to work out how many prior periods
* there are and which ones will signal.
*/
// establish the mask
const uint32_t signalling_mask = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
// mine prior periods
while (fuzzed_data_provider.remaining_bytes() > 0) {
// all blocks in these periods either do or don't signal
bool signal = fuzzed_data_provider.ConsumeBool();
for (int b = 0; b < period; ++b) {
blocks.mine_block(signal);
}
// don't risk exceeding max_blocks or times may wrap around
if (blocks.size() + 2 * period > max_blocks) break;
}
// NOTE: fuzzed_data_provider may be fully consumed at this point and should not be used further
// now we mine the final period and check that everything looks sane
// count the number of signalling blocks
int blocks_sig = 0;
// get the info for the first block of the period
CBlockIndex* prev = blocks.tip();
const int exp_since = checker.GetStateSinceHeightFor(prev);
const ThresholdState exp_state = checker.GetStateFor(prev);
BIP9Stats last_stats = checker.GetStateStatisticsFor(prev);
int prev_next_height = (prev == nullptr ? 0 : prev->nHeight + 1);
assert(exp_since <= prev_next_height);
// mine (period-1) blocks and check state
for (int b = 1; b < period; ++b) {
const bool signal = (signalling_mask >> (b % 32)) & 1;
if (signal) ++blocks_sig;
CBlockIndex* current_block = blocks.mine_block(signal);
// verify that signalling attempt was interpreted correctly
assert(checker.Condition(current_block) == signal);
// state and since don't change within the period
const ThresholdState state = checker.GetStateFor(current_block);
const int since = checker.GetStateSinceHeightFor(current_block);
assert(state == exp_state);
assert(since == exp_since);
// GetStateStatistics may crash when state is not STARTED
if (state != ThresholdState::STARTED) continue;
// check that after mining this block stats change as expected
const BIP9Stats stats = checker.GetStateStatisticsFor(current_block);
assert(stats.period == period);
assert(stats.threshold == threshold);
assert(stats.elapsed == b);
assert(stats.count == last_stats.count + (signal ? 1 : 0));
assert(stats.possible == (stats.count + period >= stats.elapsed + threshold));
last_stats = stats;
}
if (exp_state == ThresholdState::STARTED) {
// double check that stats.possible is sane
if (blocks_sig >= threshold - 1) assert(last_stats.possible);
}
// mine the final block
bool signal = (signalling_mask >> (period % 32)) & 1;
if (signal) ++blocks_sig;
CBlockIndex* current_block = blocks.mine_block(signal);
assert(checker.Condition(current_block) == signal);
// GetStateStatistics is safe on a period boundary
// and has progressed to a new period
const BIP9Stats stats = checker.GetStateStatisticsFor(current_block);
assert(stats.period == period);
assert(stats.threshold == threshold);
assert(stats.elapsed == 0);
assert(stats.count == 0);
assert(stats.possible == true);
// More interesting is whether the state changed.
const ThresholdState state = checker.GetStateFor(current_block);
const int since = checker.GetStateSinceHeightFor(current_block);
// since is straightforward:
assert(since % period == 0);
assert(0 <= since && since <= current_block->nHeight + 1);
if (state == exp_state) {
assert(since == exp_since);
} else {
assert(since == current_block->nHeight + 1);
}
// state is where everything interesting is
switch (state) {
case ThresholdState::DEFINED:
assert(since == 0);
assert(exp_state == ThresholdState::DEFINED);
assert(current_block->GetMedianTimePast() < checker.m_begin);
assert(current_block->GetMedianTimePast() < checker.m_end);
break;
case ThresholdState::STARTED:
assert(current_block->GetMedianTimePast() >= checker.m_begin);
assert(current_block->GetMedianTimePast() < checker.m_end);
if (exp_state == ThresholdState::STARTED) {
assert(blocks_sig < threshold);
} else {
assert(exp_state == ThresholdState::DEFINED);
}
break;
case ThresholdState::LOCKED_IN:
assert(exp_state == ThresholdState::STARTED);
assert(current_block->GetMedianTimePast() < checker.m_end);
assert(blocks_sig >= threshold);
break;
case ThresholdState::ACTIVE:
assert(exp_state == ThresholdState::ACTIVE || exp_state == ThresholdState::LOCKED_IN);
break;
case ThresholdState::FAILED:
assert(current_block->GetMedianTimePast() >= checker.m_end);
assert(exp_state != ThresholdState::LOCKED_IN && exp_state != ThresholdState::ACTIVE);
break;
default:
assert(false);
}
if (blocks.size() >= period * max_periods) {
// we chose the timeout (and block times) so that by the time we have this many blocks it's all over
assert(state == ThresholdState::ACTIVE || state == ThresholdState::FAILED);
}
// "always active" has additional restrictions
if (always_active_test) {
assert(state == ThresholdState::ACTIVE);
assert(exp_state == ThresholdState::ACTIVE);
assert(since == 0);
} else {
// except for always active, the initial state is always DEFINED
assert(since > 0 || state == ThresholdState::DEFINED);
assert(exp_since > 0 || exp_state == ThresholdState::DEFINED);
}
// "never active" does too
if (never_active_test) {
assert(state == ThresholdState::FAILED);
assert(since == period);
if (exp_since == 0) {
assert(exp_state == ThresholdState::DEFINED);
} else {
assert(exp_state == ThresholdState::FAILED);
}
}
}
} // namespace

View File

@ -334,7 +334,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
m_node.mempool->clear();
// orphan in *m_node.mempool, template creation fails
// orphan in mempool, template creation fails
hash = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx));
BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
@ -357,7 +357,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
m_node.mempool->clear();
// coinbase in *m_node.mempool, template creation fails
// coinbase in mempool, template creation fails
tx.vin.resize(1);
tx.vin[0].prevout.SetNull();
tx.vin[0].scriptSig = CScript() << OP_0 << OP_1;
@ -369,25 +369,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple"));
m_node.mempool->clear();
// invalid (pre-p2sh) txn in *m_node.mempool, template creation fails
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
tx.vin[0].prevout.n = 0;
tx.vin[0].scriptSig = CScript() << OP_1;
tx.vout[0].nValue = BLOCKSUBSIDY-LOWFEE;
script = CScript() << OP_0;
tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script));
hash = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
tx.vin[0].prevout.hash = hash;
tx.vin[0].scriptSig = CScript() << std::vector<unsigned char>(script.begin(), script.end());
tx.vout[0].nValue -= LOWFEE;
hash = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
// Should throw block-validation-failed
BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("block-validation-failed"));
m_node.mempool->clear();
// double spend txn pair in *m_node.mempool, template creation fails
// double spend txn pair in mempool, template creation fails
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
tx.vin[0].scriptSig = CScript() << OP_1;
tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;
@ -426,6 +408,25 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
// ::ChainActive().SetTip(next);
// }
//BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
// invalid (pre-p2sh) txn in mempool, template creation fails
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
tx.vin[0].prevout.n = 0;
tx.vin[0].scriptSig = CScript() << OP_1;
tx.vout[0].nValue = BLOCKSUBSIDY-LOWFEE;
script = CScript() << OP_0;
tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script));
hash = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
tx.vin[0].prevout.hash = hash;
tx.vin[0].scriptSig = CScript() << std::vector<unsigned char>(script.begin(), script.end());
tx.vout[0].nValue -= LOWFEE;
hash = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
// Should throw block-validation-failed
BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("block-validation-failed"));
m_node.mempool->clear();
// // Delete the dummy blocks again.
// while (::ChainActive().Tip()->nHeight > nHeight) {
// CBlockIndex* del = ::ChainActive().Tip();

View File

@ -32,6 +32,12 @@ public:
int GetStateSinceHeightFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateSinceHeightFor(pindexPrev, paramsDummy, cache); }
};
class TestAlwaysActiveConditionChecker : public TestConditionChecker
{
public:
int64_t BeginTime(const Consensus::Params& params) const override { return Consensus::BIP9Deployment::ALWAYS_ACTIVE; }
};
#define CHECKERS 6
class VersionBitsTester
@ -43,6 +49,8 @@ class VersionBitsTester
// The first one performs all checks, the second only 50%, the third only 25%, etc...
// This is to test whether lack of cached information leads to the same results.
TestConditionChecker checker[CHECKERS];
// Another 6 that assume always active activation
TestAlwaysActiveConditionChecker checker_always[CHECKERS];
// Test counter (to identify failures)
int num;
@ -56,6 +64,7 @@ public:
}
for (unsigned int i = 0; i < CHECKERS; i++) {
checker[i] = TestConditionChecker();
checker_always[i] = TestAlwaysActiveConditionChecker();
}
vpblock.clear();
return *this;
@ -82,6 +91,7 @@ public:
for (int i = 0; i < CHECKERS; i++) {
if (InsecureRandBits(i) == 0) {
BOOST_CHECK_MESSAGE(checker[i].GetStateSinceHeightFor(vpblock.empty() ? nullptr : vpblock.back()) == height, strprintf("Test %i for StateSinceHeight", num));
BOOST_CHECK_MESSAGE(checker_always[i].GetStateSinceHeightFor(vpblock.empty() ? nullptr : vpblock.back()) == 0, strprintf("Test %i for StateSinceHeight (always active)", num));
}
}
num++;
@ -92,6 +102,7 @@ public:
for (int i = 0; i < CHECKERS; i++) {
if (InsecureRandBits(i) == 0) {
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::DEFINED, strprintf("Test %i for DEFINED", num));
BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
}
}
num++;
@ -102,6 +113,7 @@ public:
for (int i = 0; i < CHECKERS; i++) {
if (InsecureRandBits(i) == 0) {
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::STARTED, strprintf("Test %i for STARTED", num));
BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
}
}
num++;
@ -112,6 +124,7 @@ public:
for (int i = 0; i < CHECKERS; i++) {
if (InsecureRandBits(i) == 0) {
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::LOCKED_IN, strprintf("Test %i for LOCKED_IN", num));
BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
}
}
num++;
@ -122,6 +135,7 @@ public:
for (int i = 0; i < CHECKERS; i++) {
if (InsecureRandBits(i) == 0) {
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE", num));
BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
}
}
num++;
@ -132,6 +146,7 @@ public:
for (int i = 0; i < CHECKERS; i++) {
if (InsecureRandBits(i) == 0) {
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::FAILED, strprintf("Test %i for FAILED", num));
BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
}
}
num++;

View File

@ -52,77 +52,6 @@ static const int MAX_LINE_LENGTH = 100000;
/****** Low-level TorControlConnection ********/
/** Reply from Tor, can be single or multi-line */
class TorControlReply
{
public:
TorControlReply() { Clear(); }
int code;
std::vector<std::string> lines;
void Clear()
{
code = 0;
lines.clear();
}
};
/** Low-level handling for Tor control connection.
* Speaks the SMTP-like protocol as defined in torspec/control-spec.txt
*/
class TorControlConnection
{
public:
typedef std::function<void(TorControlConnection&)> ConnectionCB;
typedef std::function<void(TorControlConnection &,const TorControlReply &)> ReplyHandlerCB;
/** Create a new TorControlConnection.
*/
explicit TorControlConnection(struct event_base *base);
~TorControlConnection();
/**
* Connect to a Tor control port.
* tor_control_center is address of the form host:port.
* connected is the handler that is called when connection is successfully established.
* disconnected is a handler that is called when the connection is broken.
* Return true on success.
*/
bool Connect(const std::string& tor_control_center, const ConnectionCB& connected, const ConnectionCB& disconnected);
/**
* Disconnect from Tor control port.
*/
void Disconnect();
/** Send a command, register a handler for the reply.
* A trailing CRLF is automatically added.
* Return true on success.
*/
bool Command(const std::string &cmd, const ReplyHandlerCB& reply_handler);
/** Response handlers for async replies */
boost::signals2::signal<void(TorControlConnection &,const TorControlReply &)> async_handler;
private:
/** Callback when ready for use */
std::function<void(TorControlConnection&)> connected;
/** Callback when connection lost */
std::function<void(TorControlConnection&)> disconnected;
/** Libevent event base */
struct event_base *base;
/** Connection to control socket */
struct bufferevent *b_conn;
/** Message being received */
TorControlReply message;
/** Response handlers */
std::deque<ReplyHandlerCB> reply_handlers;
/** Libevent handlers: internal */
static void readcb(struct bufferevent *bev, void *ctx);
static void eventcb(struct bufferevent *bev, short what, void *ctx);
};
TorControlConnection::TorControlConnection(struct event_base *_base):
base(_base), b_conn(nullptr)
{
@ -366,55 +295,6 @@ std::map<std::string,std::string> ParseTorReplyMapping(const std::string &s)
return mapping;
}
/****** Bitcoin specific TorController implementation ********/
/** Controller that connects to Tor control socket, authenticate, then create
* and maintain an ephemeral onion service.
*/
class TorController
{
public:
TorController(struct event_base* base, const std::string& tor_control_center, const CService& target);
~TorController();
/** Get name of file to store private key in */
fs::path GetPrivateKeyFile();
/** Reconnect, after getting disconnected */
void Reconnect();
private:
struct event_base* base;
const std::string m_tor_control_center;
TorControlConnection conn;
std::string private_key;
std::string service_id;
bool reconnect;
struct event *reconnect_ev;
float reconnect_timeout;
CService service;
const CService m_target;
/** Cookie for SAFECOOKIE auth */
std::vector<uint8_t> cookie;
/** ClientNonce for SAFECOOKIE auth */
std::vector<uint8_t> clientNonce;
/** Callback for ADD_ONION result */
void add_onion_cb(TorControlConnection& conn, const TorControlReply& reply);
/** Callback for AUTHENTICATE result */
void auth_cb(TorControlConnection& conn, const TorControlReply& reply);
/** Callback for AUTHCHALLENGE result */
void authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply);
/** Callback for PROTOCOLINFO result */
void protocolinfo_cb(TorControlConnection& conn, const TorControlReply& reply);
/** Callback after successful connection */
void connected_cb(TorControlConnection& conn);
/** Callback after connection lost or failed connection attempt */
void disconnected_cb(TorControlConnection& conn);
/** Callback for reconnect timer */
static void reconnect_cb(evutil_socket_t fd, short what, void *arg);
};
TorController::TorController(struct event_base* _base, const std::string& tor_control_center, const CService& target):
base(_base),
m_tor_control_center(tor_control_center), conn(base), reconnect(true), reconnect_ev(0),

View File

@ -8,7 +8,19 @@
#ifndef BITCOIN_TORCONTROL_H
#define BITCOIN_TORCONTROL_H
#include <fs.h>
#include <netaddress.h>
#include <boost/signals2/signal.hpp>
#include <event2/bufferevent.h>
#include <event2/event.h>
#include <cstdlib>
#include <deque>
#include <functional>
#include <string>
#include <vector>
class CService;
@ -21,4 +33,128 @@ void StopTorControl();
CService DefaultOnionServiceTarget();
/** Reply from Tor, can be single or multi-line */
class TorControlReply
{
public:
TorControlReply() { Clear(); }
int code;
std::vector<std::string> lines;
void Clear()
{
code = 0;
lines.clear();
}
};
/** Low-level handling for Tor control connection.
* Speaks the SMTP-like protocol as defined in torspec/control-spec.txt
*/
class TorControlConnection
{
public:
typedef std::function<void(TorControlConnection&)> ConnectionCB;
typedef std::function<void(TorControlConnection &,const TorControlReply &)> ReplyHandlerCB;
/** Create a new TorControlConnection.
*/
explicit TorControlConnection(struct event_base *base);
~TorControlConnection();
/**
* Connect to a Tor control port.
* tor_control_center is address of the form host:port.
* connected is the handler that is called when connection is successfully established.
* disconnected is a handler that is called when the connection is broken.
* Return true on success.
*/
bool Connect(const std::string& tor_control_center, const ConnectionCB& connected, const ConnectionCB& disconnected);
/**
* Disconnect from Tor control port.
*/
void Disconnect();
/** Send a command, register a handler for the reply.
* A trailing CRLF is automatically added.
* Return true on success.
*/
bool Command(const std::string &cmd, const ReplyHandlerCB& reply_handler);
/** Response handlers for async replies */
boost::signals2::signal<void(TorControlConnection &,const TorControlReply &)> async_handler;
private:
/** Callback when ready for use */
std::function<void(TorControlConnection&)> connected;
/** Callback when connection lost */
std::function<void(TorControlConnection&)> disconnected;
/** Libevent event base */
struct event_base *base;
/** Connection to control socket */
struct bufferevent *b_conn;
/** Message being received */
TorControlReply message;
/** Response handlers */
std::deque<ReplyHandlerCB> reply_handlers;
/** Libevent handlers: internal */
static void readcb(struct bufferevent *bev, void *ctx);
static void eventcb(struct bufferevent *bev, short what, void *ctx);
};
/****** Bitcoin specific TorController implementation ********/
/** Controller that connects to Tor control socket, authenticate, then create
* and maintain an ephemeral onion service.
*/
class TorController
{
public:
TorController(struct event_base* base, const std::string& tor_control_center, const CService& target);
TorController() : conn{nullptr} {
// Used for testing only.
}
~TorController();
/** Get name of file to store private key in */
fs::path GetPrivateKeyFile();
/** Reconnect, after getting disconnected */
void Reconnect();
private:
struct event_base* base;
const std::string m_tor_control_center;
TorControlConnection conn;
std::string private_key;
std::string service_id;
bool reconnect;
struct event *reconnect_ev = nullptr;
float reconnect_timeout;
CService service;
const CService m_target;
/** Cookie for SAFECOOKIE auth */
std::vector<uint8_t> cookie;
/** ClientNonce for SAFECOOKIE auth */
std::vector<uint8_t> clientNonce;
public:
/** Callback for ADD_ONION result */
void add_onion_cb(TorControlConnection& conn, const TorControlReply& reply);
/** Callback for AUTHENTICATE result */
void auth_cb(TorControlConnection& conn, const TorControlReply& reply);
/** Callback for AUTHCHALLENGE result */
void authchallenge_cb(TorControlConnection& conn, const TorControlReply& reply);
/** Callback for PROTOCOLINFO result */
void protocolinfo_cb(TorControlConnection& conn, const TorControlReply& reply);
/** Callback after successful connection */
void connected_cb(TorControlConnection& conn);
/** Callback after connection lost or failed connection attempt */
void disconnected_cb(TorControlConnection& conn);
/** Callback for reconnect timer */
static void reconnect_cb(evutil_socket_t fd, short what, void *arg);
};
#endif /* BITCOIN_TORCONTROL_H */

View File

@ -1966,11 +1966,12 @@ static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS] GUARDED_BY(cs_
static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& consensusparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
AssertLockHeld(cs_main);
// BIP16 didn't become active until Apr 1 2012
int64_t nBIP16SwitchTime = 1333238400;
bool fStrictPayToScriptHash = (pindex->GetBlockTime() >= nBIP16SwitchTime);
unsigned int flags = SCRIPT_VERIFY_NONE;
unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE;
// Start enforcing P2SH (BIP16)
if (pindex->nHeight >= consensusparams.BIP16Height) {
flags |= SCRIPT_VERIFY_P2SH;
}
// Start enforcing the DERSIG (BIP66) rule
if (pindex->nHeight >= consensusparams.BIP66Height) {
@ -5507,11 +5508,11 @@ CBlockFileInfo* GetBlockFileInfo(size_t n)
static const uint64_t MEMPOOL_DUMP_VERSION = 1;
bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate)
bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate, FopenFn mockable_fopen_function)
{
const CChainParams& chainparams = Params();
int64_t nExpiryTimeout = gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60;
FILE* filestr = fsbridge::fopen(GetDataDir() / "mempool.dat", "rb");
FILE* filestr{mockable_fopen_function(GetDataDir() / "mempool.dat", "rb")};
CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
if (file.IsNull()) {
LogPrintf("Failed to open mempool file from disk. Continuing anyway.\n");
@ -5601,7 +5602,7 @@ bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate)
return true;
}
bool DumpMempool(const CTxMemPool& pool)
bool DumpMempool(const CTxMemPool& pool, FopenFn mockable_fopen_function, bool skip_file_commit)
{
int64_t start = GetTimeMicros();
@ -5624,7 +5625,7 @@ bool DumpMempool(const CTxMemPool& pool)
int64_t mid = GetTimeMicros();
try {
FILE* filestr = fsbridge::fopen(GetDataDir() / "mempool.dat.new", "wb");
FILE* filestr{mockable_fopen_function(GetDataDir() / "mempool.dat.new", "wb")};
if (!filestr) {
return false;
}
@ -5647,7 +5648,7 @@ bool DumpMempool(const CTxMemPool& pool)
LogPrintf("Writing %d unbroadcast transactions to disk.\n", unbroadcast_txids.size());
file << unbroadcast_txids;
if (!FileCommit(file.Get()))
if (!skip_file_commit && !FileCommit(file.Get()))
throw std::runtime_error("FileCommit failed");
file.fclose();
if (!RenameOver(GetDataDir() / "mempool.dat.new", GetDataDir() / "mempool.dat")) {

View File

@ -1087,11 +1087,13 @@ bool GetBlockHash(uint256& hashRet, int nBlockHeight = -1);
/** Get block file info entry for one block file */
CBlockFileInfo* GetBlockFileInfo(size_t n);
using FopenFn = std::function<FILE*(const fs::path&, const char*)>;
/** Dump the mempool to disk. */
bool DumpMempool(const CTxMemPool& pool);
bool DumpMempool(const CTxMemPool& pool, FopenFn mockable_fopen_function = fsbridge::fopen, bool skip_file_commit = false);
/** Load the mempool from disk. */
bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate);
bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate, FopenFn mockable_fopen_function = fsbridge::fopen);
//! Check whether the block associated with this index entry is pruned or not.
inline bool IsBlockPruned(const CBlockIndex* pblockindex)

View File

@ -11,6 +11,11 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex*
int64_t nTimeStart = BeginTime(params);
int64_t nTimeTimeout = EndTime(params);
// Check if this deployment is always active.
if (nTimeStart == Consensus::BIP9Deployment::ALWAYS_ACTIVE) {
return ThresholdState::ACTIVE;
}
// A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1.
if (pindexPrev != nullptr) {
pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));
@ -161,6 +166,11 @@ BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockI
int AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
{
int64_t start_time = BeginTime(params);
if (start_time == Consensus::BIP9Deployment::ALWAYS_ACTIVE) {
return 0;
}
const ThresholdState initialState = GetStateFor(pindexPrev, params, cache);
// BIP 9 about state DEFINED: "The genesis block is by definition in this state for each deployment."

View File

@ -145,7 +145,7 @@ class BlockchainTest(BitcoinTestFramework):
'bip9': {
'status': 'defined',
'start_time': 0,
'timeout': 999999999999,
'timeout': 9223372036854775807,
'since': 0
}, 'active': False},
'mn_rr': {
@ -153,7 +153,7 @@ class BlockchainTest(BitcoinTestFramework):
'bip9': {
'status': 'defined',
'start_time': 0,
'timeout': 999999999999,
'timeout': 9223372036854775807,
'since': 0
},
'active': False},
@ -163,7 +163,7 @@ class BlockchainTest(BitcoinTestFramework):
'status': 'started',
'bit': 28,
'start_time': 0,
'timeout': 999999999999, # testdummy does not have a timeout so is set to the max int64 value
'timeout': 9223372036854775807, # testdummy does not have a timeout so is set to the max int64 value
'since': 144,
'statistics': {
'period': 144,