Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,7 @@ tests/fixtures/**/*.json
ci-build*

# Internal docs
internal-docs*
internal-docs*

# External clients
external-clients*
24 changes: 3 additions & 21 deletions include/lantern/networking/reqresp_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,9 @@
#include "libp2p/stream.h"
#include "peer_id/peer_id.h"

#define LANTERN_REQRESP_STATUS_PROTOCOL_SNAPPY "/leanconsensus/req/status/1/ssz_snappy"
#define LANTERN_REQRESP_STATUS_PROTOCOL_LEGACY "/leanconsensus/req/status/1/"
#define LANTERN_REQRESP_BLOCKS_BY_ROOT_PROTOCOL_SNAPPY "/leanconsensus/req/lean_blocks_by_root/1/ssz_snappy"
#define LANTERN_REQRESP_BLOCKS_BY_ROOT_PROTOCOL_LEGACY "/leanconsensus/req/blocks_by_root/1/ssz_snappy"
#define LANTERN_REQRESP_BLOCKS_BY_ROOT_PROTOCOL_BARE "/leanconsensus/req/blocks_by_root/1/"
#define LANTERN_REQRESP_STATUS_PROTOCOL LANTERN_REQRESP_STATUS_PROTOCOL_SNAPPY
#define LANTERN_REQRESP_BLOCKS_BY_ROOT_PROTOCOL LANTERN_REQRESP_BLOCKS_BY_ROOT_PROTOCOL_SNAPPY
/* Canonical protocol IDs from LeanSpec (tools/leanSpec/src/lean_spec/subspecs/networking/reqresp/message.py) */
#define LANTERN_REQRESP_STATUS_PROTOCOL "/leanconsensus/req/status/1/"
#define LANTERN_REQRESP_BLOCKS_BY_ROOT_PROTOCOL "/leanconsensus/req/blocks_by_root/1/"
#define LANTERN_REQRESP_STATUS_PREVIEW_BYTES 256u
#define LANTERN_REQRESP_MAX_CHUNK_BYTES (1u << 22)
#define LANTERN_REQRESP_MAX_CONTEXT_BYTES (1u << 20)
Expand Down Expand Up @@ -56,10 +52,7 @@ enum lantern_reqresp_protocol_kind {
};

#define LANTERN_STATUS_PROTOCOL_ID LANTERN_REQRESP_STATUS_PROTOCOL
#define LANTERN_STATUS_PROTOCOL_ID_LEGACY LANTERN_REQRESP_STATUS_PROTOCOL_LEGACY
#define LANTERN_BLOCKS_BY_ROOT_PROTOCOL_ID LANTERN_REQRESP_BLOCKS_BY_ROOT_PROTOCOL
#define LANTERN_BLOCKS_BY_ROOT_PROTOCOL_ID_LEGACY LANTERN_REQRESP_BLOCKS_BY_ROOT_PROTOCOL_LEGACY
#define LANTERN_BLOCKS_BY_ROOT_PROTOCOL_ID_BARE LANTERN_REQRESP_BLOCKS_BY_ROOT_PROTOCOL_BARE
#define LANTERN_STATUS_PREVIEW_BYTES LANTERN_REQRESP_STATUS_PREVIEW_BYTES

struct libp2p_host;
Expand Down Expand Up @@ -94,14 +87,10 @@ struct lantern_reqresp_service {
struct libp2p_host *host;
struct lantern_reqresp_service_callbacks callbacks;
struct libp2p_protocol_server *status_server;
struct libp2p_protocol_server *status_server_legacy;
struct libp2p_protocol_server *blocks_server;
struct libp2p_protocol_server *blocks_server_legacy;
struct libp2p_protocol_server *blocks_server_bare;
struct libp2p_subscription *event_subscription;
int lock_initialized;
pthread_mutex_t lock;
struct lantern_string_list legacy_peers;
};

#ifdef __cplusplus
Expand All @@ -114,13 +103,6 @@ int lantern_reqresp_service_request_status(
struct lantern_reqresp_service *service,
const peer_id_t *peer_id,
const char *peer_id_text);
void lantern_reqresp_service_hint_peer_legacy(
struct lantern_reqresp_service *service,
const char *peer_id_text,
bool legacy);
int lantern_reqresp_service_peer_prefers_legacy(
const struct lantern_reqresp_service *service,
const char *peer_id_text);
int lantern_reqresp_service_start(
struct lantern_reqresp_service *service,
const struct lantern_reqresp_service_config *config);
Expand Down
26 changes: 2 additions & 24 deletions src/core/client_network.c
Original file line number Diff line number Diff line change
Expand Up @@ -359,38 +359,16 @@ void request_status_now(struct lantern_client *client, const peer_id_t *peer, co


/**
* Seed reqresp service with peer legacy mode hints from genesis config.
* Seed reqresp service with peer mode hints from genesis config.
*
* @param client Client instance
*
* @note Currently a no-op as only canonical protocol is supported.
* @note Thread safety: This function is thread-safe
*/
void lantern_client_seed_reqresp_peer_modes(struct lantern_client *client)
{
if (!client)
{
return;
}
#if defined(LANTERN_REQRESP_STATUS_PROTOCOL_LEGACY) \
|| defined(LANTERN_REQRESP_BLOCKS_BY_ROOT_PROTOCOL_LEGACY)
const struct lantern_validator_config *config = &client->genesis.validator_config;
if (!config || !config->entries)
{
return;
}
for (size_t i = 0; i < config->count; ++i)
{
const struct lantern_validator_config_entry *entry = &config->entries[i];
if (!entry->peer_id_text || !entry->peer_id_text[0])
{
continue;
}
int legacy = (entry->client_kind == LANTERN_VALIDATOR_CLIENT_QLEAN);
lantern_reqresp_service_hint_peer_legacy(&client->reqresp, entry->peer_id_text, legacy);
}
#else
(void)client;
#endif
}


Expand Down
5 changes: 2 additions & 3 deletions src/core/client_network_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,12 @@ struct lantern_peer_status_entry
};

/**
* Blocks-by-root protocol variants for fallback handling.
* Blocks-by-root protocol variant.
* Only the canonical protocol is supported per LeanSpec.
*/
enum lantern_blocks_req_variant
{
LANTERN_BLOCKS_REQ_VARIANT_PRIMARY = 0,
LANTERN_BLOCKS_REQ_VARIANT_LEGACY_SNAPPY = 1,
LANTERN_BLOCKS_REQ_VARIANT_BARE = 2,
};


Expand Down
52 changes: 16 additions & 36 deletions src/core/client_reqresp_blocks.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,46 +95,31 @@ static bool blocks_next_variant(
enum lantern_blocks_req_variant current,
enum lantern_blocks_req_variant *out_next)
{
if (!out_next)
{
return false;
}
switch (current)
{
case LANTERN_BLOCKS_REQ_VARIANT_PRIMARY:
*out_next = LANTERN_BLOCKS_REQ_VARIANT_LEGACY_SNAPPY;
return true;
case LANTERN_BLOCKS_REQ_VARIANT_LEGACY_SNAPPY:
*out_next = LANTERN_BLOCKS_REQ_VARIANT_BARE;
return true;
default:
break;
}
(void)current;
(void)out_next;
/* No fallback variants - only canonical protocol supported */
return false;
}

static const char *blocks_protocol_id_for_variant(enum lantern_blocks_req_variant variant)
{
switch (variant)
{
case LANTERN_BLOCKS_REQ_VARIANT_LEGACY_SNAPPY:
return LANTERN_BLOCKS_BY_ROOT_PROTOCOL_ID_LEGACY;
case LANTERN_BLOCKS_REQ_VARIANT_BARE:
return LANTERN_BLOCKS_BY_ROOT_PROTOCOL_ID_BARE;
case LANTERN_BLOCKS_REQ_VARIANT_PRIMARY:
default:
return LANTERN_BLOCKS_BY_ROOT_PROTOCOL_ID;
}
(void)variant;
/* Only canonical protocol ID supported */
return LANTERN_BLOCKS_BY_ROOT_PROTOCOL_ID;
}

static bool blocks_variant_uses_raw_snappy(enum lantern_blocks_req_variant variant)
{
return variant != LANTERN_BLOCKS_REQ_VARIANT_PRIMARY;
(void)variant;
/* Always use framed snappy (canonical format) */
return false;
}

static bool blocks_variant_is_legacy(enum lantern_blocks_req_variant variant)
{
return variant != LANTERN_BLOCKS_REQ_VARIANT_PRIMARY;
(void)variant;
/* No legacy variants */
return false;
}


Expand Down Expand Up @@ -358,7 +343,7 @@ static void *block_request_worker(void *arg)
request.roots.items[0] = ctx->root;

bool use_raw_snappy = blocks_variant_uses_raw_snappy(ctx->variant);
size_t raw_size = sizeof(uint32_t) + (request.roots.length * LANTERN_ROOT_SIZE);
size_t raw_size = request.roots.length * LANTERN_ROOT_SIZE;
raw_request = (uint8_t *)malloc(raw_size > 0 ? raw_size : 1u);
if (!raw_request)
{
Expand Down Expand Up @@ -786,10 +771,6 @@ static void *block_request_worker(void *arg)
{
free(initial_chunk);
}
if (request_success && ctx->variant != LANTERN_BLOCKS_REQ_VARIANT_PRIMARY && ctx->client && ctx->peer_text[0])
{
lantern_reqresp_service_hint_peer_legacy(&ctx->client->reqresp, ctx->peer_text, true);
}
free(response);
free(payload);
free(raw_request);
Expand Down Expand Up @@ -1087,7 +1068,7 @@ static int schedule_blocks_request_variant(
* @param client Client instance
* @param peer_id_text Peer ID string
* @param root Block root to request
* @param use_legacy True to use legacy protocol
* @param use_legacy Unused (only canonical protocol supported)
* @return 0 on success
* @return LANTERN_CLIENT_ERR_INVALID_PARAM if any parameter is NULL, the peer ID is invalid, or the root is zero
* @return LANTERN_CLIENT_ERR_ALLOC if allocation fails
Expand All @@ -1101,7 +1082,6 @@ int lantern_client_schedule_blocks_request(
const LanternRoot *root,
bool use_legacy)
{
enum lantern_blocks_req_variant variant =
use_legacy ? LANTERN_BLOCKS_REQ_VARIANT_LEGACY_SNAPPY : LANTERN_BLOCKS_REQ_VARIANT_PRIMARY;
return schedule_blocks_request_variant(client, peer_id_text, root, variant);
(void)use_legacy; /* Only canonical protocol supported */
return schedule_blocks_request_variant(client, peer_id_text, root, LANTERN_BLOCKS_REQ_VARIANT_PRIMARY);
}
13 changes: 3 additions & 10 deletions src/core/client_reqresp_stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,23 +181,16 @@ static void init_peer_log_metadata(

/**
* @brief Records peer legacy framing preference.
* @note Currently a no-op as only canonical protocol is supported.
*/
static void hint_peer_legacy_framing(
struct lantern_reqresp_service *service,
const char *peer_text,
bool is_legacy)
{
if (!service || !peer_text || peer_text[0] == '\0')
{
return;
}

#if defined(LANTERN_REQRESP_STATUS_PROTOCOL_LEGACY) \
|| defined(LANTERN_REQRESP_BLOCKS_BY_ROOT_PROTOCOL_LEGACY)
lantern_reqresp_service_hint_peer_legacy(service, peer_text, is_legacy ? 1 : 0);
#else
(void)service;
(void)peer_text;
(void)is_legacy;
#endif
}


Expand Down
52 changes: 11 additions & 41 deletions src/networking/messages.c
Original file line number Diff line number Diff line change
Expand Up @@ -388,65 +388,35 @@ int lantern_network_blocks_by_root_request_encode(
if (req->roots.length > LANTERN_MAX_REQUEST_BLOCKS) {
return -1;
}
/* SSZ container: one variable field (roots list) -> 4‑byte offset + payload */
const uint32_t offset = (uint32_t)sizeof(uint32_t);
size_t roots_bytes = req->roots.length * LANTERN_ROOT_SIZE;
size_t total_bytes = sizeof(uint32_t) + roots_bytes;
if (out_len < total_bytes) {
if (out_len < roots_bytes) {
return -1;
}
/* fixed part */
if (write_u32_le(offset, out, out_len) != 0) {
return -1;
}
/* variable part */
if (roots_bytes > 0) {
if (!req->roots.items) {
return -1;
}
memcpy(out + sizeof(uint32_t), req->roots.items, roots_bytes);
memcpy(out, req->roots.items, roots_bytes);
}
*written = total_bytes;
*written = roots_bytes;
return 0;
}

int lantern_network_blocks_by_root_request_decode(
LanternBlocksByRootRequest *req,
const uint8_t *data,
size_t data_len) {
if (!req || (!data && data_len > 0)) {
if (!req) {
return -1;
}

/* New-format decode: expect 4‑byte offset to variable section */
if (data_len >= sizeof(uint32_t)) {
uint32_t offset = 0;
if (read_u32_le(data, data_len, &offset) != 0) {
return -1;
}
if (offset >= sizeof(uint32_t) && offset <= data_len && (offset % sizeof(uint32_t)) == 0) {
size_t roots_bytes = data_len - offset;
if (roots_bytes % LANTERN_ROOT_SIZE != 0) {
return -1;
}
size_t count = roots_bytes / LANTERN_ROOT_SIZE;
if (count > LANTERN_MAX_REQUEST_BLOCKS) {
return -1;
}
if (lantern_root_list_resize(&req->roots, (uint32_t)count) != 0) {
return -1;
}
if (count > 0) {
if (!req->roots.items) {
return -1;
}
memcpy(req->roots.items, data + offset, roots_bytes);
}
return 0;
}
if (data_len == 0) {
return lantern_root_list_resize(&req->roots, 0) == 0 ? 0 : -1;
}
if (!data) {
return -1;
}

/* Legacy fallback (no offset) */
/* Canonical SSZ list encoding: raw concatenated roots. */
if (data_len % LANTERN_ROOT_SIZE != 0) {
return -1;
}
Expand Down Expand Up @@ -479,7 +449,7 @@ int lantern_network_blocks_by_root_request_encode_snappy(
if (!req || !out || !written) {
return -1;
}
size_t raw_size = sizeof(uint32_t) + (req->roots.length * LANTERN_ROOT_SIZE);
size_t raw_size = req->roots.length * LANTERN_ROOT_SIZE;
uint8_t *raw = alloc_scratch(raw_size);
if (!raw) {
return -1;
Expand Down
Loading