70e4f2292e
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.
210 lines
6.5 KiB
C++
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
|