/* * This file is part of the Flowee project * Copyright (C) 2020-2025 Tom Zander * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef FLOWEE_PEER_H #define FLOWEE_PEER_H #include "PeerAddressDB.h" #include "BlockHeader.h" #include #include #include #include class PrivacySegment; class Blockchain; class ConnectionManager; class CBloomFilter; class BroadcastTxData; class Peer : public std::enable_shared_from_this { public: enum PeerStatus { Connecting, Connected, ShuttingDown }; explicit Peer(ConnectionManager *parent, const PeerAddress &address); ~Peer(); void connect(NetworkConnection && server); /** * @brief shutdown will cause this peer stop processing network request. * * Calling this is required for the shared_ptr based peer to be deletable. * Specificially: it breaks a cyclic loop with the network layer. */ void shutdown(); /// Returns the services bitfield of the remote peer. uint64_t services() const; /// Returns the amount of seconds that this peer is ahead/behind us. int timeOffset() const; /// Return the protocol version the remote peer reported. int protocolVersion() const; /// Returns the internal ID our network connection is on. inline int connectionId() const { return m_con.connectionId(); } /// Returns the user-agent of the remote peer. std::string userAgent() const; /// Returns the blockheight the peer reported at connection time. int startHeight() const; /// Returns if the remote peer is willing to relay transactions. bool relaysTransactions() const; /// Returns if the remote peer prefers headers over INV messages for new block announcements. bool preferHeaders() const; /// Return the current connection status of this peer. PeerStatus status() const { return m_peerStatus; } /// Returns true if the peers services indicate it supplies serving blockdata over the network. bool supplies_network() { return (m_services & 1) == 1; } // bip 159 /// Returns true if the peer services indicate it is partial (pruned) blockdata it serves over the net. bool supplies_partialNetwork() { return (m_services & 2) != 0; } /// Returns true if the peer supplies bloom services. bool supplies_bloom() { return (m_services & 4) != 0; } /// Sends a message to the remote peer. inline void sendMessage(const Message &message) { m_con.send(message); } /// Returns the address of the remote peer. inline PeerAddress& peerAddress() { return m_peerAddress; } /// Returns the address of the remote peer. inline const PeerAddress& peerAddress() const { return m_peerAddress; } /// peer has received the response to 'getheaders', implying it is following the same chain as us. /// @see PeerAddress::lastReceivedGoodHeaders() for a historical one. /// @see requestedHeaders() bool receivedHeaders() const; /// Peer asked for getheaders, see @receivedHeaders() bool requestedHeader() const; /// set if the peer requested headers. void setRequestedHeader(bool requestedHeader); /// Assigns this peer a wallet in the shape of a PrivacySegment. void setPrivacySegment(const std::shared_ptr &ps); /// Return the set privacy segment, if any. inline const std::weak_ptr &privacySegment() const { return m_segment; } // request this peer to please broadcast this Tx. void sendTx(const std::shared_ptr &txOwner); /// the blockheight of the last merkle block we received. int lastReceivedMerkle() const; /// Return true if the merkle-block based fetches are in-progress. bool merkleDownloadInProgress() const; /// start downloads of merkle (aka SPV) blocks to the current height. /// @param maxHeight can be given to stop earlier than current height. void startMerkleDownload(int from, int maxHeight = -1); /// Return the timestamp of first-connection time. uint32_t connectTime() const; /** * returns the peer-local blockheight. * This is verfiied to be more than a number, it actually reflects * an index in our, locally verified, longest chain. */ int peerHeight() const; /** * This is called when our messages are processed and they show * our peer has proven to have reached a valid height of at least \a peerHeight. * * Passing in a lower number than the current peerHeight will silently be ignored. */ void updatePeerHeight(int peerHeight); // \internal callback from PrivacySegment // @param mempoolMessage if true, the privacy segments wants the `mempool` p2p message // to be sent directly after the bloom filter update. void filterUpdated(bool mempoolMessage); int highestMerkleReceived() const; private: void connected(const EndPoint&); void disconnected(const EndPoint&); void processMessage(const Message &message); void processTransaction(const Tx &tx); /// sends the bloom filter to peer. void sendFilter(bool mempoolMessage = false); void registerTxToSend(std::shared_ptr txOwner); std::string m_userAgent; uint64_t m_services = 0; int m_timeOffset = 0; uint32_t m_connectTime = 0; int m_protocolVersion = 0; int m_startHeight = 0; int m_peerHeight = 0; bool m_relaysTransactions = false; bool m_preferHeaders = false; bool m_requestedHeader = false; bool m_receivedHeaders = false; bool m_mempoolSent = false; PeerAddress m_peerAddress; std::atomic m_peerStatus; NetworkConnection m_con; ConnectionManager * const m_connectionManager; // privacy segment data std::weak_ptr m_segment; int m_bloomUploaded = 0; // the bloom filter we uploaded as referenced by segment->filterChangedHeight() /* * Merkle blocks are downloaded in a sliding window style. * The next 5 properties show which blocks are in-flight. */ int m_lastReceivedMerkle = 0; ///< most recently received block int m_merkleDownloadFrom = -1; ///< sliding-window bottom int m_merkleDownloadTo = -1; ///< sliding-window top. (highest requested) int m_highestMerkleReceived = -1; ///< highest received block int m_merkleDownloadBoundary = -1; ///< Instead of stopping at the headers-tip, stop at this boundary. // SPV merkle block data int m_merkleBlockHeight = -1; std::vector m_transactionHashes; std::deque m_blockTransactions; BlockHeader m_merkleHeader; std::deque > m_transactions; }; #endif