Skip to content

eth/eth_handshake.cpp

Namespaces

Name
eth

Functions

Name
rlp::outcome::result< EthStatusHandshakeResult, StatusValidationError, rlp::outcome::policy::all_narrow > PerformEthStatusHandshake(const EthStatusHandshakeStart & start, boost::asio::yield_context yield)
Execute the ETH Status startup handshake for a negotiated ETH session.

Functions Documentation

function PerformEthStatusHandshake

rlp::outcome::result< EthStatusHandshakeResult, StatusValidationError, rlp::outcome::policy::all_narrow > PerformEthStatusHandshake(
    const EthStatusHandshakeStart & start,
    boost::asio::yield_context yield
)

Execute the ETH Status startup handshake for a negotiated ETH session.

Parameters:

  • start Handshake parameters bound to the negotiated ETH session/channel.
  • yield Boost.Asio stackful coroutine context used to await the first ETH message.

Return: ETH-layer handshake result containing the validated remote status.

Source code

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

#include <eth/eth_handshake.hpp>
#include <eth/eth_handshake_guard.hpp>
#include <rlpx/protocol/messages.hpp>

namespace eth {

rlp::outcome::result<EthStatusHandshakeResult, StatusValidationError, rlp::outcome::policy::all_narrow>
PerformEthStatusHandshake(
    const EthStatusHandshakeStart& start,
    boost::asio::yield_context     yield) noexcept
{
    if (!start.channel)
    {
        return rlp::outcome::failure(StatusValidationError::kProtocolVersionMismatch);
    }

    const uint8_t negotiated_eth_version = start.channel->negotiated_eth_version();
    const uint8_t negotiated_eth_offset = start.channel->negotiated_eth_offset();
    if (negotiated_eth_version == 0U || negotiated_eth_offset == 0U)
    {
        return rlp::outcome::failure(StatusValidationError::kProtocolVersionMismatch);
    }

    const auto status = BuildLocalStatusMessage(
        negotiated_eth_version,
        start.network_id,
        start.genesis_hash,
        start.fork_id);

    auto encoded = protocol::encode_status(status);
    if (!encoded)
    {
        return rlp::outcome::failure(StatusValidationError::kProtocolVersionMismatch);
    }

    rlpx::framing::Message status_message{};
    status_message.id = static_cast<uint8_t>(negotiated_eth_offset + protocol::kStatusMessageId);
    status_message.payload = std::move(encoded.value());
    const auto post_result = start.channel->post_message(std::move(status_message));
    if (!post_result)
    {
        return rlp::outcome::failure(StatusValidationError::kProtocolVersionMismatch);
    }

    for (;;)
    {
        auto inbound_result = start.channel->receive_message_with_timeout(
            protocol::kStatusHandshakeTimeout,
            yield);
        if (!inbound_result)
        {
            return rlp::outcome::failure(StatusValidationError::kProtocolVersionMismatch);
        }

        rlpx::protocol::Message inbound_message{};
        inbound_message.id = inbound_result.value().id;
        inbound_message.payload = std::move(inbound_result.value().payload);

        if (inbound_message.id == rlpx::kDisconnectMessageId)
        {
            const auto disconnect = rlpx::protocol::DisconnectMessage::decode(
                rlpx::ByteView(inbound_message.payload.data(), inbound_message.payload.size()));
            if (disconnect && start.remote_disconnect_handler)
            {
                start.remote_disconnect_handler(disconnect.value().reason);
            }
            return rlp::outcome::failure(StatusValidationError::kProtocolVersionMismatch);
        }

        bool status_received = false;
        const auto handshake_disposition = HandleEthHandshakeMessage(
            inbound_message,
            negotiated_eth_offset,
            negotiated_eth_version,
            start.network_id,
            start.genesis_hash,
            status_received);

        if (handshake_disposition == HandshakeMessageDisposition::kAcceptedStatus)
        {
            const auto validated_status = DecodeValidatedStatusMessage(
                inbound_message,
                negotiated_eth_offset,
                negotiated_eth_version,
                start.network_id,
                start.genesis_hash,
                start.eth_message_schemas);
            if (!validated_status)
            {
                return rlp::outcome::failure(validated_status.error());
            }

            EthStatusHandshakeResult result{};
            result.remote_status = validated_status.value();
            return result;
        }

        if (handshake_disposition == HandshakeMessageDisposition::kRejected)
        {
            const auto validated_status = DecodeValidatedStatusMessage(
                inbound_message,
                negotiated_eth_offset,
                negotiated_eth_version,
                start.network_id,
                start.genesis_hash,
                start.eth_message_schemas);
            if (!validated_status)
            {
                return rlp::outcome::failure(validated_status.error());
            }
            return rlp::outcome::failure(StatusValidationError::kProtocolVersionMismatch);
        }
    }
}

} // namespace eth

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