discv4/discv4_enr_response.cpp
Namespaces
Attributes
|
Name |
| std::array< uint8_t, 3U > |
kEthKey |
Attributes Documentation
variable kEthKey
static std::array< uint8_t, 3U > kEthKey { 0x65U, 0x74U, 0x68U };
Source code
// Copyright 2025 GeniusVentures
// SPDX-License-Identifier: Apache-2.0
#include "discv4/discv4_enr_response.hpp"
#include "discv4/discv4_constants.hpp"
namespace discv4 {
// ASCII bytes for the ENR key "eth" (go-ethereum eth/protocols/eth/discovery.go).
static constexpr std::array<uint8_t, 3U> kEthKey{ 0x65U, 0x74U, 0x68U };
rlp::Result<discv4_enr_response> discv4_enr_response::Parse( rlp::ByteView raw ) noexcept
{
if ( raw.size() <= kWireHeaderSize )
{
return rlp::DecodingError::kInputTooShort;
}
if ( raw[kWirePacketTypeOffset] != kPacketTypeEnrResponse )
{
return rlp::DecodingError::kUnexpectedString;
}
rlp::ByteView payload( raw.data() + kWireHeaderSize, raw.size() - kWireHeaderSize );
rlp::RlpDecoder decoder( payload );
BOOST_OUTCOME_TRY( bool is_list, decoder.IsList() );
if ( !is_list )
{
return rlp::DecodingError::kUnexpectedString;
}
BOOST_OUTCOME_TRY( size_t outer_len, decoder.ReadListHeaderBytes() );
(void)outer_len;
discv4_enr_response response;
BOOST_OUTCOME_TRY( decoder.read( response.request_hash ) );
BOOST_OUTCOME_TRY( auto record_header, decoder.PeekHeader() );
const size_t record_total = record_header.header_size_bytes + record_header.payload_size_bytes;
if ( decoder.Remaining().size() < record_total )
{
return rlp::DecodingError::kInputTooShort;
}
response.record_rlp.assign(
decoder.Remaining().data(),
decoder.Remaining().data() + record_total );
BOOST_OUTCOME_TRY( decoder.SkipItem() );
return response;
}
rlp::Result<ForkId> discv4_enr_response::ParseEthForkId() const noexcept
{
if ( record_rlp.empty() )
{
return rlp::DecodingError::kInputTooShort;
}
rlp::ByteView record_view( record_rlp.data(), record_rlp.size() );
rlp::RlpDecoder record_dec( record_view );
// ENR record: RLP([signature, seq, k0, v0, k1, v1, ...])
BOOST_OUTCOME_TRY( bool is_list, record_dec.IsList() );
if ( !is_list )
{
return rlp::DecodingError::kUnexpectedString;
}
BOOST_OUTCOME_TRY( size_t record_len, record_dec.ReadListHeaderBytes() );
(void)record_len;
// Skip signature (first element).
BOOST_OUTCOME_TRY( record_dec.SkipItem() );
// Skip sequence number (second element).
BOOST_OUTCOME_TRY( record_dec.SkipItem() );
// Iterate key/value pairs looking for key == "eth".
while ( !record_dec.IsFinished() )
{
rlp::Bytes key_bytes;
BOOST_OUTCOME_TRY( record_dec.read( key_bytes ) );
if ( key_bytes.size() == kEthKey.size() &&
std::equal( key_bytes.begin(), key_bytes.end(), kEthKey.begin() ) )
{
// Value: RLP(enrEntry) = RLP([ [hash4, next_uint64] ])
// Outer list = enrEntry fields; inner list = ForkId fields.
BOOST_OUTCOME_TRY( bool val_is_list, record_dec.IsList() );
if ( !val_is_list )
{
return rlp::DecodingError::kUnexpectedString;
}
BOOST_OUTCOME_TRY( size_t outer_val_len, record_dec.ReadListHeaderBytes() );
(void)outer_val_len;
BOOST_OUTCOME_TRY( bool fork_is_list, record_dec.IsList() );
if ( !fork_is_list )
{
return rlp::DecodingError::kUnexpectedString;
}
BOOST_OUTCOME_TRY( size_t fork_len, record_dec.ReadListHeaderBytes() );
(void)fork_len;
ForkId fork_id;
BOOST_OUTCOME_TRY( record_dec.read( fork_id.hash ) );
BOOST_OUTCOME_TRY( record_dec.read( fork_id.next ) );
return fork_id;
}
// Not "eth" — skip the value and continue.
BOOST_OUTCOME_TRY( record_dec.SkipItem() );
}
// `eth` key not present in record.
return rlp::DecodingError::kUnexpectedString;
}
} // namespace discv4
Updated on 2026-04-13 at 23:22:46 -0700