From ca517f2919a28c2a83169ab177d7dce076a3adef Mon Sep 17 00:00:00 2001 From: uink45 <79078981+uink45@users.noreply.github.com> Date: Sun, 24 May 2026 10:50:42 +1000 Subject: [PATCH 1/3] Add fixture_loader test and proof alias handling --- CMakeLists.txt | 10 ++++++ Dockerfile | 2 +- tests/support/fixture_loader.c | 3 ++ tests/unit/test_fixture_loader.c | 58 ++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test_fixture_loader.c diff --git a/CMakeLists.txt b/CMakeLists.txt index df7e5ac..1537446 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -297,6 +297,16 @@ if(LANTERN_BUILD_TESTS) add_test(NAME lantern_signature COMMAND lantern_signature_test) set_tests_properties(lantern_signature PROPERTIES TIMEOUT 3600) + add_executable(lantern_fixture_loader_test tests/unit/test_fixture_loader.c) + target_link_libraries(lantern_fixture_loader_test PRIVATE ${LANTERN_TEST_LINK_LIB}) + target_include_directories( + lantern_fixture_loader_test + PRIVATE + ${PROJECT_SOURCE_DIR} + ${PROJECT_SOURCE_DIR}/external/jsmn + ) + add_test(NAME lantern_fixture_loader COMMAND lantern_fixture_loader_test) + add_executable(lantern_consensus_runtime_test tests/unit/test_consensus_runtime.c) target_link_libraries(lantern_consensus_runtime_test PRIVATE ${LANTERN_TEST_LINK_LIB}) add_test(NAME lantern_consensus_runtime COMMAND lantern_consensus_runtime_test) diff --git a/Dockerfile b/Dockerfile index 3edb744..365f076 100644 --- a/Dockerfile +++ b/Dockerfile @@ -72,7 +72,7 @@ RUN --mount=type=cache,target=/root/.ccache,sharing=locked,id=ccache-${TARGETPLA --mount=type=cache,target=/usr/src/lantern/build,sharing=locked,id=lantern-build-${TARGETPLATFORM} \ echo "LANTERN_FORCE_REBUILD=${LANTERN_FORCE_REBUILD}" \ && cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DLANTERN_GIT_COMMIT="${GIT_COMMIT}" -DLANTERN_GIT_BRANCH="${GIT_BRANCH}" \ - && cmake --build build --target lantern_cli --parallel "$(nproc)" \ + && cmake --build build --target lantern_cli --parallel "$(nproc)" --clean-first \ && (cmake --build build --target lantern_client_test --parallel "$(nproc)" || true) \ && mkdir -p /opt/lantern/bin \ && cp build/lantern_cli /opt/lantern/bin/lantern \ diff --git a/tests/support/fixture_loader.c b/tests/support/fixture_loader.c index d682e00..16535fa 100644 --- a/tests/support/fixture_loader.c +++ b/tests/support/fixture_loader.c @@ -797,6 +797,9 @@ int lantern_fixture_parse_signature_proof( if (proof_data_idx < 0) { proof_data_idx = lantern_fixture_object_get_field(doc, proof_idx, "proof_data"); } + if (proof_data_idx < 0) { + proof_data_idx = lantern_fixture_object_get_field(doc, proof_idx, "proof"); + } if (proof_data_idx < 0) { return -1; } diff --git a/tests/unit/test_fixture_loader.c b/tests/unit/test_fixture_loader.c new file mode 100644 index 0000000..45e0ea2 --- /dev/null +++ b/tests/unit/test_fixture_loader.c @@ -0,0 +1,58 @@ +#include "tests/support/fixture_loader.h" + +#include +#include +#include + +#define CHECK(cond) \ + do { \ + if (!(cond)) { \ + fprintf(stderr, "check failed: %s (%s:%d)\n", #cond, __FILE__, __LINE__); \ + abort(); \ + } \ + } while (0) + +static char *copy_text(const char *text) { + size_t len = strlen(text); + char *copy = (char *)malloc(len + 1u); + CHECK(copy != NULL); + memcpy(copy, text, len + 1u); + return copy; +} + +static void expect_lstar_signature_proof_alias(void) { + static const char json[] = + "{" + "\"participants\":{\"data\":[false,true,true]}," + "\"proof\":{\"data\":\"0x01020304\"}" + "}"; + + struct lantern_fixture_document doc; + LanternAggregatedSignatureProof proof; + + memset(&doc, 0, sizeof(doc)); + lantern_aggregated_signature_proof_init(&proof); + + CHECK(lantern_fixture_document_init(&doc, copy_text(json)) == 0); + CHECK(lantern_fixture_parse_signature_proof(&doc, 0, &proof) == 0); + + CHECK(proof.participants.bit_length == 3u); + CHECK(!lantern_bitlist_get(&proof.participants, 0u)); + CHECK(lantern_bitlist_get(&proof.participants, 1u)); + CHECK(lantern_bitlist_get(&proof.participants, 2u)); + + CHECK(proof.proof_data.length == 4u); + CHECK(proof.proof_data.data != NULL); + CHECK(proof.proof_data.data[0] == 0x01u); + CHECK(proof.proof_data.data[1] == 0x02u); + CHECK(proof.proof_data.data[2] == 0x03u); + CHECK(proof.proof_data.data[3] == 0x04u); + + lantern_aggregated_signature_proof_reset(&proof); + lantern_fixture_document_reset(&doc); +} + +int main(void) { + expect_lstar_signature_proof_alias(); + return 0; +} From d7ab3e966edace318c0e74ebf31f1bb4c9c3de5c Mon Sep 17 00:00:00 2001 From: uink45 <79078981+uink45@users.noreply.github.com> Date: Sun, 24 May 2026 21:43:16 +1000 Subject: [PATCH 2/3] Bump c-lean-libp2p for gossipsub v1.2 IDONTWANT compatibility Picks up Pier-Two/c-lean-libp2p#18, which lets lantern interop with peers running gossipsub v1.2 (qlean, ream, others). Two changes upstream: - Decode incoming IDONTWANT control frames on any negotiated version rather than aborting RPC body decode with UNSUPPORTED_VERSION. The encoder remains strict: lantern only emits IDONTWANT on v1.2 streams. - Drive gossipsub stream_read on any readable event regardless of stream direction, since peers may deliver readable traffic on the outbound stream too. Resolves the lantern+qlean (and likely other lantern+vN clients) finality stall reproduced in hive client-interop and locally with 1 lantern + 2 qlean. --- external/c-lean-libp2p | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/c-lean-libp2p b/external/c-lean-libp2p index 2e0bb8c..7850c36 160000 --- a/external/c-lean-libp2p +++ b/external/c-lean-libp2p @@ -1 +1 @@ -Subproject commit 2e0bb8cc49f354a082af34762f7e830521de2116 +Subproject commit 7850c367e511f7185c3ef42a6db5ebc41cbd5b2b From 9063851ebb1e14c224e226194d3cbfe3433b92e4 Mon Sep 17 00:00:00 2001 From: uink45 <79078981+uink45@users.noreply.github.com> Date: Sun, 24 May 2026 21:46:36 +1000 Subject: [PATCH 3/3] Add idle-status sync test; adjust includes and flag --- cmake/Dependencies.cmake | 2 +- src/core/client_reqresp.c | 2 +- tests/unit/test_client_pending.c | 55 +++++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake index 7cac17f..587b5ca 100644 --- a/cmake/Dependencies.cmake +++ b/cmake/Dependencies.cmake @@ -181,7 +181,7 @@ function(_lantern_define_c_leanvm_xmss_variant target_name source_dir cargo_targ set_target_properties(${target_name} PROPERTIES IMPORTED_LOCATION "${c_leanvm_xmss_output}" - INTERFACE_INCLUDE_DIRECTORIES "${header_dir}" + INTERFACE_INCLUDE_DIRECTORIES "${header_dir};${source_dir}/include" ) if(C_XMSS_TEST_CONFIG) set_target_properties(${target_name} diff --git a/src/core/client_reqresp.c b/src/core/client_reqresp.c index 405ca3d..54abd6b 100644 --- a/src/core/client_reqresp.c +++ b/src/core/client_reqresp.c @@ -965,7 +965,7 @@ static void lantern_client_peer_status_update( true, network_finalized_slot, true, - false); + true); } diff --git a/tests/unit/test_client_pending.c b/tests/unit/test_client_pending.c index 6d0bee1..80d703a 100644 --- a/tests/unit/test_client_pending.c +++ b/tests/unit/test_client_pending.c @@ -987,12 +987,14 @@ static int test_idle_status_triggers_syncing_before_gossip_backfill(void) status.head.root = child_root; status.head.slot = client.state.slot; status.finalized = client.state.latest_finalized; + status.finalized.slot = client.state.slot + 1u; + client_test_fill_root(&status.finalized.root, 0x55u); if (reqresp_handle_status(&client, &status, peer_id) != LANTERN_CLIENT_OK) { fprintf(stderr, "peer status update failed\n"); goto cleanup; } if (client.sync_state != LANTERN_SYNC_STATE_SYNCING) { - fprintf(stderr, "first peer status should move IDLE to SYNCING\n"); + fprintf(stderr, "peer status finalized ahead should keep sync incomplete\n"); goto cleanup; } @@ -1019,6 +1021,54 @@ static int test_idle_status_triggers_syncing_before_gossip_backfill(void) return rc; } +static int test_idle_status_at_known_head_completes_sync(void) +{ + struct lantern_client client; + struct PQSignatureSchemePublicKey *pub = NULL; + struct PQSignatureSchemeSecretKey *secret = NULL; + LanternRoot child_root; + const char *peer_id = "16Uiu2HAmPV5jU62WtmDkCEmfq1jzbBDkGbHNsDN78gJyvmv2TuC6"; + int rc = 1; + + if (client_test_setup_vote_validation_client( + &client, + "sync_idle_status_caught_up", + &pub, + &secret, + NULL, + &child_root) + != 0) { + return 1; + } + if (enable_sync_test_peer(&client, peer_id) != 0) { + fprintf(stderr, "failed to enable sync test peer\n"); + goto cleanup; + } + + client.sync_state = LANTERN_SYNC_STATE_IDLE; + + LanternStatusMessage status; + memset(&status, 0, sizeof(status)); + status.head.root = child_root; + status.head.slot = client.state.slot; + status.finalized = client.state.latest_finalized; + if (reqresp_handle_status(&client, &status, peer_id) != LANTERN_CLIENT_OK) { + fprintf(stderr, "caught-up peer status update failed\n"); + goto cleanup; + } + if (client.sync_state != LANTERN_SYNC_STATE_SYNCED) { + fprintf(stderr, "caught-up peer status should complete sync from IDLE\n"); + goto cleanup; + } + + rc = 0; + +cleanup: + disable_sync_test_peer(&client); + client_test_teardown_vote_validation_client(&client, pub, secret); + return rc; +} + static int test_imported_blocks_update_sync_network_view(void) { struct block_signature_fixture fixture; @@ -2016,6 +2066,9 @@ int main(void) { if (test_idle_status_triggers_syncing_before_gossip_backfill() != 0) { return 1; } + if (test_idle_status_at_known_head_completes_sync() != 0) { + return 1; + } if (test_reqresp_block_response_accepts_missing_parent() != 0) { return 1; }