Files
thehub/libs/p2p/PeerAddressDB.h
T

227 lines
7.0 KiB
C++
Raw Permalink Normal View History

2020-04-17 19:33:06 +02:00
/*
* This file is part of the Flowee project
2022-11-11 19:25:19 +01:00
* Copyright (C) 2020-2022 Tom Zander <tom@flowee.org>
2020-04-17 19:33:06 +02:00
*
* 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 PEERADDRESSDB_H
#define PEERADDRESSDB_H
#include <NetworkEndPoint.h>
2020-05-11 12:49:10 +02:00
#include <boost/filesystem.hpp>
2020-04-17 19:33:06 +02:00
#include <map>
2020-05-16 10:28:08 +02:00
#include <mutex>
2020-04-17 19:33:06 +02:00
class PeerAddressDB;
class Message;
class ConnectionManager;
2023-04-23 11:58:18 +02:00
// this is the cut-off punishment score that makes a peer get
// insta disconnected.
2020-04-17 19:33:06 +02:00
constexpr int PUNISHMENT_MAX = 1000;
2021-07-30 10:01:06 +02:00
/**
* Represents a single peer we could or have connected to.
*/
2020-04-17 19:33:06 +02:00
class PeerAddress
{
public:
2021-07-30 10:01:06 +02:00
/// returns the internet address over which the peer can be reached
2020-04-17 19:33:06 +02:00
const EndPoint &peerAddress() const;
2021-07-30 10:01:06 +02:00
/**
* Calling this updates the peer database to register that we have successfully connected to this peer.
*/
2020-04-17 19:33:06 +02:00
void successfullyConnected();
2021-07-30 10:01:06 +02:00
/**
* Calling this updates the database to register that we received good headers.
*/
void gotGoodHeaders();
2021-07-30 10:01:06 +02:00
/**
* Register a punishment for this peer.
* This is used to keep track of how much this peer misbehaves. 1000 points means they are banned.
*/
2020-04-17 19:33:06 +02:00
short punishPeer(short amount);
2021-07-30 10:01:06 +02:00
/**
* Current level of punishment.
*/
2020-04-17 19:33:06 +02:00
short punishment() const;
2021-07-30 10:01:06 +02:00
/**
* Reset the punishment.
*/
2020-04-26 16:20:45 +02:00
void resetPunishment();
2021-07-30 10:01:06 +02:00
/**
* Returns simply if this instance represents an actual entry in the peer adddress DB.
*/
2020-04-17 19:33:06 +02:00
bool isValid() const;
2021-07-30 10:01:06 +02:00
/// Returns true if an p2p message for addresses was received.
2020-04-17 19:33:06 +02:00
bool askedAddresses() const;
2021-07-30 10:01:06 +02:00
/// Register if we asked for adddresses.
2020-04-17 19:33:06 +02:00
void setAskedAddresses(bool on);
2021-07-30 10:01:06 +02:00
/**
* Returns true if we have ever made a full connection to this peer.
* Notice that connecting to a peer on a different chain still may return true here.
* @see successfullyConnected()
*/
2020-04-26 16:20:45 +02:00
bool hasEverConnected() const;
2021-07-30 10:01:06 +02:00
/**
* Return a unit timestamp (sec since epoch) when we received good headers from this peer.
2023-02-25 11:04:19 +01:00
* Or 0 if the peer never did.
2021-07-30 10:01:06 +02:00
*/
2020-11-05 21:53:08 +01:00
uint32_t lastReceivedGoodHeaders() const;
2020-04-17 19:33:06 +02:00
2021-07-30 10:01:06 +02:00
/**
* THe PrivacySegment ID that this peer is associated with.
* For privacy reasons we only allow this peer to see this privacy segments bloom filter.
*/
2020-04-17 19:33:06 +02:00
uint16_t segment() const;
2021-07-30 10:01:06 +02:00
/**
* Set the privacy segment ID.
*/
2020-04-17 19:33:06 +02:00
void setSegment(uint16_t segment);
2021-07-30 10:01:06 +02:00
/**
* Register on the peerAddressDB (non persistent) that this peer is being used.
* This typically menas we are connecting or connected to the peer.
*/
2020-04-17 19:33:06 +02:00
void setInUse(bool on);
2021-07-30 10:01:06 +02:00
/**
* Remember which services the peer announces.
* @see Peer::services()
*/
2020-04-17 19:33:06 +02:00
void setServices(uint64_t services);
2021-07-30 10:01:06 +02:00
/**
* Return the unix date (sec since epoch) when we last made a successsful full connection.
*/
2020-04-17 19:33:06 +02:00
uint32_t lastConnected() const;
2021-07-30 10:01:06 +02:00
/// \internal This returns the peerAddressDB internal ID for this specific peer.
2020-04-17 19:33:06 +02:00
int id() const;
protected:
friend class PeerAddressDB;
explicit PeerAddress(PeerAddressDB *parent, int peerId);
private:
PeerAddressDB *d;
int m_id;
};
2021-07-30 10:01:06 +02:00
/**
* The addresses database to collect and manage all the peeer addresses we learned about.
* In the p2p net, peers notify each other about peers they recently successsfully connected to.
* We store and score and manage those addresses for ourselves.
*
* This is backed by the on-disk file 'peers.dat'
*/
2020-04-17 19:33:06 +02:00
class PeerAddressDB
{
public:
PeerAddressDB(ConnectionManager *parent);
2021-07-30 10:01:06 +02:00
/**
* Try to find a (semi)random peer that has good specs to connect to.
* The peer returned will have a good score (low punishment) and not already in use.
*
* \param required services. A mask of services that a peer must have.
*
* \param segment The segment (privacySegment ID) is matched or a peer with no segment is returned,
* we guarentee this method never returns a match that has a different segment.
*
* Please note that the PeerAddressDB instance has to outlive the PeerAddress instance.
*/
2020-04-17 19:33:06 +02:00
PeerAddress findBest(uint64_t requiredServices = 0, uint16_t segment = 0);
2021-07-30 10:01:06 +02:00
/// return number of peers this DB holds.
2020-04-17 19:33:06 +02:00
int peerCount() const;
void processAddressMessage(const Message &message, int sourcePeerId);
2021-07-30 10:01:06 +02:00
/**
* Try to add a peer to the DB.
* Duplicates are Ok, we notice them and decrese their punishment if multiple sources repeat it.
*/
2020-04-17 19:33:06 +02:00
void addOne(const EndPoint &endPoint);
2021-07-30 10:01:06 +02:00
/// \internal
2020-04-17 19:33:06 +02:00
inline PeerAddress peer(int id) {
assert(0 <= id);
return PeerAddress(this, id);
}
2020-05-11 12:49:10 +02:00
void saveDatabase(const boost::filesystem::path &basedir);
void loadDatabase(const boost::filesystem::path &basedir);
2021-07-30 10:01:06 +02:00
/// return the current network's default port number for peers that don't supply one.
2020-10-29 21:47:53 +01:00
int defaultPortNr() const;
2021-07-30 10:01:06 +02:00
/**
* Peers that we get from DNS do not have a port number, this is used to store
* the current network's default port number for those peers.
*/
2020-10-29 21:47:53 +01:00
void setDefaultPortNr(int defaultPortNr);
2020-04-17 19:33:06 +02:00
private:
friend class PeerAddress;
struct PeerInfo {
EndPoint address;
uint64_t services = 0;
uint32_t lastConnected = 0;
2020-05-11 18:49:16 +02:00
uint32_t lastReceivedGoodHeaders = 0;
2020-04-17 19:33:06 +02:00
short punishment = 0;
uint16_t segment = 0;
short peerSpeed = 0;
bool inUse = false;
bool askedAddr = false;
bool everConnected = false; // if false, lastConnected comes from untrusted peers
};
2020-05-09 19:58:44 +02:00
void insert(PeerInfo &pi);
2020-04-17 19:33:06 +02:00
2020-05-16 10:28:08 +02:00
mutable std::mutex m_lock;
2020-04-17 19:33:06 +02:00
std::map<int, PeerInfo> m_peers;
int m_nextPeerId = 0;
int m_disabledPeerCount = 0; // amount of peers with punishment >= 1000
2020-10-29 21:47:53 +01:00
int m_defaultPortNr = 8333;
2022-11-11 19:25:19 +01:00
bool m_needsSave = false;
2023-04-23 11:58:18 +02:00
bool m_supportIPv4Net = true;
bool m_supportIPv6Net = false;
2020-04-17 19:33:06 +02:00
ConnectionManager *m_parent;
};
2020-05-10 11:51:17 +02:00
inline Log::Item operator<<(Log::Item item, const PeerAddress &pa) {
if (item.isEnabled()) {
const bool old = item.useSpace();
item.nospace() << pa.id() << "-{";
const EndPoint &ep = pa.peerAddress();
if (ep.ipAddress.is_unspecified())
item << ep.hostname;
else
item << ep.ipAddress.to_string().c_str();
2020-10-29 21:47:53 +01:00
if (ep.announcePort != 8333 && ep.announcePort != 28333)
2020-05-10 11:51:17 +02:00
item << ':' << ep.announcePort;
item << '}';
if (old)
return item.space();
}
return item;
}
inline Log::SilentItem operator<<(Log::SilentItem item, const PeerAddress&) { return item; }
2020-04-17 19:33:06 +02:00
#endif