Branch data Line data Source code
# 1 : : // Copyright (c) 2012 Pieter Wuille
# 2 : : // Copyright (c) 2012-2021 The Bitcoin Core developers
# 3 : : // Distributed under the MIT software license, see the accompanying
# 4 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
# 5 : :
# 6 : : #ifndef BITCOIN_ADDRMAN_H
# 7 : : #define BITCOIN_ADDRMAN_H
# 8 : :
# 9 : : #include <netaddress.h>
# 10 : : #include <protocol.h>
# 11 : : #include <streams.h>
# 12 : : #include <timedata.h>
# 13 : :
# 14 : : #include <cstdint>
# 15 : : #include <memory>
# 16 : : #include <optional>
# 17 : : #include <utility>
# 18 : : #include <vector>
# 19 : :
# 20 : : class InvalidAddrManVersionError : public std::ios_base::failure
# 21 : : {
# 22 : : public:
# 23 : 1 : InvalidAddrManVersionError(std::string msg) : std::ios_base::failure(msg) { }
# 24 : : };
# 25 : :
# 26 : : class AddrManImpl;
# 27 : :
# 28 : : /** Default for -checkaddrman */
# 29 : : static constexpr int32_t DEFAULT_ADDRMAN_CONSISTENCY_CHECKS{0};
# 30 : :
# 31 : : /** Test-only struct, capturing info about an address in AddrMan */
# 32 : : struct AddressPosition {
# 33 : : // Whether the address is in the new or tried table
# 34 : : const bool tried;
# 35 : :
# 36 : : // Addresses in the tried table should always have a multiplicity of 1.
# 37 : : // Addresses in the new table can have multiplicity between 1 and
# 38 : : // ADDRMAN_NEW_BUCKETS_PER_ADDRESS
# 39 : : const int multiplicity;
# 40 : :
# 41 : : // If the address is in the new table, the bucket and position are
# 42 : : // populated based on the first source who sent the address.
# 43 : : // In certain edge cases, this may not be where the address is currently
# 44 : : // located.
# 45 : : const int bucket;
# 46 : : const int position;
# 47 : :
# 48 : 4 : bool operator==(AddressPosition other) {
# 49 : 4 : return std::tie(tried, multiplicity, bucket, position) ==
# 50 : 4 : std::tie(other.tried, other.multiplicity, other.bucket, other.position);
# 51 : 4 : }
# 52 : : explicit AddressPosition(bool tried_in, int multiplicity_in, int bucket_in, int position_in)
# 53 : 26 : : tried{tried_in}, multiplicity{multiplicity_in}, bucket{bucket_in}, position{position_in} {}
# 54 : : };
# 55 : :
# 56 : : /** Stochastic address manager
# 57 : : *
# 58 : : * Design goals:
# 59 : : * * Keep the address tables in-memory, and asynchronously dump the entire table to peers.dat.
# 60 : : * * Make sure no (localized) attacker can fill the entire table with his nodes/addresses.
# 61 : : *
# 62 : : * To that end:
# 63 : : * * Addresses are organized into buckets that can each store up to 64 entries.
# 64 : : * * Addresses to which our node has not successfully connected go into 1024 "new" buckets.
# 65 : : * * Based on the address range (/16 for IPv4) of the source of information, or if an asmap is provided,
# 66 : : * the AS it belongs to (for IPv4/IPv6), 64 buckets are selected at random.
# 67 : : * * The actual bucket is chosen from one of these, based on the range in which the address itself is located.
# 68 : : * * The position in the bucket is chosen based on the full address.
# 69 : : * * One single address can occur in up to 8 different buckets to increase selection chances for addresses that
# 70 : : * are seen frequently. The chance for increasing this multiplicity decreases exponentially.
# 71 : : * * When adding a new address to an occupied position of a bucket, it will not replace the existing entry
# 72 : : * unless that address is also stored in another bucket or it doesn't meet one of several quality criteria
# 73 : : * (see IsTerrible for exact criteria).
# 74 : : * * Addresses of nodes that are known to be accessible go into 256 "tried" buckets.
# 75 : : * * Each address range selects at random 8 of these buckets.
# 76 : : * * The actual bucket is chosen from one of these, based on the full address.
# 77 : : * * When adding a new good address to an occupied position of a bucket, a FEELER connection to the
# 78 : : * old address is attempted. The old entry is only replaced and moved back to the "new" buckets if this
# 79 : : * attempt was unsuccessful.
# 80 : : * * Bucket selection is based on cryptographic hashing, using a randomly-generated 256-bit key, which should not
# 81 : : * be observable by adversaries.
# 82 : : * * Several indexes are kept for high performance. Setting m_consistency_check_ratio with the -checkaddrman
# 83 : : * configuration option will introduce (expensive) consistency checks for the entire data structure.
# 84 : : */
# 85 : : class AddrMan
# 86 : : {
# 87 : : protected:
# 88 : : const std::unique_ptr<AddrManImpl> m_impl;
# 89 : :
# 90 : : public:
# 91 : : explicit AddrMan(std::vector<bool> asmap, bool deterministic, int32_t consistency_check_ratio);
# 92 : :
# 93 : : ~AddrMan();
# 94 : :
# 95 : : template <typename Stream>
# 96 : : void Serialize(Stream& s_) const;
# 97 : :
# 98 : : template <typename Stream>
# 99 : : void Unserialize(Stream& s_);
# 100 : :
# 101 : : //! Return the number of (unique) addresses in all tables.
# 102 : : size_t size() const;
# 103 : :
# 104 : : /**
# 105 : : * Attempt to add one or more addresses to addrman's new table.
# 106 : : *
# 107 : : * @param[in] vAddr Address records to attempt to add.
# 108 : : * @param[in] source The address of the node that sent us these addr records.
# 109 : : * @param[in] nTimePenalty A "time penalty" to apply to the address record's nTime. If a peer
# 110 : : * sends us an address record with nTime=n, then we'll add it to our
# 111 : : * addrman with nTime=(n - nTimePenalty).
# 112 : : * @return true if at least one address is successfully added. */
# 113 : : bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty = 0);
# 114 : :
# 115 : : /**
# 116 : : * Mark an address record as accessible and attempt to move it to addrman's tried table.
# 117 : : *
# 118 : : * @param[in] addr Address record to attempt to move to tried table.
# 119 : : * @param[in] nTime The time that we were last connected to this peer.
# 120 : : * @return true if the address is successfully moved from the new table to the tried table.
# 121 : : */
# 122 : : bool Good(const CService& addr, int64_t nTime = GetAdjustedTime());
# 123 : :
# 124 : : //! Mark an entry as connection attempted to.
# 125 : : void Attempt(const CService& addr, bool fCountFailure, int64_t nTime = GetAdjustedTime());
# 126 : :
# 127 : : //! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
# 128 : : void ResolveCollisions();
# 129 : :
# 130 : : /**
# 131 : : * Randomly select an address in the tried table that another address is
# 132 : : * attempting to evict.
# 133 : : *
# 134 : : * @return CAddress The record for the selected tried peer.
# 135 : : * int64_t The last time we attempted to connect to that peer.
# 136 : : */
# 137 : : std::pair<CAddress, int64_t> SelectTriedCollision();
# 138 : :
# 139 : : /**
# 140 : : * Choose an address to connect to.
# 141 : : *
# 142 : : * @param[in] newOnly Whether to only select addresses from the new table.
# 143 : : * @return CAddress The record for the selected peer.
# 144 : : * int64_t The last time we attempted to connect to that peer.
# 145 : : */
# 146 : : std::pair<CAddress, int64_t> Select(bool newOnly = false) const;
# 147 : :
# 148 : : /**
# 149 : : * Return all or many randomly selected addresses, optionally by network.
# 150 : : *
# 151 : : * @param[in] max_addresses Maximum number of addresses to return (0 = all).
# 152 : : * @param[in] max_pct Maximum percentage of addresses to return (0 = all).
# 153 : : * @param[in] network Select only addresses of this network (nullopt = all).
# 154 : : *
# 155 : : * @return A vector of randomly selected addresses from vRandom.
# 156 : : */
# 157 : : std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const;
# 158 : :
# 159 : : /** We have successfully connected to this peer. Calling this function
# 160 : : * updates the CAddress's nTime, which is used in our IsTerrible()
# 161 : : * decisions and gossiped to peers. Callers should be careful that updating
# 162 : : * this information doesn't leak topology information to network spies.
# 163 : : *
# 164 : : * net_processing calls this function when it *disconnects* from a peer to
# 165 : : * not leak information about currently connected peers.
# 166 : : *
# 167 : : * @param[in] addr The address of the peer we were connected to
# 168 : : * @param[in] nTime The time that we were last connected to this peer
# 169 : : */
# 170 : : void Connected(const CService& addr, int64_t nTime = GetAdjustedTime());
# 171 : :
# 172 : : //! Update an entry's service bits.
# 173 : : void SetServices(const CService& addr, ServiceFlags nServices);
# 174 : :
# 175 : : const std::vector<bool>& GetAsmap() const;
# 176 : :
# 177 : : /** Test-only function
# 178 : : * Find the address record in AddrMan and return information about its
# 179 : : * position.
# 180 : : * @param[in] addr The address record to look up.
# 181 : : * @return Information about the address record in AddrMan
# 182 : : * or nullopt if address is not found.
# 183 : : */
# 184 : : std::optional<AddressPosition> FindAddressEntry(const CAddress& addr);
# 185 : : };
# 186 : :
# 187 : : #endif // BITCOIN_ADDRMAN_H
|