/ src / test / fuzz / process_messages.cpp
process_messages.cpp
  1  // Copyright (c) 2020-present The Bitcoin Core developers
  2  // Distributed under the MIT software license, see the accompanying
  3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  4  
  5  #include <banman.h>
  6  #include <consensus/consensus.h>
  7  #include <net.h>
  8  #include <net_processing.h>
  9  #include <node/warnings.h>
 10  #include <protocol.h>
 11  #include <script/script.h>
 12  #include <sync.h>
 13  #include <test/fuzz/FuzzedDataProvider.h>
 14  #include <test/fuzz/fuzz.h>
 15  #include <test/fuzz/util.h>
 16  #include <test/fuzz/util/net.h>
 17  #include <test/util/mining.h>
 18  #include <test/util/net.h>
 19  #include <test/util/setup_common.h>
 20  #include <test/util/validation.h>
 21  #include <util/time.h>
 22  #include <validationinterface.h>
 23  
 24  #include <ios>
 25  #include <string>
 26  #include <utility>
 27  #include <vector>
 28  
 29  namespace {
 30  TestingSetup* g_setup;
 31  
 32  void ResetChainman(TestingSetup& setup)
 33  {
 34      SetMockTime(setup.m_node.chainman->GetParams().GenesisBlock().Time());
 35      setup.m_node.chainman.reset();
 36      setup.m_make_chainman();
 37      setup.LoadVerifyActivateChainstate();
 38      node::BlockAssembler::Options options;
 39      options.include_dummy_extranonce = true;
 40      for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
 41          MineBlock(setup.m_node, options);
 42      }
 43  }
 44  } // namespace
 45  
 46  void initialize_process_messages()
 47  {
 48      static const auto testing_setup{
 49          MakeNoLogFileContext<TestingSetup>(
 50              /*chain_type=*/ChainType::REGTEST,
 51              {}),
 52      };
 53      g_setup = testing_setup.get();
 54      ResetChainman(*g_setup);
 55  }
 56  
 57  FUZZ_TARGET(process_messages, .init = initialize_process_messages)
 58  {
 59      SeedRandomStateForTest(SeedRand::ZEROS);
 60      FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
 61  
 62      auto& node{g_setup->m_node};
 63      auto& connman{static_cast<ConnmanTestMsg&>(*node.connman)};
 64      connman.Reset();
 65      auto& chainman{static_cast<TestChainstateManager&>(*node.chainman)};
 66      const auto block_index_size{WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())};
 67      SetMockTime(1610000000); // any time to successfully reset ibd
 68      chainman.ResetIbd();
 69      chainman.DisableNextWrite();
 70  
 71      // Reset, so that dangling pointers can be detected by sanitizers.
 72      node.banman.reset();
 73      node.addrman.reset();
 74      node.peerman.reset();
 75      node.addrman = std::make_unique<AddrMan>(*node.netgroupman, /*deterministic=*/true, /*consistency_check_ratio=*/0);
 76      node.peerman = PeerManager::make(connman, *node.addrman,
 77                                       /*banman=*/nullptr, chainman,
 78                                       *node.mempool, *node.warnings,
 79                                       PeerManager::Options{
 80                                           .reconcile_txs = true,
 81                                           .deterministic_rng = true,
 82                                       });
 83      connman.SetMsgProc(node.peerman.get());
 84      connman.SetAddrman(*node.addrman);
 85  
 86      node.validation_signals->RegisterValidationInterface(node.peerman.get());
 87  
 88      LOCK(NetEventsInterface::g_msgproc_mutex);
 89  
 90      std::vector<CNode*> peers;
 91      const auto num_peers_to_add = fuzzed_data_provider.ConsumeIntegralInRange(1, 3);
 92      for (int i = 0; i < num_peers_to_add; ++i) {
 93          peers.push_back(ConsumeNodeAsUniquePtr(fuzzed_data_provider, i).release());
 94          CNode& p2p_node = *peers.back();
 95  
 96          FillNode(fuzzed_data_provider, connman, p2p_node);
 97  
 98          connman.AddTestNode(p2p_node);
 99      }
100  
101      LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 30)
102      {
103          const std::string random_message_type{fuzzed_data_provider.ConsumeBytesAsString(CMessageHeader::MESSAGE_TYPE_SIZE).c_str()};
104  
105          const auto mock_time = ConsumeTime(fuzzed_data_provider);
106          SetMockTime(mock_time);
107  
108          CSerializedNetMsg net_msg;
109          net_msg.m_type = random_message_type;
110          net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider, MAX_PROTOCOL_MESSAGE_LENGTH);
111  
112          CNode& random_node = *PickValue(fuzzed_data_provider, peers);
113  
114          connman.FlushSendBuffer(random_node);
115          (void)connman.ReceiveMsgFrom(random_node, std::move(net_msg));
116  
117          bool more_work{true};
118          while (more_work) { // Ensure that every message is eventually processed in some way or another
119              random_node.fPauseSend = false;
120  
121              try {
122                  more_work = connman.ProcessMessagesOnce(random_node);
123              } catch (const std::ios_base::failure&) {
124              }
125              node.peerman->SendMessages(random_node);
126          }
127      }
128      node.validation_signals->SyncWithValidationInterfaceQueue();
129      node.validation_signals->UnregisterValidationInterface(node.peerman.get());
130      node.connman->StopNodes();
131      if (block_index_size != WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())) {
132          // Reuse the global chainman, but reset it when it is dirty
133          ResetChainman(*g_setup);
134      }
135  }