Skip to content

eth/eth_handshake_guard.cpp

Namespaces

Name
eth

Functions

Name
std::optional< uint8_t > NormalizeEthWireMessageId(uint8_t wire_message_id, uint8_t negotiated_eth_offset)
Return the ETH-local message id for a wire-level message.
uint64_t ExtractLatestBlockNumber(const StatusMessage & status)
Return the latest block number from a validated ETH Status message.
rlp::outcome::result< StatusMessage, StatusValidationError, rlp::outcome::policy::all_narrow > DecodeValidatedStatusMessage(const rlpx::protocol::Message & message, uint8_t negotiated_eth_offset, uint8_t negotiated_eth_version, uint64_t network_id, const Hash256 & genesis_hash, const std::vector< EthMessageSchema > & eth_message_schemas ={})
Decode and validate an inbound ETH Status message.
HandshakeMessageDisposition HandleEthHandshakeMessage(const rlpx::protocol::Message & message, uint8_t negotiated_eth_offset, uint8_t negotiated_eth_version, uint64_t network_id, const Hash256 & genesis_hash, bool & status_received)
Process one inbound ETH handshake-phase message.

Functions Documentation

function NormalizeEthWireMessageId

std::optional< uint8_t > NormalizeEthWireMessageId(
    uint8_t wire_message_id,
    uint8_t negotiated_eth_offset
)

Return the ETH-local message id for a wire-level message.

Parameters:

  • wire_message_id Wire-level RLPx message id.
  • negotiated_eth_offset Negotiated ETH wire offset.

Return: ETH-local message id if the wire id belongs to ETH; std::nullopt otherwise.

function ExtractLatestBlockNumber

uint64_t ExtractLatestBlockNumber(
    const StatusMessage & status
)

Return the latest block number from a validated ETH Status message.

Parameters:

  • status Decoded ETH Status message.

Return: Latest block number for ETH/69, or 0 for earlier layouts.

function DecodeValidatedStatusMessage

rlp::outcome::result< StatusMessage, StatusValidationError, rlp::outcome::policy::all_narrow > DecodeValidatedStatusMessage(
    const rlpx::protocol::Message & message,
    uint8_t negotiated_eth_offset,
    uint8_t negotiated_eth_version,
    uint64_t network_id,
    const Hash256 & genesis_hash,
    const std::vector< EthMessageSchema > & eth_message_schemas ={}
)

Decode and validate an inbound ETH Status message.

Parameters:

  • message Inbound wire-level RLPx message.
  • negotiated_eth_offset Negotiated ETH wire offset.
  • negotiated_eth_version Negotiated ETH version.
  • network_id Expected local network identifier.
  • genesis_hash Expected local genesis hash.

Return: Decoded valid ETH Status message, or a validation/decode error.

function HandleEthHandshakeMessage

HandshakeMessageDisposition HandleEthHandshakeMessage(
    const rlpx::protocol::Message & message,
    uint8_t negotiated_eth_offset,
    uint8_t negotiated_eth_version,
    uint64_t network_id,
    const Hash256 & genesis_hash,
    bool & status_received
)

Process one inbound ETH handshake-phase message.

Parameters:

  • message Inbound wire-level RLPx message.
  • negotiated_eth_offset Negotiated ETH wire offset.
  • negotiated_eth_version Negotiated ETH version.
  • network_id Expected local network identifier.
  • genesis_hash Expected local genesis hash.
  • status_received Whether a valid remote ETH Status was already accepted.

Return: Disposition indicating whether the message was ignored, accepted, or rejected.

Source code

// Copyright 2026 Genius Ventures, Inc.
// SPDX-License-Identifier: MIT

#include <eth/eth_handshake_guard.hpp>
#include <eth/messages.hpp>

namespace eth {

std::optional<uint8_t> NormalizeEthWireMessageId(
    uint8_t wire_message_id,
    uint8_t negotiated_eth_offset) noexcept
{
    if (wire_message_id < negotiated_eth_offset)
    {
        return std::nullopt;
    }

    return static_cast<uint8_t>(wire_message_id - negotiated_eth_offset);
}

uint64_t ExtractLatestBlockNumber(const StatusMessage& status) noexcept
{
    return std::visit([](const auto& message) -> uint64_t
    {
        if constexpr (std::is_same_v<std::decay_t<decltype(message)>, StatusMessage69>)
        {
            return message.latest_block;
        }
        return 0;
    }, status);
}

rlp::outcome::result<StatusMessage, StatusValidationError, rlp::outcome::policy::all_narrow>
DecodeValidatedStatusMessage(
    const rlpx::protocol::Message& message,
    uint8_t                        negotiated_eth_offset,
    uint8_t                        negotiated_eth_version,
    uint64_t                       network_id,
    const Hash256&                 genesis_hash,
    const std::vector<EthMessageSchema>& eth_message_schemas) noexcept
{
    const auto eth_id = NormalizeEthWireMessageId(message.id, negotiated_eth_offset);
    if (!eth_id.has_value() || *eth_id != protocol::kStatusMessageId)
    {
        return rlp::outcome::failure(StatusValidationError::kProtocolVersionMismatch);
    }

    const rlp::ByteView payload(message.payload.data(), message.payload.size());
    const auto decoded = eth_message_schemas.empty()
        ? protocol::decode_status(payload)
        : protocol::decode_status(payload, eth_message_schemas);
    if (!decoded)
    {
        return rlp::outcome::failure(StatusValidationError::kProtocolVersionMismatch);
    }

    const auto valid = ValidateRemoteStatusMessage(
        decoded.value(),
        negotiated_eth_version,
        network_id,
        genesis_hash);
    if (!valid)
    {
        return rlp::outcome::failure(valid.error());
    }

    return decoded.value();
}

HandshakeMessageDisposition HandleEthHandshakeMessage(
    const rlpx::protocol::Message& message,
    uint8_t                        negotiated_eth_offset,
    uint8_t                        negotiated_eth_version,
    uint64_t                       network_id,
    const Hash256&                 genesis_hash,
    bool&                          status_received) noexcept
{
    const auto eth_id = NormalizeEthWireMessageId(message.id, negotiated_eth_offset);
    if (!eth_id.has_value())
    {
        return HandshakeMessageDisposition::kIgnored;
    }

    if (*eth_id != protocol::kStatusMessageId)
    {
        if (!status_received)
        {
            return HandshakeMessageDisposition::kRejected;
        }
        return HandshakeMessageDisposition::kIgnored;
    }

    const auto decoded = DecodeValidatedStatusMessage(
        message,
        negotiated_eth_offset,
        negotiated_eth_version,
        network_id,
        genesis_hash);
    if (!decoded)
    {
        return HandshakeMessageDisposition::kRejected;
    }

    status_received = true;
    return HandshakeMessageDisposition::kAcceptedStatus;
}

} // namespace eth

Updated on 2026-06-05 at 17:22:19 -0700