Files
thehub/libs/p2p/Peer.h
T
tomFlowee f2d12fd1fe Alter spv download to be parallel.
We always need two random peers to download a certain merkle block, to
avoid the withholding attack.
It occurred to me that there is no need to do them one after the other,
they can both run in parallel without issues. Saving time.
2025-02-19 19:26:56 +01:00

222 lines
7.3 KiB
C++

/*
* This file is part of the Flowee project
* Copyright (C) 2020-2025 Tom Zander <tom@flowee.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef FLOWEE_PEER_H
#define FLOWEE_PEER_H
#include "PeerAddressDB.h"
#include "BlockHeader.h"
#include <primitives/Tx.h>
#include <networkmanager/NetworkConnection.h>
#include <uint256.h>
#include <deque>
class PrivacySegment;
class Blockchain;
class ConnectionManager;
class CBloomFilter;
class BroadcastTxData;
class Peer : public std::enable_shared_from_this<Peer>
{
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<PrivacySegment> &ps);
/// Return the set privacy segment, if any.
inline const std::weak_ptr<PrivacySegment> &privacySegment() const {
return m_segment;
}
// request this peer to please broadcast this Tx.
void sendTx(const std::shared_ptr<BroadcastTxData> &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<BroadcastTxData> 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<PeerStatus> m_peerStatus;
NetworkConnection m_con;
ConnectionManager * const m_connectionManager;
// privacy segment data
std::weak_ptr<PrivacySegment> 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<uint256> m_transactionHashes;
std::deque<Tx> m_blockTransactions;
BlockHeader m_merkleHeader;
std::deque<std::weak_ptr<BroadcastTxData> > m_transactions;
};
#endif