bitcoin/src/test/fuzz/util.h

150 lines
5.5 KiB
C
Raw Normal View History

// Copyright (c) 2009-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.
#ifndef BITCOIN_TEST_FUZZ_UTIL_H
#define BITCOIN_TEST_FUZZ_UTIL_H
#include <amount.h>
#include <arith_uint256.h>
#include <attributes.h>
#include <consensus/consensus.h>
#include <optional.h>
#include <primitives/transaction.h>
#include <script/script.h>
#include <serialize.h>
#include <streams.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <txmempool.h>
#include <uint256.h>
#include <version.h>
#include <cstdint>
#include <string>
#include <vector>
NODISCARD inline std::vector<uint8_t> ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
{
const std::string s = fuzzed_data_provider.ConsumeRandomLengthString(max_length);
return {s.begin(), s.end()};
}
NODISCARD inline std::vector<std::string> ConsumeRandomLengthStringVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16, const size_t max_string_length = 16) noexcept
{
const size_t n_elements = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_vector_size);
std::vector<std::string> r;
for (size_t i = 0; i < n_elements; ++i) {
r.push_back(fuzzed_data_provider.ConsumeRandomLengthString(max_string_length));
}
return r;
}
template <typename T>
NODISCARD inline std::vector<T> ConsumeRandomLengthIntegralVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_vector_size = 16) noexcept
{
const size_t n_elements = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, max_vector_size);
std::vector<T> r;
for (size_t i = 0; i < n_elements; ++i) {
r.push_back(fuzzed_data_provider.ConsumeIntegral<T>());
}
return r;
}
template <typename T>
NODISCARD inline Optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
{
const std::vector<uint8_t> buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length);
CDataStream ds{buffer, SER_NETWORK, INIT_PROTO_VERSION};
T obj;
try {
ds >> obj;
} catch (const std::ios_base::failure&) {
return nullopt;
}
return obj;
}
NODISCARD inline opcodetype ConsumeOpcodeType(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
return static_cast<opcodetype>(fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, MAX_OPCODE));
}
NODISCARD inline CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
return fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, MAX_MONEY);
}
NODISCARD inline CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
return {b.begin(), b.end()};
}
NODISCARD inline CScriptNum ConsumeScriptNum(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
return CScriptNum{fuzzed_data_provider.ConsumeIntegral<int64_t>()};
}
NODISCARD inline uint256 ConsumeUInt256(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
const std::vector<unsigned char> v256 = fuzzed_data_provider.ConsumeBytes<unsigned char>(sizeof(uint256));
if (v256.size() != sizeof(uint256)) {
return {};
}
return uint256{v256};
}
NODISCARD inline arith_uint256 ConsumeArithUInt256(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
return UintToArith256(ConsumeUInt256(fuzzed_data_provider));
}
NODISCARD inline CTxMemPoolEntry ConsumeTxMemPoolEntry(FuzzedDataProvider& fuzzed_data_provider, const CTransaction& tx) noexcept
{
// Avoid:
// policy/feerate.cpp:28:34: runtime error: signed integer overflow: 34873208148477500 * 1000 cannot be represented in type 'long'
const CAmount fee = ConsumeMoney(fuzzed_data_provider) / static_cast<CAmount>(100);
const int64_t time = fuzzed_data_provider.ConsumeIntegral<int64_t>();
const unsigned int entry_height = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
const bool spends_coinbase = fuzzed_data_provider.ConsumeBool();
const unsigned int sig_op_cost = fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(0, MAX_BLOCK_SIGOPS_COST);
return CTxMemPoolEntry{MakeTransactionRef(tx), fee, time, entry_height, spends_coinbase, sig_op_cost, {}};
}
template <typename T>
NODISCARD bool MultiplicationOverflow(const T i, const T j) noexcept
{
static_assert(std::is_integral<T>::value, "Integral required.");
if (std::numeric_limits<T>::is_signed) {
if (i > 0) {
if (j > 0) {
return i > (std::numeric_limits<T>::max() / j);
} else {
return j < (std::numeric_limits<T>::min() / i);
}
} else {
if (j > 0) {
return i < (std::numeric_limits<T>::min() / j);
} else {
return i != 0 && (j < (std::numeric_limits<T>::max() / i));
}
}
} else {
return j != 0 && i > std::numeric_limits<T>::max() / j;
}
}
template <class T>
NODISCARD bool AdditionOverflow(const T i, const T j) noexcept
{
static_assert(std::is_integral<T>::value, "Integral required.");
if (std::numeric_limits<T>::is_signed) {
return (i > 0 && j > std::numeric_limits<T>::max() - i) ||
(i < 0 && j < std::numeric_limits<T>::min() - i);
}
return std::numeric_limits<T>::max() - i < j;
}
#endif // BITCOIN_TEST_FUZZ_UTIL_H