discv4/packet_factory.cpp¶
Namespaces¶
| Name |
|---|
| discv4 |
Source code¶
// packet_factory.cpp
#include "discv4/packet_factory.hpp"
#include <secp256k1.h>
#include <secp256k1_recovery.h>
#include <boost/outcome/try.hpp>
#include "discv4/discv4_constants.hpp"
#include "discv4/discv4_ping.hpp"
#include "discv4/discv4_pong.hpp"
#include <nil/crypto3/hash/algorithm/hash.hpp>
#include <nil/crypto3/hash/keccak.hpp>
namespace discv4 {
PacketResult PacketFactory::SendPingAndWait(
asio::io_context& io,
const std::string& fromIp, uint16_t fUdp, uint16_t fTcp,
const std::string& toIp, uint16_t tUdp, uint16_t tTcp,
const std::vector<uint8_t>& privKeyHex,
SendCallback callback,
uint16_t* boundPort )
{
// Create socket
udp::socket socket( io, udp::v4() );
socket.set_option( udp::socket::reuse_address( true ) );
socket.bind( udp::endpoint( boost::asio::ip::address_v4::any(), 0 ) );
const auto localPort = socket.local_endpoint().port();
if ( boundPort != nullptr )
{
*boundPort = localPort;
}
std::cout << "SendPingAndWait bound local UDP port: " << localPort << "\n";
auto ping = std::make_unique<discv4_ping>( fromIp, fUdp, fTcp, toIp, tUdp, tTcp );
std::vector<uint8_t> msg;
auto signResult = SignAndBuildPacket( ping.get(), privKeyHex, msg );
if ( !signResult )
{
return outcome::failure( signResult.error() );
}
// Send
udp::endpoint target( boost::asio::ip::address_v4::from_string( toIp ), tUdp );
udp::endpoint sender;
SendPacket( socket, msg, target );
// Receive async
std::array<uint8_t, kUdpBufferSize> arrayBuffer;
boost::system::error_code ec;
size_t bytesTransferred = socket.receive_from( boost::asio::buffer( arrayBuffer ), sender, 0, ec );
if ( !ec )
{
std::vector<uint8_t> data( arrayBuffer.data(), arrayBuffer.data() + bytesTransferred );
callback( data, sender );
}
// Run io_context (in a loop)
io.run();
return outcome::success();
}
PacketResult PacketFactory::SignAndBuildPacket(
discv4_packet* packet,
const std::vector<uint8_t>& privKeyHex,
std::vector<uint8_t>& out )
{
if ( packet == nullptr )
{
return outcome::failure( PacketError::kNullPacket );
}
auto payload = packet->RlpPayload();
// Hash with keccak-256
std::array<uint8_t, kWireHashSize> hash = discv4_packet::Keccak256( payload );
// Sign with secp256k1
auto ctx = secp256k1_context_create( SECP256K1_CONTEXT_SIGN );
secp256k1_ecdsa_recoverable_signature sig;
int success = secp256k1_ecdsa_sign_recoverable( ctx, &sig, hash.data(), privKeyHex.data(),
secp256k1_nonce_function_rfc6979, nullptr );
if ( !success )
{
secp256k1_context_destroy( ctx );
return outcome::failure( PacketError::kSignFailure );
}
std::array<uint8_t, kWireCompactSigSize> serialized{};
int recid;
secp256k1_ecdsa_recoverable_signature_serialize_compact( ctx, serialized.data(), &recid, &sig );
secp256k1_context_destroy( ctx );
out.reserve( kWireHashSize + kWireSigSize + payload.size() );
out.insert( out.end(), kWireHashSize, 0 ); // Skip for hash for whole out message
out.insert( out.end(), serialized.begin(), serialized.end() );
out.push_back( recid );
out.insert( out.end(), payload.begin(), payload.end() );
// Hash for whole out message
auto payloadHash = nil::crypto3::hash<nil::crypto3::hashes::keccak_1600<256>>( out.begin() + kWireHashSize, out.end() );
std::array<uint8_t, kWireHashSize> payloadArray = payloadHash;
std::copy( payloadArray.begin(), payloadArray.end(), out.begin() );
return outcome::success();
}
void PacketFactory::SendPacket(
asio::ip::udp::socket& socket,
const std::vector<uint8_t>& msg,
const udp::endpoint& target )
{
socket.send_to( boost::asio::buffer( msg ), target );
}
} // namespace discv4
Updated on 2026-04-13 at 23:22:46 -0700