Files
thehub/libs/p2p/Peer.h
T
tomFlowee 6ade318b2e Introduce interleaving during download
The download from a peer is now limited to just 4000 blocks, at which
point the download proceeds from another peer.
Naturally it can go back to the first afterwards too.

The idea is that we download a month worth of blocks at a time and then
fetch the same blocks from a backup peer in order to be certain we
actually see the real state.
The problem we've seen is that after the first downloads we end up
starting the second and if the initial sync or a similar large download
happens, many people won't leave it running until the backup actually
completes since the UI looks like its finished.

This is also a good starting point for rating peers at download speed by
having predictable chunks and that means we could time and aim to use
the faster peers.
This is becoming relevant as we can see a huge difference where peers
give you 10x performance compared to some of the slower ones.
2024-02-23 22:08:28 +01:00

220 lines
7.2 KiB
C++

/*
* This file is part of the Flowee project
* Copyright (C) 2020-2023 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(PrivacySegment *ps);
/// Return the set privacy segment, if any.
inline 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);
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
PrivacySegment *m_segment = nullptr;
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