Files
thehub/libs/p2p/Peer.h
T
tomFlowee 70e4f2292e Refactor the SPV merkleblock/mempool sending
Tuesdays idea of adding some code into the SyncSPVAction didn't feel
right.
A second look made clear that bloom filter updates make much more sense
to go hand in hand with sending a mempool message. Especially since they
depend on each other on the server side.

To-rehash:
the wallet may decide at any time that a new bloom filter is needed. It
then uses the superclass (code in p2plib) PrivacySegment, to build that
filter. As part of that we get a lock object which, when going out of
scope, makes the peers that are subscribed to the privacySegment send
out the filter.

This separation of concerns means that the subclass wallet in the app
doens't know about peers or messages, only its superclass PrivacySegment
does.

What we did in this change is make the PrivacySegment class decide to
combine a bloom update with a mempool call. Typicall only once per
connection.

This means I can remove hacks in the SyncSPVAction which forced the
sending of the mempool message separately.
2023-02-24 19:41:42 +01:00

210 lines
6.5 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 PEER_H
#define PEER_H
#include "PeerAddressDB.h"
#include "BlockHeader.h"
#include "PrivacySegmentListener.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>, private PrivacySegmentListener
{
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.
void startMerkleDownload(int from);
/// Return the timestamp of first-connection time.
uint32_t connectTime() const;
/**
* The peer-local blockheight. nnything higher than this is
* likely not present on that peer yet.
*
* Notice that the height is counted as it is in OUR blockchain.
*/
int peerHeight() const;
/**
* This is called when our messages are processed and they show
* our peer has a (possibly) higher blockHeight.
*/
void updatePeerHeight(int peerHeight);
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);
// PrivacySegmentListener interface
void filterUpdated(bool mempoolMessage) override;
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;
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()
int m_lastReceivedMerkle = 0;
int m_merkleDownloadFrom = -1;
int m_merkleDownloadTo = -1;
int m_highestMerkleReceived = -1;
// 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