diff --git a/src/net.h b/src/net.h --- a/src/net.h +++ b/src/net.h @@ -529,6 +529,7 @@ std::atomic m_next_send_inv_to_incoming{0}; friend struct ::CConnmanTest; + friend struct ConnmanTestMsg; }; void Discover(); @@ -781,6 +782,7 @@ /** Information about a peer */ class CNode { friend class CConnman; + friend struct ConnmanTestMsg; public: std::unique_ptr m_deserializer; diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -48,6 +48,7 @@ util/blockfilter.cpp util/logging.cpp util/mining.cpp + util/net.cpp util/setup_common.cpp util/str.cpp util/transaction_utils.cpp diff --git a/src/test/fuzz/CMakeLists.txt b/src/test/fuzz/CMakeLists.txt --- a/src/test/fuzz/CMakeLists.txt +++ b/src/test/fuzz/CMakeLists.txt @@ -99,6 +99,7 @@ parse_script parse_univalue process_message + process_messages psbt script script_flags diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp new file mode 100644 --- /dev/null +++ b/src/test/fuzz/process_messages.cpp @@ -0,0 +1,87 @@ +// 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +const RegTestingSetup *g_setup; + +void initialize() { + static RegTestingSetup setup{}; + g_setup = &setup; + + for (int i = 0; i < 2 * COINBASE_MATURITY; i++) { + MineBlock(GetConfig(), g_setup->m_node, CScript() << OP_TRUE); + } + SyncWithValidationInterfaceQueue(); +} + +void test_one_input(const std::vector &buffer) { + const Config &config = GetConfig(); + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + + ConnmanTestMsg &connman = *(ConnmanTestMsg *)g_setup->m_node.connman.get(); + std::vector peers; + + const auto num_peers_to_add = + fuzzed_data_provider.ConsumeIntegralInRange(1, 3); + for (int i = 0; i < num_peers_to_add; ++i) { + const ServiceFlags service_flags = + ServiceFlags(fuzzed_data_provider.ConsumeIntegral()); + const bool inbound{fuzzed_data_provider.ConsumeBool()}; + const bool block_relay_only{fuzzed_data_provider.ConsumeBool()}; + peers.push_back( + std::make_unique( + i, service_flags, 0, INVALID_SOCKET, + CAddress{CService{in_addr{0x0100007f}, 7777}, NODE_NETWORK}, 0, + 0, CAddress{}, std::string{}, inbound, block_relay_only) + .release()); + CNode &p2p_node = *peers.back(); + + p2p_node.fSuccessfullyConnected = true; + p2p_node.fPauseSend = false; + p2p_node.nVersion = PROTOCOL_VERSION; + p2p_node.SetSendVersion(PROTOCOL_VERSION); + g_setup->m_node.peer_logic->InitializeNode(config, &p2p_node); + + connman.AddTestNode(p2p_node); + } + + while (fuzzed_data_provider.ConsumeBool()) { + const std::string random_message_type{ + fuzzed_data_provider + .ConsumeBytesAsString(CMessageHeader::COMMAND_SIZE) + .c_str()}; + + CSerializedNetMsg net_msg; + net_msg.m_type = random_message_type; + net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider); + + CNode &random_node = + *peers.at(fuzzed_data_provider.ConsumeIntegralInRange( + 0, peers.size() - 1)); + + (void)connman.ReceiveMsgFrom(random_node, net_msg); + random_node.fPauseSend = false; + + try { + connman.ProcessMessagesOnce(random_node); + } catch (const std::ios_base::failure &) { + } + } + connman.ClearTestNodes(); + SyncWithValidationInterfaceQueue(); +} diff --git a/src/test/util/net.h b/src/test/util/net.h new file mode 100644 --- /dev/null +++ b/src/test/util/net.h @@ -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. + +#ifndef BITCOIN_TEST_UTIL_NET_H +#define BITCOIN_TEST_UTIL_NET_H + +#include + +struct ConnmanTestMsg : public CConnman { + using CConnman::CConnman; + void AddTestNode(CNode &node) { + LOCK(cs_vNodes); + vNodes.push_back(&node); + } + void ClearTestNodes() { + LOCK(cs_vNodes); + for (CNode *node : vNodes) { + delete node; + } + vNodes.clear(); + } + + void ProcessMessagesOnce(CNode &node) { + m_msgproc->ProcessMessages(*config, &node, flagInterruptMsgProc); + } + + void NodeReceiveMsgBytes(CNode &node, const char *pch, unsigned int nBytes, + bool &complete) const; + + bool ReceiveMsgFrom(CNode &node, CSerializedNetMsg &ser_msg) const; +}; + +#endif // BITCOIN_TEST_UTIL_NET_H diff --git a/src/test/util/net.cpp b/src/test/util/net.cpp new file mode 100644 --- /dev/null +++ b/src/test/util/net.cpp @@ -0,0 +1,45 @@ +// 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 + +#include +#include +#include + +void ConnmanTestMsg::NodeReceiveMsgBytes(CNode &node, const char *pch, + unsigned int nBytes, + bool &complete) const { + assert(node.ReceiveMsgBytes(*config, pch, nBytes, complete)); + if (complete) { + size_t nSizeAdded = 0; + auto it(node.vRecvMsg.begin()); + for (; it != node.vRecvMsg.end(); ++it) { + // vRecvMsg contains only completed CNetMessage + // the single possible partially deserialized message are held by + // TransportDeserializer + nSizeAdded += it->m_raw_message_size; + } + { + LOCK(node.cs_vProcessMsg); + node.vProcessMsg.splice(node.vProcessMsg.end(), node.vRecvMsg, + node.vRecvMsg.begin(), it); + node.nProcessQueueSize += nSizeAdded; + node.fPauseRecv = node.nProcessQueueSize > nReceiveFloodSize; + } + } +} + +bool ConnmanTestMsg::ReceiveMsgFrom(CNode &node, + CSerializedNetMsg &ser_msg) const { + std::vector ser_msg_header; + node.m_serializer->prepareForTransport(*config, ser_msg, ser_msg_header); + + bool complete; + NodeReceiveMsgBytes(node, (const char *)ser_msg_header.data(), + ser_msg_header.size(), complete); + NodeReceiveMsgBytes(node, (const char *)ser_msg.data.data(), + ser_msg.data.size(), complete); + return complete; +} diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -181,6 +181,11 @@ m_node.peer_logic = std::make_unique( m_node.connman.get(), m_node.banman.get(), *m_node.scheduler, *m_node.chainman); + { + CConnman::Options options; + options.m_msgproc = m_node.peer_logic.get(); + m_node.connman->Init(options); + } } TestingSetup::~TestingSetup() {