diff --git a/src/net.h b/src/net.h
index 7f7f51823..95a89453a 100644
--- a/src/net.h
+++ b/src/net.h
@@ -1,1081 +1,1083 @@
 // Copyright (c) 2009-2010 Satoshi Nakamoto
 // Copyright (c) 2009-2019 The Bitcoin Core developers
 // Copyright (c) 2017-2019 The Bitcoin developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #ifndef BITCOIN_NET_H
 #define BITCOIN_NET_H
 
 #include <addrdb.h>
 #include <addrman.h>
 #include <amount.h>
 #include <bloom.h>
 #include <chainparams.h>
 #include <compat.h>
 #include <crypto/siphash.h>
 #include <hash.h>
 #include <limitedmap.h>
 #include <net_permissions.h>
 #include <netaddress.h>
 #include <protocol.h>
 #include <random.h>
 #include <streams.h>
 #include <sync.h>
 #include <threadinterrupt.h>
 #include <uint256.h>
 
 #include <atomic>
 #include <condition_variable>
 #include <cstdint>
 #include <deque>
 #include <memory>
 #include <thread>
 
 #ifndef WIN32
 #include <arpa/inet.h>
 #endif
 
 class BanMan;
 class Config;
 class CNode;
 class CScheduler;
 struct bilingual_str;
 
 /** Default for -whitelistrelay. */
 static const bool DEFAULT_WHITELISTRELAY = true;
 /** Default for -whitelistforcerelay. */
 static const bool DEFAULT_WHITELISTFORCERELAY = false;
 
 /**
  * Time between pings automatically sent out for latency probing and keepalive
  * (in seconds).
  */
 static const int PING_INTERVAL = 2 * 60;
 /**
  * Time after which to disconnect, after waiting for a ping response (or
  * inactivity).
  */
 static const int TIMEOUT_INTERVAL = 20 * 60;
 /** Run the feeler connection loop once every 2 minutes or 120 seconds. **/
 static const int FEELER_INTERVAL = 120;
 /** The maximum number of entries in an 'inv' protocol message */
 static const unsigned int MAX_INV_SZ = 50000;
 static_assert(MAX_PROTOCOL_MESSAGE_LENGTH > MAX_INV_SZ * sizeof(CInv),
               "Max protocol message length must be greater than largest "
               "possible INV message");
 /** The maximum number of entries in a locator */
 static const unsigned int MAX_LOCATOR_SZ = 101;
 /** The maximum number of new addresses to accumulate before announcing. */
 static const unsigned int MAX_ADDR_TO_SEND = 1000;
 /** Maximum length of the user agent string in `version` message */
 static const unsigned int MAX_SUBVERSION_LENGTH = 256;
 /**
  * Maximum number of automatic outgoing nodes over which we'll relay everything
  * (blocks, tx, addrs, etc)
  */
 static const int MAX_OUTBOUND_FULL_RELAY_CONNECTIONS = 8;
 /** Maximum number of addnode outgoing nodes */
 static const int MAX_ADDNODE_CONNECTIONS = 8;
 /** Maximum number of block-relay-only outgoing connections */
 static const int MAX_BLOCKS_ONLY_CONNECTIONS = 2;
 /** -listen default */
 static const bool DEFAULT_LISTEN = true;
 /** -upnp default */
 #ifdef USE_UPNP
 static const bool DEFAULT_UPNP = USE_UPNP;
 #else
 static const bool DEFAULT_UPNP = false;
 #endif
 /** The maximum number of peer connections to maintain. */
 static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125;
 /** The default for -maxuploadtarget. 0 = Unlimited */
 static const uint64_t DEFAULT_MAX_UPLOAD_TARGET = 0;
 /** The default timeframe for -maxuploadtarget. 1 day. */
 static const uint64_t MAX_UPLOAD_TIMEFRAME = 60 * 60 * 24;
 /** Default for blocks only*/
 static const bool DEFAULT_BLOCKSONLY = false;
 /** -peertimeout default */
 static const int64_t DEFAULT_PEER_CONNECT_TIMEOUT = 60;
 
 static const bool DEFAULT_FORCEDNSSEED = false;
 static const size_t DEFAULT_MAXRECEIVEBUFFER = 5 * 1000;
 static const size_t DEFAULT_MAXSENDBUFFER = 1 * 1000;
 
 typedef int64_t NodeId;
 
 /**
  * Special NodeId that represent no node.
  */
 static constexpr NodeId NO_NODE = -1;
 
 struct AddedNodeInfo {
     std::string strAddedNode;
     CService resolvedAddress;
     bool fConnected;
     bool fInbound;
 };
 
 struct CNodeStats;
 class CClientUIInterface;
 
 struct CSerializedNetMsg {
     CSerializedNetMsg() = default;
     CSerializedNetMsg(CSerializedNetMsg &&) = default;
     CSerializedNetMsg &operator=(CSerializedNetMsg &&) = default;
     // No copying, only moves.
     CSerializedNetMsg(const CSerializedNetMsg &msg) = delete;
     CSerializedNetMsg &operator=(const CSerializedNetMsg &) = delete;
 
     std::vector<uint8_t> data;
     std::string command;
 };
 
 namespace {
 struct CConnmanTest;
 }
 
 class NetEventsInterface;
 class CConnman {
 public:
     enum NumConnections {
         CONNECTIONS_NONE = 0,
         CONNECTIONS_IN = (1U << 0),
         CONNECTIONS_OUT = (1U << 1),
         CONNECTIONS_ALL = (CONNECTIONS_IN | CONNECTIONS_OUT),
     };
 
     struct Options {
         ServiceFlags nLocalServices = NODE_NONE;
         int nMaxConnections = 0;
         int m_max_outbound_full_relay = 0;
         int m_max_outbound_block_relay = 0;
         int nMaxAddnode = 0;
         int nMaxFeeler = 0;
         int nBestHeight = 0;
         CClientUIInterface *uiInterface = nullptr;
         NetEventsInterface *m_msgproc = nullptr;
         BanMan *m_banman = nullptr;
         unsigned int nSendBufferMaxSize = 0;
         unsigned int nReceiveFloodSize = 0;
         uint64_t nMaxOutboundTimeframe = 0;
         uint64_t nMaxOutboundLimit = 0;
         int64_t m_peer_connect_timeout = DEFAULT_PEER_CONNECT_TIMEOUT;
         std::vector<std::string> vSeedNodes;
         std::vector<NetWhitelistPermissions> vWhitelistedRange;
         std::vector<NetWhitebindPermissions> vWhiteBinds;
         std::vector<CService> vBinds;
         bool m_use_addrman_outgoing = true;
         std::vector<std::string> m_specified_outgoing;
         std::vector<std::string> m_added_nodes;
         std::vector<bool> m_asmap;
     };
 
     void Init(const Options &connOptions) {
         nLocalServices = connOptions.nLocalServices;
         nMaxConnections = connOptions.nMaxConnections;
         m_max_outbound_full_relay = std::min(
             connOptions.m_max_outbound_full_relay, connOptions.nMaxConnections);
         m_max_outbound_block_relay = connOptions.m_max_outbound_block_relay;
         m_use_addrman_outgoing = connOptions.m_use_addrman_outgoing;
         nMaxAddnode = connOptions.nMaxAddnode;
         nMaxFeeler = connOptions.nMaxFeeler;
         m_max_outbound =
             m_max_outbound_full_relay + m_max_outbound_block_relay + nMaxFeeler;
         nBestHeight = connOptions.nBestHeight;
         clientInterface = connOptions.uiInterface;
         m_banman = connOptions.m_banman;
         m_msgproc = connOptions.m_msgproc;
         nSendBufferMaxSize = connOptions.nSendBufferMaxSize;
         nReceiveFloodSize = connOptions.nReceiveFloodSize;
         m_peer_connect_timeout = connOptions.m_peer_connect_timeout;
         {
             LOCK(cs_totalBytesSent);
             nMaxOutboundTimeframe = connOptions.nMaxOutboundTimeframe;
             nMaxOutboundLimit = connOptions.nMaxOutboundLimit;
         }
         vWhitelistedRange = connOptions.vWhitelistedRange;
         {
             LOCK(cs_vAddedNodes);
             vAddedNodes = connOptions.m_added_nodes;
         }
     }
 
     CConnman(const Config &configIn, uint64_t seed0, uint64_t seed1);
     ~CConnman();
 
     bool Start(CScheduler &scheduler, const Options &options);
 
     // TODO: Remove NO_THREAD_SAFETY_ANALYSIS. Lock cs_vNodes before reading the
     // variable vNodes.
     //
     // When removing NO_THREAD_SAFETY_ANALYSIS be aware of the following lock
     // order requirements:
     // * CheckForStaleTipAndEvictPeers locks cs_main before indirectly calling
     //   GetExtraOutboundCount which locks cs_vNodes.
     // * ProcessMessage locks cs_main and g_cs_orphans before indirectly calling
     //   ForEachNode which locks cs_vNodes.
     //
     // Thus the implicit locking order requirement is: (1) cs_main, (2)
     // g_cs_orphans, (3) cs_vNodes.
     void Stop() NO_THREAD_SAFETY_ANALYSIS;
 
     void Interrupt();
     bool GetNetworkActive() const { return fNetworkActive; };
     bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; };
     void SetNetworkActive(bool active);
     void OpenNetworkConnection(const CAddress &addrConnect, bool fCountFailure,
                                CSemaphoreGrant *grantOutbound = nullptr,
                                const char *strDest = nullptr,
                                bool fOneShot = false, bool fFeeler = false,
                                bool manual_connection = false,
                                bool block_relay_only = false);
     bool CheckIncomingNonce(uint64_t nonce);
 
     bool ForNode(NodeId id, std::function<bool(CNode *pnode)> func);
 
     void PushMessage(CNode *pnode, CSerializedNetMsg &&msg);
 
     template <typename Callable> void ForEachNode(Callable &&func) {
         LOCK(cs_vNodes);
         for (auto &&node : vNodes) {
             if (NodeFullyConnected(node)) {
                 func(node);
             }
         }
     };
 
     template <typename Callable> void ForEachNode(Callable &&func) const {
         LOCK(cs_vNodes);
         for (auto &&node : vNodes) {
             if (NodeFullyConnected(node)) {
                 func(node);
             }
         }
     };
 
     template <typename Callable, typename CallableAfter>
     void ForEachNodeThen(Callable &&pre, CallableAfter &&post) {
         LOCK(cs_vNodes);
         for (auto &&node : vNodes) {
             if (NodeFullyConnected(node)) {
                 pre(node);
             }
         }
         post();
     };
 
     template <typename Callable, typename CallableAfter>
     void ForEachNodeThen(Callable &&pre, CallableAfter &&post) const {
         LOCK(cs_vNodes);
         for (auto &&node : vNodes) {
             if (NodeFullyConnected(node)) {
                 pre(node);
             }
         }
         post();
     };
 
     // Addrman functions
     size_t GetAddressCount() const;
     void SetServices(const CService &addr, ServiceFlags nServices);
     void MarkAddressGood(const CAddress &addr);
     void AddNewAddresses(const std::vector<CAddress> &vAddr,
                          const CAddress &addrFrom, int64_t nTimePenalty = 0);
     std::vector<CAddress> GetAddresses();
 
     // This allows temporarily exceeding m_max_outbound_full_relay, with the
     // goal of finding a peer that is better than all our current peers.
     void SetTryNewOutboundPeer(bool flag);
     bool GetTryNewOutboundPeer();
 
     // Return the number of outbound peers we have in excess of our target (eg,
     // if we previously called SetTryNewOutboundPeer(true), and have since set
     // to false, we may have extra peers that we wish to disconnect). This may
     // return a value less than (num_outbound_connections - num_outbound_slots)
     // in cases where some outbound connections are not yet fully connected, or
     // not yet fully disconnected.
     int GetExtraOutboundCount();
 
     bool AddNode(const std::string &node);
     bool RemoveAddedNode(const std::string &node);
     std::vector<AddedNodeInfo> GetAddedNodeInfo();
 
     size_t GetNodeCount(NumConnections num);
     void GetNodeStats(std::vector<CNodeStats> &vstats);
     bool DisconnectNode(const std::string &node);
     bool DisconnectNode(const CSubNet &subnet);
     bool DisconnectNode(const CNetAddr &addr);
     bool DisconnectNode(NodeId id);
 
     //! Used to convey which local services we are offering peers during node
     //! connection.
     //!
     //! The data returned by this is used in CNode construction,
     //! which is used to advertise which services we are offering
     //! that peer during `net_processing.cpp:PushNodeVersion()`.
     ServiceFlags GetLocalServices() const;
 
     //! set the max outbound target in bytes.
     void SetMaxOutboundTarget(uint64_t limit);
     uint64_t GetMaxOutboundTarget();
 
     //! set the timeframe for the max outbound target.
     void SetMaxOutboundTimeframe(uint64_t timeframe);
     uint64_t GetMaxOutboundTimeframe();
 
     //! check if the outbound target is reached. If param
     //! historicalBlockServingLimit is set true, the function will response true
     //! if the limit for serving historical blocks has been reached.
     bool OutboundTargetReached(bool historicalBlockServingLimit);
 
     //! response the bytes left in the current max outbound cycle in case of no
     //! limit, it will always response 0
     uint64_t GetOutboundTargetBytesLeft();
 
     //! response the time in second left in the current max outbound cycle in
     //! case of no limit, it will always response 0
     uint64_t GetMaxOutboundTimeLeftInCycle();
 
     uint64_t GetTotalBytesRecv();
     uint64_t GetTotalBytesSent();
 
     void SetBestHeight(int height);
     int GetBestHeight() const;
 
     /** Get a unique deterministic randomizer. */
     CSipHasher GetDeterministicRandomizer(uint64_t id) const;
 
     unsigned int GetReceiveFloodSize() const;
 
     void WakeMessageHandler();
 
     /**
      * Attempts to obfuscate tx time through exponentially distributed emitting.
      * Works assuming that a single interval is used.
      * Variable intervals will result in privacy decrease.
      */
     int64_t PoissonNextSendInbound(int64_t now, int average_interval_seconds);
 
     void SetAsmap(std::vector<bool> asmap) {
         addrman.m_asmap = std::move(asmap);
     }
 
 private:
     struct ListenSocket {
     public:
         SOCKET socket;
         inline void AddSocketPermissionFlags(NetPermissionFlags &flags) const {
             NetPermissions::AddFlag(flags, m_permissions);
         }
         ListenSocket(SOCKET socket_, NetPermissionFlags permissions_)
             : socket(socket_), m_permissions(permissions_) {}
 
     private:
         NetPermissionFlags m_permissions;
     };
 
     bool BindListenPort(const CService &bindAddr, bilingual_str &strError,
                         NetPermissionFlags permissions);
     bool Bind(const CService &addr, unsigned int flags,
               NetPermissionFlags permissions);
     bool InitBinds(const std::vector<CService> &binds,
                    const std::vector<NetWhitebindPermissions> &whiteBinds);
     void ThreadOpenAddedConnections();
     void AddOneShot(const std::string &strDest);
     void ProcessOneShot();
     void ThreadOpenConnections(std::vector<std::string> connect);
     void ThreadMessageHandler();
     void AcceptConnection(const ListenSocket &hListenSocket);
     void DisconnectNodes();
     void NotifyNumConnectionsChanged();
     void InactivityCheck(CNode *pnode);
     bool GenerateSelectSet(std::set<SOCKET> &recv_set,
                            std::set<SOCKET> &send_set,
                            std::set<SOCKET> &error_set);
     void SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set,
                       std::set<SOCKET> &error_set);
     void SocketHandler();
     void ThreadSocketHandler();
     void ThreadDNSAddressSeed();
 
     uint64_t CalculateKeyedNetGroup(const CAddress &ad) const;
 
     CNode *FindNode(const CNetAddr &ip);
     CNode *FindNode(const CSubNet &subNet);
     CNode *FindNode(const std::string &addrName);
     CNode *FindNode(const CService &addr);
 
     bool AttemptToEvictConnection();
     CNode *ConnectNode(CAddress addrConnect, const char *pszDest,
                        bool fCountFailure, bool manual_connection,
                        bool block_relay_only);
     void AddWhitelistPermissionFlags(NetPermissionFlags &flags,
                                      const CNetAddr &addr) const;
 
     void DeleteNode(CNode *pnode);
 
     NodeId GetNewNodeId();
 
     size_t SocketSendData(CNode *pnode) const;
     void DumpAddresses();
 
     // Network stats
     void RecordBytesRecv(uint64_t bytes);
     void RecordBytesSent(uint64_t bytes);
 
     // Whether the node should be passed out in ForEach* callbacks
     static bool NodeFullyConnected(const CNode *pnode);
 
     const Config *config;
 
     // Network usage totals
     RecursiveMutex cs_totalBytesRecv;
     RecursiveMutex cs_totalBytesSent;
     uint64_t nTotalBytesRecv GUARDED_BY(cs_totalBytesRecv);
     uint64_t nTotalBytesSent GUARDED_BY(cs_totalBytesSent);
 
     // outbound limit & stats
     uint64_t nMaxOutboundTotalBytesSentInCycle GUARDED_BY(cs_totalBytesSent);
     uint64_t nMaxOutboundCycleStartTime GUARDED_BY(cs_totalBytesSent);
     uint64_t nMaxOutboundLimit GUARDED_BY(cs_totalBytesSent);
     uint64_t nMaxOutboundTimeframe GUARDED_BY(cs_totalBytesSent);
 
     // P2P timeout in seconds
     int64_t m_peer_connect_timeout;
 
     // Whitelisted ranges. Any node connecting from these is automatically
     // whitelisted (as well as those connecting to whitelisted binds).
     std::vector<NetWhitelistPermissions> vWhitelistedRange;
 
     unsigned int nSendBufferMaxSize{0};
     unsigned int nReceiveFloodSize{0};
 
     std::vector<ListenSocket> vhListenSocket;
     std::atomic<bool> fNetworkActive{true};
     bool fAddressesInitialized{false};
     CAddrMan addrman;
     std::deque<std::string> vOneShots GUARDED_BY(cs_vOneShots);
     RecursiveMutex cs_vOneShots;
     std::vector<std::string> vAddedNodes GUARDED_BY(cs_vAddedNodes);
     RecursiveMutex cs_vAddedNodes;
     std::vector<CNode *> vNodes GUARDED_BY(cs_vNodes);
     std::list<CNode *> vNodesDisconnected;
     mutable RecursiveMutex cs_vNodes;
     std::atomic<NodeId> nLastNodeId{0};
     unsigned int nPrevNodeCount{0};
 
     /**
      * Services this instance offers.
      *
      * This data is replicated in each CNode instance we create during peer
      * connection (in ConnectNode()) under a member also called
      * nLocalServices.
      *
      * This data is not marked const, but after being set it should not
      * change. See the note in CNode::nLocalServices documentation.
      *
      * \sa CNode::nLocalServices
      */
     ServiceFlags nLocalServices;
 
     std::unique_ptr<CSemaphore> semOutbound;
     std::unique_ptr<CSemaphore> semAddnode;
     int nMaxConnections;
 
     // How many full-relay (tx, block, addr) outbound peers we want
     int m_max_outbound_full_relay;
 
     // How many block-relay only outbound peers we want
     // We do not relay tx or addr messages with these peers
     int m_max_outbound_block_relay;
 
     int nMaxAddnode;
     int nMaxFeeler;
     int m_max_outbound;
     bool m_use_addrman_outgoing;
     std::atomic<int> nBestHeight;
     CClientUIInterface *clientInterface;
     NetEventsInterface *m_msgproc;
     BanMan *m_banman;
 
     /** SipHasher seeds for deterministic randomness */
     const uint64_t nSeed0, nSeed1;
 
     /** flag for waking the message processor. */
     bool fMsgProcWake GUARDED_BY(mutexMsgProc);
 
     std::condition_variable condMsgProc;
     Mutex mutexMsgProc;
     std::atomic<bool> flagInterruptMsgProc{false};
 
     CThreadInterrupt interruptNet;
 
     std::thread threadDNSAddressSeed;
     std::thread threadSocketHandler;
     std::thread threadOpenAddedConnections;
     std::thread threadOpenConnections;
     std::thread threadMessageHandler;
 
     /**
      * flag for deciding to connect to an extra outbound peer, in excess of
      * m_max_outbound_full_relay. This takes the place of a feeler connection.
      */
     std::atomic_bool m_try_another_outbound_peer;
 
     std::atomic<int64_t> m_next_send_inv_to_incoming{0};
 
     friend struct ::CConnmanTest;
+    friend struct ConnmanTestMsg;
 };
 
 void Discover();
 void StartMapPort();
 void InterruptMapPort();
 void StopMapPort();
 unsigned short GetListenPort();
 
 /**
  * Interface for message handling
  */
 class NetEventsInterface {
 public:
     virtual bool ProcessMessages(const Config &config, CNode *pnode,
                                  std::atomic<bool> &interrupt) = 0;
     virtual bool SendMessages(const Config &config, CNode *pnode,
                               std::atomic<bool> &interrupt) = 0;
     virtual void InitializeNode(const Config &config, CNode *pnode) = 0;
     virtual void FinalizeNode(const Config &config, NodeId id,
                               bool &update_connection_time) = 0;
 
 protected:
     /**
      * Protected destructor so that instances can only be deleted by derived
      * classes. If that restriction is no longer desired, this should be made
      * public and virtual.
      */
     ~NetEventsInterface() = default;
 };
 
 enum {
     // unknown
     LOCAL_NONE,
     // address a local interface listens on
     LOCAL_IF,
     // address explicit bound to
     LOCAL_BIND,
     // address reported by UPnP
     LOCAL_UPNP,
     // address explicitly specified (-externalip=)
     LOCAL_MANUAL,
 
     LOCAL_MAX
 };
 
 bool IsPeerAddrLocalGood(CNode *pnode);
 void AdvertiseLocal(CNode *pnode);
 
 /**
  * Mark a network as reachable or unreachable (no automatic connects to it)
  * @note Networks are reachable by default
  */
 void SetReachable(enum Network net, bool reachable);
 /** @returns true if the network is reachable, false otherwise */
 bool IsReachable(enum Network net);
 /** @returns true if the address is in a reachable network, false otherwise */
 bool IsReachable(const CNetAddr &addr);
 
 bool AddLocal(const CService &addr, int nScore = LOCAL_NONE);
 bool AddLocal(const CNetAddr &addr, int nScore = LOCAL_NONE);
 void RemoveLocal(const CService &addr);
 bool SeenLocal(const CService &addr);
 bool IsLocal(const CService &addr);
 bool GetLocal(CService &addr, const CNetAddr *paddrPeer = nullptr);
 CAddress GetLocalAddress(const CNetAddr *paddrPeer,
                          ServiceFlags nLocalServices);
 
 extern bool fDiscover;
 extern bool fListen;
 extern bool g_relay_txes;
 
 struct LocalServiceInfo {
     int nScore;
     int nPort;
 };
 
 extern RecursiveMutex cs_mapLocalHost;
 extern std::map<CNetAddr, LocalServiceInfo>
     mapLocalHost GUARDED_BY(cs_mapLocalHost);
 
 extern const std::string NET_MESSAGE_COMMAND_OTHER;
 // Command, total bytes
 typedef std::map<std::string, uint64_t> mapMsgCmdSize;
 
 /**
  * POD that contains various stats about a node.
  * Usually constructed from CConman::GetNodeStats. Stats are filled from the
  * node using CNode::copyStats.
  */
 struct CNodeStats {
     NodeId nodeid;
     ServiceFlags nServices;
     bool fRelayTxes;
     int64_t nLastSend;
     int64_t nLastRecv;
     int64_t nTimeConnected;
     int64_t nTimeOffset;
     std::string addrName;
     int nVersion;
     std::string cleanSubVer;
     bool fInbound;
     bool m_manual_connection;
     int nStartingHeight;
     uint64_t nSendBytes;
     mapMsgCmdSize mapSendBytesPerMsgCmd;
     uint64_t nRecvBytes;
     mapMsgCmdSize mapRecvBytesPerMsgCmd;
     NetPermissionFlags m_permissionFlags;
     bool m_legacyWhitelisted;
     int64_t m_ping_usec;
     int64_t m_ping_wait_usec;
     int64_t m_min_ping_usec;
     Amount minFeeFilter;
     // Our address, as reported by the peer
     std::string addrLocal;
     // Address of this peer
     CAddress addr;
     // Bind address of our side of the connection
     CAddress addrBind;
     uint32_t m_mapped_as;
 };
 
 /**
  * Transport protocol agnostic message container.
  * Ideally it should only contain receive time, payload,
  * command and size.
  */
 class CNetMessage {
 public:
     // received message data
     CDataStream m_recv;
     // time (in microseconds) of message receipt.
     int64_t m_time = 0;
     bool m_valid_netmagic = false;
     bool m_valid_header = false;
     bool m_valid_checksum = false;
     // size of the payload
     uint32_t m_message_size = 0;
     // used wire size of the message (including header/checksum)
     uint32_t m_raw_message_size = 0;
     std::string m_command;
 
     CNetMessage(CDataStream &&recv_in) : m_recv(std::move(recv_in)) {}
 
     void SetVersion(int nVersionIn) { m_recv.SetVersion(nVersionIn); }
 };
 
 /**
  * The TransportDeserializer takes care of holding and deserializing the
  * network receive buffer. It can deserialize the network buffer into a
  * transport protocol agnostic CNetMessage (command & payload)
  */
 class TransportDeserializer {
 public:
     // returns true if the current deserialization is complete
     virtual bool Complete() const = 0;
     // set the serialization context version
     virtual void SetVersion(int version) = 0;
     // read and deserialize data
     virtual int Read(const Config &config, const char *data,
                      uint32_t bytes) = 0;
     // decomposes a message from the context
     virtual CNetMessage GetMessage(const Config &config, int64_t time) = 0;
     virtual ~TransportDeserializer() {}
 };
 
 class V1TransportDeserializer final : public TransportDeserializer {
 private:
     mutable CHash256 hasher;
     mutable uint256 data_hash;
 
     // Parsing header (false) or data (true)
     bool in_data;
     // Partially received header.
     CDataStream hdrbuf;
     // Complete header.
     CMessageHeader hdr;
     // Received message data.
     CDataStream vRecv;
     uint32_t nHdrPos;
     uint32_t nDataPos;
 
     const uint256 &GetMessageHash() const;
     int readHeader(const Config &config, const char *pch, uint32_t nBytes);
     int readData(const char *pch, uint32_t nBytes);
 
     void Reset() {
         vRecv.clear();
         hdrbuf.clear();
         hdrbuf.resize(24);
         in_data = false;
         nHdrPos = 0;
         nDataPos = 0;
         data_hash.SetNull();
         hasher.Reset();
     }
 
 public:
     V1TransportDeserializer(
         const CMessageHeader::MessageMagic &pchMessageStartIn, int nTypeIn,
         int nVersionIn)
         : hdrbuf(nTypeIn, nVersionIn), hdr(pchMessageStartIn),
           vRecv(nTypeIn, nVersionIn) {
         Reset();
     }
 
     bool Complete() const override {
         if (!in_data) {
             return false;
         }
 
         return (hdr.nMessageSize == nDataPos);
     }
 
     void SetVersion(int nVersionIn) override {
         hdrbuf.SetVersion(nVersionIn);
         vRecv.SetVersion(nVersionIn);
     }
     int Read(const Config &config, const char *pch, uint32_t nBytes) override {
         int ret =
             in_data ? readData(pch, nBytes) : readHeader(config, pch, nBytes);
         if (ret < 0) {
             Reset();
         }
         return ret;
     }
 
     CNetMessage GetMessage(const Config &config, int64_t time) override;
 };
 
 /**
  * The TransportSerializer prepares messages for the network transport
  */
 class TransportSerializer {
 public:
     // prepare message for transport (header construction, error-correction
     // computation, payload encryption, etc.)
     virtual void prepareForTransport(const Config &config,
                                      CSerializedNetMsg &msg,
                                      std::vector<uint8_t> &header) = 0;
     virtual ~TransportSerializer() {}
 };
 
 class V1TransportSerializer : public TransportSerializer {
 public:
     void prepareForTransport(const Config &config, CSerializedNetMsg &msg,
                              std::vector<uint8_t> &header) override;
 };
 
 /** Information about a peer */
 class CNode {
     friend class CConnman;
+    friend struct ConnmanTestMsg;
 
 public:
     std::unique_ptr<TransportDeserializer> m_deserializer;
     std::unique_ptr<TransportSerializer> m_serializer;
 
     // socket
     std::atomic<ServiceFlags> nServices{NODE_NONE};
     SOCKET hSocket GUARDED_BY(cs_hSocket);
     // Total size of all vSendMsg entries.
     size_t nSendSize{0};
     // Offset inside the first vSendMsg already sent.
     size_t nSendOffset{0};
     uint64_t nSendBytes GUARDED_BY(cs_vSend){0};
     std::deque<std::vector<uint8_t>> vSendMsg GUARDED_BY(cs_vSend);
     RecursiveMutex cs_vSend;
     RecursiveMutex cs_hSocket;
     RecursiveMutex cs_vRecv;
 
     RecursiveMutex cs_vProcessMsg;
     std::list<CNetMessage> vProcessMsg GUARDED_BY(cs_vProcessMsg);
     size_t nProcessQueueSize{0};
 
     RecursiveMutex cs_sendProcessing;
 
     std::deque<CInv> vRecvGetData;
     uint64_t nRecvBytes GUARDED_BY(cs_vRecv){0};
     std::atomic<int> nRecvVersion{INIT_PROTO_VERSION};
 
     std::atomic<int64_t> nLastSend{0};
     std::atomic<int64_t> nLastRecv{0};
     const int64_t nTimeConnected;
     std::atomic<int64_t> nTimeOffset{0};
     // Address of this peer
     const CAddress addr;
     // Bind address of our side of the connection
     const CAddress addrBind;
     std::atomic<int> nVersion{0};
     RecursiveMutex cs_SubVer;
     /**
      * cleanSubVer is a sanitized string of the user agent byte array we read
      * from the wire. This cleaned string can safely be logged or displayed.
      */
     std::string cleanSubVer GUARDED_BY(cs_SubVer){};
     // This peer is preferred for eviction.
     bool m_prefer_evict{false};
     bool HasPermission(NetPermissionFlags permission) const {
         return NetPermissions::HasFlag(m_permissionFlags, permission);
     }
     // This boolean is unusued in actual processing, only present for backward
     // compatibility at RPC/QT level
     bool m_legacyWhitelisted{false};
     // If true this node is being used as a short lived feeler.
     bool fFeeler{false};
     bool fOneShot{false};
     bool m_manual_connection{false};
     // set by version message
     bool fClient{false};
     // after BIP159, set by version message
     bool m_limited_node{false};
     const bool fInbound;
     std::atomic_bool fSuccessfullyConnected{false};
     // Setting fDisconnect to true will cause the node to be disconnected the
     // next time DisconnectNodes() runs
     std::atomic_bool fDisconnect{false};
     bool fSentAddr{false};
     CSemaphoreGrant grantOutbound;
     std::atomic<int> nRefCount{0};
 
     const uint64_t nKeyedNetGroup;
     std::atomic_bool fPauseRecv{false};
     std::atomic_bool fPauseSend{false};
 
 protected:
     mapMsgCmdSize mapSendBytesPerMsgCmd;
     mapMsgCmdSize mapRecvBytesPerMsgCmd GUARDED_BY(cs_vRecv);
 
 public:
     BlockHash hashContinue;
     std::atomic<int> nStartingHeight{-1};
 
     // flood relay
     std::vector<CAddress> vAddrToSend;
     const std::unique_ptr<CRollingBloomFilter> m_addr_known;
     bool fGetAddr{false};
     int64_t nNextAddrSend GUARDED_BY(cs_sendProcessing){0};
     int64_t nNextLocalAddrSend GUARDED_BY(cs_sendProcessing){0};
 
     bool IsAddrRelayPeer() const { return m_addr_known != nullptr; }
 
     // List of block ids we still have to announce.
     // There is no final sorting before sending, as they are always sent
     // immediately and in the order requested.
     std::vector<BlockHash> vInventoryBlockToSend GUARDED_BY(cs_inventory);
     RecursiveMutex cs_inventory;
 
     struct TxRelay {
         TxRelay() { pfilter = std::make_unique<CBloomFilter>(); }
         mutable RecursiveMutex cs_filter;
         // We use fRelayTxes for two purposes -
         // a) it allows us to not relay tx invs before receiving the peer's
         //    version message.
         // b) the peer may tell us in its version message that we should not
         //    relay tx invs unless it loads a bloom filter.
         bool fRelayTxes GUARDED_BY(cs_filter){false};
         std::unique_ptr<CBloomFilter> pfilter PT_GUARDED_BY(cs_filter)
             GUARDED_BY(cs_filter);
 
         mutable RecursiveMutex cs_tx_inventory;
         CRollingBloomFilter filterInventoryKnown GUARDED_BY(cs_tx_inventory){
             50000, 0.000001};
         // Set of transaction ids we still have to announce.
         // They are sorted by the mempool before relay, so the order is not
         // important.
         std::set<TxId> setInventoryTxToSend;
         // Used for BIP35 mempool sending
         bool fSendMempool GUARDED_BY(cs_tx_inventory){false};
         // Last time a "MEMPOOL" request was serviced.
         std::atomic<std::chrono::seconds> m_last_mempool_req{
             std::chrono::seconds{0}};
         std::chrono::microseconds nNextInvSend{0};
 
         RecursiveMutex cs_feeFilter;
         // Minimum fee rate with which to filter inv's to this node
         Amount minFeeFilter GUARDED_BY(cs_feeFilter){Amount::zero()};
         Amount lastSentFeeFilter{Amount::zero()};
         int64_t nextSendTimeFeeFilter{0};
     };
 
     // m_tx_relay == nullptr if we're not relaying transactions with this peer
     std::unique_ptr<TxRelay> m_tx_relay;
 
     // Used for headers announcements - unfiltered blocks to relay
     std::vector<BlockHash> vBlockHashesToAnnounce GUARDED_BY(cs_inventory);
 
     // Block and TXN accept times
     std::atomic<int64_t> nLastBlockTime{0};
     std::atomic<int64_t> nLastTXTime{0};
 
     // Ping time measurement:
     // The pong reply we're expecting, or 0 if no pong expected.
     std::atomic<uint64_t> nPingNonceSent{0};
     // Time (in usec) the last ping was sent, or 0 if no ping was ever sent.
     std::atomic<int64_t> nPingUsecStart{0};
     // Last measured round-trip time.
     std::atomic<int64_t> nPingUsecTime{0};
     // Best measured round-trip time.
     std::atomic<int64_t> nMinPingUsecTime{std::numeric_limits<int64_t>::max()};
     // Whether a ping is requested.
     std::atomic<bool> fPingQueued{false};
 
     std::set<TxId> orphan_work_set;
 
     CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn,
           SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn,
           uint64_t nLocalHostNonceIn, const CAddress &addrBindIn,
           const std::string &addrNameIn = "", bool fInboundIn = false,
           bool block_relay_only = false);
     ~CNode();
     CNode(const CNode &) = delete;
     CNode &operator=(const CNode &) = delete;
 
 private:
     const NodeId id;
     const uint64_t nLocalHostNonce;
 
     //! Services offered to this peer.
     //!
     //! This is supplied by the parent CConnman during peer connection
     //! (CConnman::ConnectNode()) from its attribute of the same name.
     //!
     //! This is const because there is no protocol defined for renegotiating
     //! services initially offered to a peer. The set of local services we
     //! offer should not change after initialization.
     //!
     //! An interesting example of this is NODE_NETWORK and initial block
     //! download: a node which starts up from scratch doesn't have any blocks
     //! to serve, but still advertises NODE_NETWORK because it will eventually
     //! fulfill this role after IBD completes. P2P code is written in such a
     //! way that it can gracefully handle peers who don't make good on their
     //! service advertisements.
     const ServiceFlags nLocalServices;
 
     const int nMyStartingHeight;
     int nSendVersion{0};
     NetPermissionFlags m_permissionFlags{PF_NONE};
     // Used only by SocketHandler thread
     std::list<CNetMessage> vRecvMsg;
 
     mutable RecursiveMutex cs_addrName;
     std::string addrName GUARDED_BY(cs_addrName);
 
     // Our address, as reported by the peer
     CService addrLocal GUARDED_BY(cs_addrLocal);
     mutable RecursiveMutex cs_addrLocal;
 
 public:
     NodeId GetId() const { return id; }
 
     uint64_t GetLocalNonce() const { return nLocalHostNonce; }
 
     int GetMyStartingHeight() const { return nMyStartingHeight; }
 
     int GetRefCount() const {
         assert(nRefCount >= 0);
         return nRefCount;
     }
 
     bool ReceiveMsgBytes(const Config &config, const char *pch, uint32_t nBytes,
                          bool &complete);
 
     void SetRecvVersion(int nVersionIn) { nRecvVersion = nVersionIn; }
     int GetRecvVersion() const { return nRecvVersion; }
     void SetSendVersion(int nVersionIn);
     int GetSendVersion() const;
 
     CService GetAddrLocal() const;
     //! May not be called more than once
     void SetAddrLocal(const CService &addrLocalIn);
 
     CNode *AddRef() {
         nRefCount++;
         return this;
     }
 
     void Release() { nRefCount--; }
 
     void AddAddressKnown(const CAddress &_addr) {
         assert(m_addr_known);
         m_addr_known->insert(_addr.GetKey());
     }
 
     void PushAddress(const CAddress &_addr, FastRandomContext &insecure_rand) {
         // Known checking here is only to save space from duplicates.
         // SendMessages will filter it again for knowns that were added
         // after addresses were pushed.
         assert(m_addr_known);
         if (_addr.IsValid() && !m_addr_known->contains(_addr.GetKey())) {
             if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) {
                 vAddrToSend[insecure_rand.randrange(vAddrToSend.size())] =
                     _addr;
             } else {
                 vAddrToSend.push_back(_addr);
             }
         }
     }
 
     void AddInventoryKnown(const CInv &inv) {
         if (m_tx_relay != nullptr) {
             LOCK(m_tx_relay->cs_tx_inventory);
             m_tx_relay->filterInventoryKnown.insert(inv.hash);
         }
     }
 
     void PushInventory(const CInv &inv) {
         if (inv.type == MSG_TX && m_tx_relay != nullptr) {
             const TxId txid(inv.hash);
             LOCK(m_tx_relay->cs_tx_inventory);
             if (!m_tx_relay->filterInventoryKnown.contains(txid)) {
                 m_tx_relay->setInventoryTxToSend.insert(txid);
             }
         } else if (inv.type == MSG_BLOCK) {
             const BlockHash hash(inv.hash);
             LOCK(cs_inventory);
             vInventoryBlockToSend.push_back(hash);
         }
     }
 
     void PushBlockHash(const BlockHash &hash) {
         LOCK(cs_inventory);
         vBlockHashesToAnnounce.push_back(hash);
     }
 
     void CloseSocketDisconnect();
 
     void copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap);
 
     ServiceFlags GetLocalServices() const { return nLocalServices; }
 
     std::string GetAddrName() const;
     //! Sets the addrName only if it was not previously set
     void MaybeSetAddrName(const std::string &addrNameIn);
 };
 
 /**
  * Return a timestamp in the future (in microseconds) for exponentially
  * distributed events.
  */
 int64_t PoissonNextSend(int64_t now, int average_interval_seconds);
 
 /** Wrapper to return mockable type */
 inline std::chrono::microseconds
 PoissonNextSend(std::chrono::microseconds now,
                 std::chrono::seconds average_interval) {
     return std::chrono::microseconds{
         PoissonNextSend(now.count(), average_interval.count())};
 }
 
 std::string getSubVersionEB(uint64_t MaxBlockSize);
 std::string userAgent(const Config &config);
 
 #endif // BITCOIN_NET_H
diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt
index 73b9b1dd2..723873377 100644
--- a/src/test/CMakeLists.txt
+++ b/src/test/CMakeLists.txt
@@ -1,278 +1,279 @@
 # Copyright (c) 2018 The Bitcoin developers
 
 project(bitcoin-test)
 
 # Process json files.
 file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/data")
 
 function(gen_json_header NAME)
 	set(HEADERS "")
 	foreach(f ${ARGN})
 		set(h "${CMAKE_CURRENT_BINARY_DIR}/${f}.h")
 
 		# Get the proper name for the test variable.
 		get_filename_component(TEST_NAME ${f} NAME_WE)
 		add_custom_command(OUTPUT ${h}
 			COMMAND
 				"${Python_EXECUTABLE}"
 				"${CMAKE_CURRENT_SOURCE_DIR}/data/generate_header.py"
 				"${TEST_NAME}"
 				"${CMAKE_CURRENT_SOURCE_DIR}/${f}" > ${h}
 			MAIN_DEPENDENCY ${f}
 			DEPENDS
 				"data/generate_header.py"
 			VERBATIM
 		)
 		list(APPEND HEADERS ${h})
 	endforeach(f)
 	set(${NAME} "${HEADERS}" PARENT_SCOPE)
 endfunction()
 
 gen_json_header(JSON_HEADERS
 	data/base58_encode_decode.json
 	data/blockfilters.json
 	data/key_io_valid.json
 	data/key_io_invalid.json
 	data/script_tests.json
 	data/sighash.json
 	data/tx_invalid.json
 	data/tx_valid.json
 )
 
 include(TestSuite)
 create_test_suite(bitcoin)
 add_dependencies(check check-bitcoin)
 
 # An utility library for bitcoin related test suites.
 add_library(testutil OBJECT
 	util/blockfilter.cpp
 	util/logging.cpp
 	util/mining.cpp
+	util/net.cpp
 	util/setup_common.cpp
 	util/str.cpp
 	util/transaction_utils.cpp
 	util/wallet.cpp
 )
 
 target_link_libraries(testutil server)
 
 if(BUILD_BITCOIN_WALLET)
 	set(BITCOIN_WALLET_TEST_FIXTURE
 		../wallet/test/init_test_fixture.cpp
 		../wallet/test/wallet_test_fixture.cpp
 	)
 	set(BITCOIN_WALLET_TESTS
 		../wallet/test/db_tests.cpp
 		../wallet/test/coinselector_tests.cpp
 		../wallet/test/init_tests.cpp
 		../wallet/test/ismine_tests.cpp
 		../wallet/test/psbt_wallet_tests.cpp
 		../wallet/test/wallet_tests.cpp
 		../wallet/test/walletdb_tests.cpp
 		../wallet/test/wallet_crypto_tests.cpp
 	)
 endif()
 
 function(gen_asmap_headers HEADERS_VAR)
 	foreach(INPUT_FILE ${ARGN})
 		set(OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/${INPUT_FILE}.h")
 
 		add_custom_command(
 			OUTPUT "${OUTPUT_FILE}"
 			COMMENT "Generate ASMAP header from ${INPUT_FILE}"
 			COMMAND
 				"${Python_EXECUTABLE}"
 				"${CMAKE_CURRENT_SOURCE_DIR}/data/generate_asmap.py"
 				"${CMAKE_CURRENT_SOURCE_DIR}/${INPUT_FILE}"
 				"${OUTPUT_FILE}"
 			MAIN_DEPENDENCY "${INPUT_FILE}"
 			DEPENDS
 				"data/generate_header.py"
 			VERBATIM
 		)
 		list(APPEND ${HEADERS_VAR} "${OUTPUT_FILE}")
 	endforeach()
 	set(${HEADERS_VAR} ${${HEADERS_VAR}} PARENT_SCOPE)
 endfunction()
 
 gen_asmap_headers(ASMAP_HEADERS
 	data/asmap.raw
 )
 
 add_boost_unit_tests_to_suite(bitcoin test_bitcoin
 	fixture.cpp
 	jsonutil.cpp
 	scriptflags.cpp
 	sigutil.cpp
 
 	${ASMAP_HEADERS}
 
 	# Tests generated from JSON
 	${JSON_HEADERS}
 
 	# Wallet test fixture
 	${BITCOIN_WALLET_TEST_FIXTURE}
 
 	TESTS
 		activation_tests.cpp
 		addrman_tests.cpp
 		allocator_tests.cpp
 		amount_tests.cpp
 		arith_uint256_tests.cpp
 		base32_tests.cpp
 		base58_tests.cpp
 		base64_tests.cpp
 		bip32_tests.cpp
 		bitmanip_tests.cpp
 		blockchain_tests.cpp
 		blockcheck_tests.cpp
 		blockencodings_tests.cpp
 		blockfilter_tests.cpp
 		blockfilter_index_tests.cpp
 		blockindex_tests.cpp
 		blockstatus_tests.cpp
 		bloom_tests.cpp
 		bswap_tests.cpp
 		cashaddr_tests.cpp
 		cashaddrenc_tests.cpp
 		checkdatasig_tests.cpp
 		checkpoints_tests.cpp
 		checkqueue_tests.cpp
 		coins_tests.cpp
 		compilerbug_tests.cpp
 		compress_tests.cpp
 		config_tests.cpp
 		core_io_tests.cpp
 		crypto_tests.cpp
 		cuckoocache_tests.cpp
 		dbwrapper_tests.cpp
 		denialofservice_tests.cpp
 		descriptor_tests.cpp
 		dstencode_tests.cpp
 		excessiveblock_tests.cpp
 		feerate_tests.cpp
 		finalization_tests.cpp
 		flatfile_tests.cpp
 		fs_tests.cpp
 		getarg_tests.cpp
 		hash_tests.cpp
 		interfaces_tests.cpp
 		inv_tests.cpp
 		key_io_tests.cpp
 		key_tests.cpp
 		lcg_tests.cpp
 		limitedmap_tests.cpp
 		mempool_tests.cpp
 		merkle_tests.cpp
 		merkleblock_tests.cpp
 		miner_tests.cpp
 		monolith_opcodes_tests.cpp
 		multisig_tests.cpp
 		net_tests.cpp
 		netbase_tests.cpp
 		op_reversebytes_tests.cpp
 		pmt_tests.cpp
 		policyestimator_tests.cpp
 		prevector_tests.cpp
 		radix_tests.cpp
 		raii_event_tests.cpp
 		random_tests.cpp
 		rcu_tests.cpp
 		ref_tests.cpp
 		reverselock_tests.cpp
 		rpc_tests.cpp
 		rpc_server_tests.cpp
 		rwcollection_tests.cpp
 		sanity_tests.cpp
 		scheduler_tests.cpp
 		schnorr_tests.cpp
 		script_bitfield_tests.cpp
 		script_commitment_tests.cpp
 		script_p2sh_tests.cpp
 		script_standard_tests.cpp
 		script_tests.cpp
 		scriptnum_tests.cpp
 		serialize_tests.cpp
 		settings_tests.cpp
 		sigcache_tests.cpp
 		sigencoding_tests.cpp
 		sighash_tests.cpp
 		sighashtype_tests.cpp
 		sigcheckcount_tests.cpp
 		skiplist_tests.cpp
 		streams_tests.cpp
 		sync_tests.cpp
 		timedata_tests.cpp
 		torcontrol_tests.cpp
 		transaction_tests.cpp
 		txindex_tests.cpp
 		txvalidation_tests.cpp
 		txvalidationcache_tests.cpp
 		uint256_tests.cpp
 		undo_tests.cpp
 		util_tests.cpp
 		util_threadnames_tests.cpp
 		validation_block_tests.cpp
 		validation_tests.cpp
 		validationinterface_tests.cpp
 		versionbits_tests.cpp
 		work_comparator_tests.cpp
 
 		# RPC Tests
 		../rpc/test/server_tests.cpp
 
 		# Wallet tests
 		${BITCOIN_WALLET_TESTS}
 )
 
 function(add_boost_test_runners_with_upgrade_activated SUITE EXECUTABLE)
 	set(SUITE_UPGRADE_ACTIVATED "${SUITE}-upgrade-activated")
 	get_target_from_suite(${SUITE_UPGRADE_ACTIVATED} TARGET_UPGRADE_ACTIVATED)
 
 	if(NOT TARGET ${TARGET_UPGRADE_ACTIVATED})
 		create_test_suite_with_parent_targets(
 			${SUITE_UPGRADE_ACTIVATED}
 			check-upgrade-activated
 			check-upgrade-activated-extended
 		)
 		add_dependencies(${TARGET_UPGRADE_ACTIVATED} ${EXECUTABLE})
 	endif()
 
 	get_target_from_suite(${SUITE} SUITE_TARGET)
 	get_target_property(BOOST_TESTS ${SUITE_TARGET} UNIT_TESTS)
 
 	get_target_from_suite(${SUITE_UPGRADE_ACTIVATED} SUITE_UPGRADE_ACTIVATED_TARGET)
 
 	set(HRF_LOGGER "HRF,test_suite")
 
 	foreach(_test_name ${BOOST_TESTS})
 		if(ENABLE_JUNIT_REPORT)
 			set(JUNIT_LOGGER ":JUNIT,message,${SUITE_UPGRADE_ACTIVATED}-${_test_name}.xml")
 		endif()
 
 		add_test_runner(
 			${SUITE_UPGRADE_ACTIVATED}
 			"${_test_name}"
 			${EXECUTABLE}
 			JUNIT
 			"--run_test=${_test_name}"
 			"--logger=${HRF_LOGGER}${JUNIT_LOGGER}"
 			"--catch_system_errors=no"
 			# Dec. 1st, 2019 at 00:00:00
 			--
 			"-testsuitename=Bitcoin ABC unit tests with next upgrade activated"
 			-axionactivationtime=1575158400
 		)
 	endforeach()
 endfunction()
 
 add_boost_test_runners_with_upgrade_activated(bitcoin test_bitcoin)
 
 target_link_libraries(test_bitcoin rpcclient testutil)
 if(TARGET bitcoinconsensus-shared)
 	target_link_libraries(test_bitcoin bitcoinconsensus-shared)
 else()
 	target_link_libraries(test_bitcoin bitcoinconsensus)
 endif()
 
 add_subdirectory(fuzz)
diff --git a/src/test/fuzz/CMakeLists.txt b/src/test/fuzz/CMakeLists.txt
index a2a44b7d1..3d144a1ae 100644
--- a/src/test/fuzz/CMakeLists.txt
+++ b/src/test/fuzz/CMakeLists.txt
@@ -1,178 +1,179 @@
 # Fuzzer test harness
 add_custom_target(bitcoin-fuzzers)
 
 define_property(GLOBAL
 	PROPERTY FUZZ_TARGETS
 	BRIEF_DOCS "List of fuzz targets"
 	FULL_DOCS "A list of the fuzz targets"
 )
 set_property(GLOBAL APPEND PROPERTY FUZZ_TARGETS bitcoin-fuzzers)
 
 include(InstallationHelper)
 macro(add_fuzz_target TARGET EXE_NAME)
 	add_executable(${TARGET} EXCLUDE_FROM_ALL
 		fuzz.cpp
 		${ARGN}
 	)
 	set_target_properties(${TARGET} PROPERTIES OUTPUT_NAME ${EXE_NAME})
 
 	target_link_libraries(${TARGET} server testutil rpcclient)
 
 	add_dependencies(bitcoin-fuzzers ${TARGET})
 
 	set_property(GLOBAL APPEND PROPERTY FUZZ_TARGETS ${TARGET})
 
 	install_target(${TARGET}
 		COMPONENT fuzzer
 		EXCLUDE_FROM_ALL
 	)
 endmacro()
 
 function(add_regular_fuzz_targets)
 	foreach(_fuzz_test_name ${ARGN})
 		sanitize_target_name("fuzz-" ${_fuzz_test_name} _fuzz_target_name)
 		add_fuzz_target(
 			${_fuzz_target_name}
 			${_fuzz_test_name}
 
 			# Sources
 			"${_fuzz_test_name}.cpp"
 		)
 	endforeach()
 endfunction()
 
 include(SanitizeHelper)
 function(add_deserialize_fuzz_targets)
 	foreach(_fuzz_test_name ${ARGN})
 		sanitize_target_name("fuzz-" ${_fuzz_test_name} _fuzz_target_name)
 		add_fuzz_target(
 			${_fuzz_target_name}
 			${_fuzz_test_name}
 
 			# Sources
 			deserialize.cpp
 		)
 
 		sanitize_c_cxx_definition("" ${_fuzz_test_name} _target_definition)
 		string(TOUPPER ${_target_definition} _target_definition)
 		target_compile_definitions(${_fuzz_target_name} PRIVATE ${_target_definition})
 	endforeach()
 endfunction()
 
 function(add_process_message_fuzz_targets)
 	foreach(_fuzz_test_name ${ARGN})
 		sanitize_target_name("fuzz-process_message_" ${_fuzz_test_name} _fuzz_target_name)
 		add_fuzz_target(
 			${_fuzz_target_name}
 			process_message_${_fuzz_test_name}
 
 			# Sources
 			process_message.cpp
 		)
 
 		target_compile_definitions(${_fuzz_target_name} PRIVATE MESSAGE_TYPE=${_fuzz_test_name})
 	endforeach()
 endfunction()
 
 add_regular_fuzz_targets(
 	addrdb
 	asmap
 	base_encode_decode
 	block
 	bloom_filter
 	rolling_bloom_filter
 	cashaddr
 	descriptor_parse
 	eval_script
 	float
 	hex
 	integer
 	key
 	key_io
 	locale
 	net_permissions
 	netaddress
 	p2p_transport_deserializer
 	parse_hd_keypath
 	parse_iso8601
 	parse_numbers
 	parse_script
 	parse_univalue
 	process_message
+	process_messages
 	psbt
 	script
 	script_flags
 	spanparsing
 	strprintf
 	timedata
 	transaction
 	tx_in
 	tx_out
 )
 
 add_deserialize_fuzz_targets(
 	addr_info_deserialize
 	address_deserialize
 	addrman_deserialize
 	banentry_deserialize
 	block_deserialize
 	block_file_info_deserialize
 	block_filter_deserialize
 	block_header_and_short_txids_deserialize
 	blockheader_deserialize
 	blocklocator_deserialize
 	blockmerkleroot
 	blocktransactions_deserialize
 	blocktransactionsrequest_deserialize
 	blockundo_deserialize
 	bloomfilter_deserialize
 	coins_deserialize
 	diskblockindex_deserialize
 	fee_rate_deserialize
 	flat_file_pos_deserialize
 	inv_deserialize
 	key_origin_info_deserialize
 	merkle_block_deserialize
 	messageheader_deserialize
 	netaddr_deserialize
 	out_point_deserialize
 	partial_merkle_tree_deserialize
 	partially_signed_transaction_deserialize
 	prefilled_transaction_deserialize
 	psbt_input_deserialize
 	psbt_output_deserialize
 	pub_key_deserialize
 	script_deserialize
 	service_deserialize
 	sub_net_deserialize
 	tx_in_deserialize
 	txoutcompressor_deserialize
 	txundo_deserialize
 )
 
 add_process_message_fuzz_targets(
 	addr
 	block
 	blocktxn
 	cmpctblock
 	feefilter
 	filteradd
 	filterclear
 	filterload
 	getaddr
 	getblocks
 	getblocktxn
 	getdata
 	getheaders
 	headers
 	inv
 	mempool
 	notfound
 	ping
 	pong
 	sendcmpct
 	sendheaders
 	tx
 	verack
 	version
 )
diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp
new file mode 100644
index 000000000..78b5695bc
--- /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 <config.h>
+#include <consensus/consensus.h>
+#include <net.h>
+#include <net_processing.h>
+#include <protocol.h>
+#include <validation.h>
+#include <validationinterface.h>
+
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/mining.h>
+#include <test/util/net.h>
+#include <test/util/setup_common.h>
+
+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<uint8_t> &buffer) {
+    const Config &config = GetConfig();
+    FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+
+    ConnmanTestMsg &connman = *(ConnmanTestMsg *)g_setup->m_node.connman.get();
+    std::vector<CNode *> 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<uint64_t>());
+        const bool inbound{fuzzed_data_provider.ConsumeBool()};
+        const bool block_relay_only{fuzzed_data_provider.ConsumeBool()};
+        peers.push_back(
+            std::make_unique<CNode>(
+                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.command = random_message_type;
+        net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+
+        CNode &random_node =
+            *peers.at(fuzzed_data_provider.ConsumeIntegralInRange<int>(
+                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.cpp b/src/test/util/net.cpp
new file mode 100644
index 000000000..eaf46f9e5
--- /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 <test/util/net.h>
+
+#include <chainparams.h>
+#include <config.h>
+#include <net.h>
+
+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<uint8_t> 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/net.h b/src/test/util/net.h
new file mode 100644
index 000000000..669087c11
--- /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 <net.h>
+
+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/setup_common.cpp b/src/test/util/setup_common.cpp
index 84e0985d6..fb6de2825 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -1,373 +1,378 @@
 // Copyright (c) 2011-2019 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/util/setup_common.h>
 
 #include <banman.h>
 #include <chainparams.h>
 #include <config.h>
 #include <consensus/consensus.h>
 #include <consensus/validation.h>
 #include <crypto/sha256.h>
 #include <init.h>
 #include <interfaces/chain.h>
 #include <logging.h>
 #include <miner.h>
 #include <net.h>
 #include <net_processing.h>
 #include <noui.h>
 #include <pow/pow.h>
 #include <rpc/blockchain.h>
 #include <rpc/register.h>
 #include <rpc/server.h>
 #include <script/script_error.h>
 #include <script/scriptcache.h>
 #include <script/sigcache.h>
 #include <streams.h>
 #include <txdb.h>
 #include <txmempool.h>
 #include <util/strencodings.h>
 #include <util/time.h>
 #include <util/translation.h>
 #include <validation.h>
 #include <validationinterface.h>
 #include <walletinitinterface.h>
 
 #include <functional>
 #include <memory>
 
 const std::function<std::string(const char *)> G_TRANSLATION_FUN = nullptr;
 
 FastRandomContext g_insecure_rand_ctx;
 /**
  * Random context to get unique temp data dirs. Separate from
  * g_insecure_rand_ctx, which can be seeded from a const env var
  */
 static FastRandomContext g_insecure_rand_ctx_temp_path;
 
 /**
  * Return the unsigned from the environment var if available,
  * otherwise 0
  */
 static uint256 GetUintFromEnv(const std::string &env_name) {
     const char *num = std::getenv(env_name.c_str());
     if (!num) {
         return {};
     }
     return uint256S(num);
 }
 
 void Seed(FastRandomContext &ctx) {
     // Should be enough to get the seed once for the process
     static uint256 seed{};
     static const std::string RANDOM_CTX_SEED{"RANDOM_CTX_SEED"};
     if (seed.IsNull()) {
         seed = GetUintFromEnv(RANDOM_CTX_SEED);
     }
     if (seed.IsNull()) {
         seed = GetRandHash();
     }
     LogPrintf("%s: Setting random seed for current tests to %s=%s\n", __func__,
               RANDOM_CTX_SEED, seed.GetHex());
     ctx = FastRandomContext(seed);
 }
 
 std::ostream &operator<<(std::ostream &os, const uint256 &num) {
     os << num.ToString();
     return os;
 }
 
 std::ostream &operator<<(std::ostream &os, const ScriptError &err) {
     os << ScriptErrorString(err);
     return os;
 }
 
 BasicTestingSetup::BasicTestingSetup(const std::string &chainName)
     : m_path_root{fs::temp_directory_path() / "test_common_" PACKAGE_NAME /
                   g_insecure_rand_ctx_temp_path.rand256().ToString()} {
     SetMockTime(0);
     fs::create_directories(m_path_root);
     gArgs.ForceSetArg("-datadir", m_path_root.string());
     ClearDatadirCache();
     SelectParams(chainName);
     SeedInsecureRand();
     gArgs.ForceSetArg("-printtoconsole", "0");
     InitLogging();
     LogInstance().StartLogging();
     SHA256AutoDetect();
     ECC_Start();
     SetupEnvironment();
     SetupNetworking();
     InitSignatureCache();
     InitScriptExecutionCache();
 
     m_node.chain = interfaces::MakeChain(m_node, Params());
     g_wallet_init_interface.Construct(m_node);
 
     fCheckBlockIndex = true;
     static bool noui_connected = false;
     if (!noui_connected) {
         noui_connect();
         noui_connected = true;
     }
 }
 
 BasicTestingSetup::~BasicTestingSetup() {
     LogInstance().DisconnectTestLogger();
     fs::remove_all(m_path_root);
     ECC_Stop();
 }
 
 TestingSetup::TestingSetup(const std::string &chainName)
     : BasicTestingSetup(chainName) {
     const Config &config = GetConfig();
     const CChainParams &chainparams = config.GetChainParams();
 
     // Ideally we'd move all the RPC tests to the functional testing framework
     // instead of unit tests, but for now we need these here.
     RPCServer rpcServer;
     RegisterAllRPCCommands(config, rpcServer, tableRPC);
 
     /**
      * RPC does not come out of the warmup state on its own. Normally, this is
      * handled in bitcoind's init path, but unit tests do not trigger this
      * codepath, so we call it explicitly as part of setup.
      */
     std::string rpcWarmupStatus;
     if (RPCIsInWarmup(&rpcWarmupStatus)) {
         SetRPCWarmupFinished();
     }
 
     m_node.scheduler = std::make_unique<CScheduler>();
 
     // We have to run a scheduler thread to prevent ActivateBestChain
     // from blocking due to queue overrun.
     threadGroup.create_thread([&] { m_node.scheduler->serviceQueue(); });
     GetMainSignals().RegisterBackgroundSignalScheduler(*m_node.scheduler);
 
     pblocktree.reset(new CBlockTreeDB(1 << 20, true));
     g_chainstate = std::make_unique<CChainState>();
     ::ChainstateActive().InitCoinsDB(
         /* cache_size_bytes */ 1 << 23, /* in_memory */ true,
         /* should_wipe */ false);
     assert(!::ChainstateActive().CanFlushToDisk());
     ::ChainstateActive().InitCoinsCache();
     assert(::ChainstateActive().CanFlushToDisk());
     if (!LoadGenesisBlock(chainparams)) {
         throw std::runtime_error("LoadGenesisBlock failed.");
     }
     {
         BlockValidationState state;
         if (!ActivateBestChain(config, state)) {
             throw std::runtime_error(
                 strprintf("ActivateBestChain failed. (%s)", state.ToString()));
         }
     }
     constexpr int script_check_threads = 2;
     for (int i = 0; i < script_check_threads; ++i) {
         threadGroup.create_thread([i]() { return ThreadScriptCheck(i); });
     }
 
     m_node.mempool = &::g_mempool;
     m_node.mempool->setSanityCheck(1.0);
     m_node.banman =
         std::make_unique<BanMan>(GetDataDir() / "banlist.dat", chainparams,
                                  nullptr, DEFAULT_MISBEHAVING_BANTIME);
     // Deterministic randomness for tests.
     m_node.connman = std::make_unique<CConnman>(config, 0x1337, 0x1337);
     m_node.peer_logic = std::make_unique<PeerLogicValidation>(
         m_node.connman.get(), m_node.banman.get(), *m_node.scheduler);
+    {
+        CConnman::Options options;
+        options.m_msgproc = m_node.peer_logic.get();
+        m_node.connman->Init(options);
+    }
 }
 
 TestingSetup::~TestingSetup() {
     if (m_node.scheduler) {
         m_node.scheduler->stop();
     }
     threadGroup.interrupt_all();
     threadGroup.join_all();
     GetMainSignals().FlushBackgroundCallbacks();
     GetMainSignals().UnregisterBackgroundSignalScheduler();
     m_node.connman.reset();
     m_node.banman.reset();
     m_node.mempool = nullptr;
     m_node.scheduler.reset();
     UnloadBlockIndex();
     g_chainstate.reset();
     pblocktree.reset();
 }
 
 TestChain100Setup::TestChain100Setup() {
     // Generate a 100-block chain:
     coinbaseKey.MakeNewKey(true);
     CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey())
                                      << OP_CHECKSIG;
     for (int i = 0; i < COINBASE_MATURITY; i++) {
         std::vector<CMutableTransaction> noTxns;
         CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey);
         m_coinbase_txns.push_back(b.vtx[0]);
     }
 }
 
 //
 // Create a new block with just given transactions, coinbase paying to
 // scriptPubKey, and try to add it to the current chain.
 //
 CBlock TestChain100Setup::CreateAndProcessBlock(
     const std::vector<CMutableTransaction> &txns, const CScript &scriptPubKey) {
     const Config &config = GetConfig();
     std::unique_ptr<CBlockTemplate> pblocktemplate =
         BlockAssembler(config, *m_node.mempool).CreateNewBlock(scriptPubKey);
     CBlock &block = pblocktemplate->block;
 
     // Replace mempool-selected txns with just coinbase plus passed-in txns:
     block.vtx.resize(1);
     for (const CMutableTransaction &tx : txns) {
         block.vtx.push_back(MakeTransactionRef(tx));
     }
 
     // Order transactions by canonical order
     std::sort(std::begin(block.vtx) + 1, std::end(block.vtx),
               [](const std::shared_ptr<const CTransaction> &txa,
                  const std::shared_ptr<const CTransaction> &txb) -> bool {
                   return txa->GetId() < txb->GetId();
               });
 
     // IncrementExtraNonce creates a valid coinbase and merkleRoot
     {
         LOCK(cs_main);
         unsigned int extraNonce = 0;
         IncrementExtraNonce(&block, ::ChainActive().Tip(),
                             config.GetMaxBlockSize(), extraNonce);
     }
 
     const Consensus::Params &params = config.GetChainParams().GetConsensus();
     while (!CheckProofOfWork(block.GetHash(), block.nBits, params)) {
         ++block.nNonce;
     }
 
     std::shared_ptr<const CBlock> shared_pblock =
         std::make_shared<const CBlock>(block);
     ProcessNewBlock(config, shared_pblock, true, nullptr);
 
     CBlock result = block;
     return result;
 }
 
 TestChain100Setup::~TestChain100Setup() {}
 
 CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx) {
     return FromTx(MakeTransactionRef(tx));
 }
 
 CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransactionRef &tx) {
     return CTxMemPoolEntry(tx, nFee, nTime, nHeight, spendsCoinbase,
                            nSigOpCount, LockPoints());
 }
 
 /**
  * @returns a real block
  * (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af) with 9
  * txs.
  */
 CBlock getBlock13b8a() {
     CBlock block;
     CDataStream stream(
         ParseHex(
             "0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb680000000"
             "0000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558"
             "da2fdb261b4d4c86041b1ab1bf9309010000000100000000000000000000000000"
             "00000000000000000000000000000000000000ffffffff07044c86041b0146ffff"
             "ffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf2"
             "54bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c"
             "4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada9027"
             "80da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100da"
             "b24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd0221"
             "00fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb4"
             "01ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369e"
             "d2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98e"
             "c706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad"
             "2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21ad"
             "c6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e86"
             "25a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d8982"
             "35e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff02"
             "80969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388"
             "ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd3"
             "88ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c522"
             "92d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3"
             "889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2f"
             "afd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d3"
             "1b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83aba"
             "f975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cb"
             "cba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044"
             "022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae7406056"
             "58022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e0100"
             "3614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c342"
             "3e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc"
             "2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13"
             "fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021"
             "e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91"
             "c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b4830"
             "4502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9"
             "236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddc"
             "ce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d78990"
             "4f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8"
             "ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942"
             "fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad5652937"
             "1864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd9"
             "0111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37"
             "f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b"
             "25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d0014104"
             "43bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf"
             "7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffff"
             "ffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a1232"
             "2d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70a"
             "e67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176"
             "f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf"
             "062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b956"
             "00db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd40"
             "67b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c6"
             "9b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e"
             "58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b217901000000"
             "8b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3c"
             "a2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b49"
             "1d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33"
             "d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312e"
             "f1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144a"
             "f553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd"
             "48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b"
             "659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0"
             "aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc3"
             "1895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9"
             "944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830"
             "450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1a"
             "f03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d9"
             "8a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d78990"
             "4f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8"
             "ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a03"
             "8fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261"
             "b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f6351285"
             "0811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa4207"
             "0082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0"
             "c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c0000000000"
             "1976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000"
             "000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed"
             "8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc"
             "87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded"
             "4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e"
             "3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29"
             "934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695"
             "a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93"
             "376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e9"
             "1349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49"
             "304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654"
             "d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66"
             "ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e88"
             "60c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8"
             "fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb604203"
             "4aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75e"
             "ef7942fc9288edd37c32f5c388ac00000000"),
         SER_NETWORK, PROTOCOL_VERSION);
     stream >> block;
     return block;
 }