discv4/discv4_client.hpp¶
Namespaces¶
| Name |
|---|
| discv4 |
Classes¶
| Name | |
|---|---|
| struct | discv4::DiscoveredPeer |
| struct | discv4::discv4Config |
| class | discv4::discv4_client Discovery v4 protocol client. |
Types¶
| Name | |
|---|---|
| using asio::ip::udp | udp |
| using std::array< uint8_t, 64 > | NodeId |
| using std::function< void(const DiscoveredPeer &)> | PeerDiscoveredCallback |
| using std::function< void(const std::string &)> | ErrorCallback |
| using std::shared_ptr< spdlog::logger > | Logger |
Functions¶
| Name | |
|---|---|
| std::shared_ptr< spdlog::logger > | createLogger(const std::string & tag, const std::string & basepath ="") Create a logger instance. |
Types Documentation¶
using udp¶
using NodeId¶
using PeerDiscoveredCallback¶
using ErrorCallback¶
using Logger¶
Functions Documentation¶
function createLogger¶
std::shared_ptr< spdlog::logger > createLogger(
const std::string & tag,
const std::string & basepath =""
)
Create a logger instance.
Parameters:
- tag Tagging name for identifying logger.
- basepath Optional base path for log output (platform dependent).
Return: Logger object.
Source code¶
// Copyright 2025 GeniusVentures
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include "discv4/discv4_pong.hpp"
#include "discv4/discv4_enr_request.hpp"
#include "discv4/discv4_enr_response.hpp"
#include "discv4/discv4_constants.hpp"
#include "discv4/discv4_error.hpp"
#include <rlp/result.hpp>
#include <rlpx/rlpx_error.hpp>
#include <base/rlp-logger.hpp>
#include <array>
#include <chrono>
#include <functional>
#include <optional>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace discv4 {
using rlp::base::Logger;
using rlp::base::createLogger;
namespace asio = boost::asio;
using udp = asio::ip::udp;
// Node identifier (64 bytes - uncompressed secp256k1 public key)
using NodeId = std::array<uint8_t, 64>;
// Discovered peer information
struct DiscoveredPeer {
NodeId node_id;
std::string ip;
uint16_t udp_port;
uint16_t tcp_port;
std::chrono::steady_clock::time_point last_seen;
std::optional<ForkId> eth_fork_id{};
};
// Discovery client configuration
struct discv4Config {
std::string bind_ip = "0.0.0.0";
uint16_t bind_port = 30303;
uint16_t tcp_port = 30303;
std::array<uint8_t, 32> private_key{}; // secp256k1 private key
NodeId public_key{}; // secp256k1 public key (uncompressed, 64 bytes)
std::chrono::milliseconds ping_timeout{kDefaultPingTimeout};
std::chrono::seconds peer_expiry{kDefaultPeerExpiry}; // 5 minutes
};
// Callback types
using PeerDiscoveredCallback = std::function<void(const DiscoveredPeer&)>;
using ErrorCallback = std::function<void(const std::string&)>;
class discv4_client {
public:
explicit discv4_client(asio::io_context& io_context, const discv4Config& config);
~discv4_client();
// Start discovery process
rlpx::VoidResult start();
// Stop discovery
void stop();
discv4::Result<discv4_pong> ping(
const std::string& ip,
uint16_t port,
const NodeId& node_id,
boost::asio::yield_context yield
);
rlpx::VoidResult find_node(
const std::string& ip,
uint16_t port,
const NodeId& target_id,
boost::asio::yield_context yield
);
discv4::Result<discv4_enr_response> request_enr(
const std::string& ip,
uint16_t port,
boost::asio::yield_context yield
);
// Get list of discovered peers
std::vector<DiscoveredPeer> get_peers() const;
// Set callback for when new peers are discovered
void set_peer_discovered_callback(PeerDiscoveredCallback callback);
// Set error callback
void set_error_callback(ErrorCallback callback);
// Get local node ID
const NodeId& local_node_id() const { return config_.public_key; }
uint16_t bound_port() const noexcept
{
return socket_.local_endpoint().port();
}
private:
// Receive loop
void receive_loop(boost::asio::yield_context yield);
// Handle incoming packet
void handle_packet(const uint8_t* data, size_t length, const udp::endpoint& sender);
// Handle specific packet types
void handle_ping(const uint8_t* data, size_t length, const udp::endpoint& sender);
void handle_pong(const uint8_t* data, size_t length, const udp::endpoint& sender);
void handle_find_node(const uint8_t* data, size_t length, const udp::endpoint& sender);
void handle_neighbours(const uint8_t* data, size_t length, const udp::endpoint& sender);
void handle_enr_request(const uint8_t* data, size_t length, const udp::endpoint& sender);
void handle_enr_response(const uint8_t* data, size_t length, const udp::endpoint& sender);
// Send packet
discv4::Result<void> send_packet(
const std::vector<uint8_t>& packet,
const udp::endpoint& destination,
boost::asio::yield_context yield
);
// Sign packet with ECDSA
discv4::Result<std::vector<uint8_t>> sign_packet(const std::vector<uint8_t>& payload);
// Verify packet signature
discv4::Result<NodeId> verify_packet(const uint8_t* data, size_t length);
// Compute node ID from public key (keccak256 hash)
static NodeId compute_node_id(const std::array<uint8_t, 64>& public_key);
asio::io_context& io_context_;
discv4Config config_;
udp::socket socket_;
Logger logger_ = createLogger("discv4");
// Peer table
mutable std::mutex peers_mutex_;
std::unordered_map<std::string, DiscoveredPeer> peers_; // key: node_id_hex
// Callbacks
PeerDiscoveredCallback peer_callback_;
ErrorCallback error_callback_;
// Running state
std::atomic<bool> running_{false};
// Pending reply entries — one per outstanding PING or FIND_NODE.
// Keyed by reply_key(). All access on the single io_context thread — no mutex needed.
struct PendingReply
{
std::shared_ptr<boost::asio::steady_timer> timer;
std::shared_ptr<discv4_pong> pong;
std::shared_ptr<discv4_enr_response> enr_response;
std::array<uint8_t, kWireHashSize> expected_hash{};
};
std::unordered_map<std::string, PendingReply> pending_replies_;
std::unordered_set<std::string> bonded_set_;
std::unordered_set<std::string> discovered_set_;
static std::string reply_key(const std::string& ip, uint16_t port, uint8_t ptype) noexcept;
void ensure_bond(const std::string& ip, uint16_t port,
boost::asio::yield_context yield) noexcept;
};
} // namespace discv4
Updated on 2026-04-13 at 23:22:46 -0700