From a7f4fff58015750c8e0a22807c488f30adbf66ac Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Sat, 20 Dec 2025 14:58:30 +0530 Subject: [PATCH 01/31] fix: Update leanp2p commit hash to working version --- example/00-vcpkg-install/vcpkg-overlay/leanp2p/portfile.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/00-vcpkg-install/vcpkg-overlay/leanp2p/portfile.cmake b/example/00-vcpkg-install/vcpkg-overlay/leanp2p/portfile.cmake index 40d5a3a7..71b20edd 100644 --- a/example/00-vcpkg-install/vcpkg-overlay/leanp2p/portfile.cmake +++ b/example/00-vcpkg-install/vcpkg-overlay/leanp2p/portfile.cmake @@ -2,8 +2,8 @@ vcpkg_check_linkage(ONLY_STATIC_LIBRARY) vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH REPO qdrvm/leanp2p - REF c4deae2f4269983253ce67a2f14506577a720972 - SHA512 be2542a3d51161abd7e8fc99b25ba9557c53fb7ee2dc6edccef16c87db76d23290b7f6df2cc197a1ae5365d49e7bef07e83948a9e62cb5a218dffc72cbfa9fc7 + REF f5d7e82fa0d16488ebc4974407e7fe11615bb638 + SHA512 d93160336590b70379256547b4b584a107743e8c84aa2ccc9fff8615409dbcd47ac9a51d4dc05bc841db907c97a3733c0f4307a472ec9fafefb9fb8260669f7b ) vcpkg_cmake_configure(SOURCE_PATH "${SOURCE_PATH}") vcpkg_cmake_install() From 8f1365b1f72940ab5a4445535daeb0f72388b25d Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Sat, 20 Dec 2025 14:59:10 +0530 Subject: [PATCH 02/31] feat: Add redis feature to vcpkg for test-plans build --- .gitignore | 2 ++ CMakeLists.txt | 10 +++++++++ CMakePresets.json | 38 ++++++++++++++++++++++------------ test-plans/CMakeLists.txt | 1 + test-plans/ping/CMakeLists.txt | 8 +++++++ vcpkg.json | 6 ++++++ 6 files changed, 52 insertions(+), 13 deletions(-) create mode 100644 test-plans/CMakeLists.txt create mode 100644 test-plans/ping/CMakeLists.txt diff --git a/.gitignore b/.gitignore index 26881008..94a2958b 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,5 @@ dist ninja_build_release _builds _logs + +vcpkg_installed/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 56688c57..2e1fa2ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,8 @@ project(leanp2p) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) +option(ENABLE_REDIS "Enable Redis support" OFF) + find_package(Boost CONFIG REQUIRED filesystem random beast program_options) find_package(OpenSSL CONFIG REQUIRED) find_package(soralog CONFIG REQUIRED) @@ -16,6 +18,9 @@ find_package(libsecp256k1 CONFIG REQUIRED) find_package(Protobuf CONFIG REQUIRED) find_package(tsl_hat_trie CONFIG REQUIRED) find_package(Boost.DI CONFIG REQUIRED) +if(ENABLE_REDIS) + find_package(hiredis CONFIG REQUIRED) +endif() include(cmake/functions.cmake) include(cmake/install.cmake) @@ -28,3 +33,8 @@ add_subdirectory(src) # Examples add_subdirectory(example) + +# Test-plans +if(ENABLE_REDIS) + add_subdirectory(test-plans) +endif() \ No newline at end of file diff --git a/CMakePresets.json b/CMakePresets.json index 69e9a20e..0b29583a 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -1,14 +1,26 @@ { - "version": 2, - "configurePresets": [ - { - "name": "default", - "generator": "Ninja", - "binaryDir": "${sourceDir}/build", - "cacheVariables": { - "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", - "CMAKE_BUILD_TYPE": "Debug" - } - } - ] -} + "version": 2, + "configurePresets": [ + { + "name": "default", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "CMAKE_BUILD_TYPE": "Debug", + "ENABLE_REDIS": "OFF" + } + }, + { + "name": "test-plans", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "CMAKE_BUILD_TYPE": "Debug", + "ENABLE_REDIS": "ON", + "VCPKG_MANIFEST_FEATURES": "redis" + } + } + ] +} \ No newline at end of file diff --git a/test-plans/CMakeLists.txt b/test-plans/CMakeLists.txt new file mode 100644 index 00000000..1aed946e --- /dev/null +++ b/test-plans/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(ping) \ No newline at end of file diff --git a/test-plans/ping/CMakeLists.txt b/test-plans/ping/CMakeLists.txt new file mode 100644 index 00000000..488c1bb7 --- /dev/null +++ b/test-plans/ping/CMakeLists.txt @@ -0,0 +1,8 @@ +add_executable(ping + ping.cpp +) +target_link_libraries(ping + libp2p + p2p_protocol_ping + hiredis +) \ No newline at end of file diff --git a/vcpkg.json b/vcpkg.json index 1316b656..8e01f017 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,6 +1,12 @@ { "name": "leanp2p", "version": "0.1.0", + "features": { + "redis": { + "description": "Enable Redis support (needed for test-plans)", + "dependencies": ["hiredis"] + } + }, "dependencies": [ "boost-asio", "boost-beast", From 193a176026be2f5114643f9948ab592628ae9346 Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Sat, 20 Dec 2025 14:59:36 +0530 Subject: [PATCH 03/31] feat: Add ping interop test for dialer mode --- test-plans/ping/ping.cpp | 186 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 test-plans/ping/ping.cpp diff --git a/test-plans/ping/ping.cpp b/test-plans/ping/ping.cpp new file mode 100644 index 00000000..031f71b9 --- /dev/null +++ b/test-plans/ping/ping.cpp @@ -0,0 +1,186 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +std::optional getenv_opt(const char* name){ + if(const char* v = std::getenv(name)){ + return std::string(v); + } + else{ + return std::nullopt; + } +} + +redisContext* connect_redis(const std::string& host, int port, int timeout_ms, libp2p::log::Logger log){ + struct timeval timeout; + timeout.tv_sec = timeout_ms / 1000; + timeout.tv_usec = (timeout_ms % 1000) * 1000; + + redisContext* ctx = redisConnectWithTimeout(host.c_str(), port, timeout); + + if(!ctx || ctx->err){ + if(ctx){ + log->error("Failed to connect to redis:{}\n", ctx->errstr); + redisFree(ctx); + } + return nullptr; + } + else{ + return ctx; + } +} + +bool wait_for_redis(redisContext* ctx, int timeout_ms){ + auto start_time = std::chrono::steady_clock::now(); + + while(true){ + redisReply* reply = (redisReply*)redisCommand(ctx, "PING"); + if(reply){ + bool ok = reply->type == REDIS_REPLY_STATUS && std::string(reply->str) == "PONG"; + freeReplyObject(reply); + if (ok) return true; + } + + if (std::chrono::steady_clock::now() - start_time < std::chrono::milliseconds(timeout_ms)){ + return false; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } +} + +int parse_redis_port(std::string& redisAddr, libp2p::log::Logger log){ + std::string redisPortStr = redisAddr.substr(redisAddr.find(":"), redisAddr.length()); + int port{}; + auto [ptr, ec] = std::from_chars(redisPortStr.data(), redisPortStr.data() + redisPortStr.size(), port); + if(ec == std::errc{}){ + return port; + } + else{ + log->error("Could not parse reddis port, using default\n"); + return 6379; + } +} + +std::shared_ptr make_host(){} + +int main(){ + libp2p::simpleLoggingSystem(); + auto log = libp2p::log::createLogger("Ping"); + + auto transport = getenv_opt("transport"); + auto muxer = getenv_opt("muxer"); + auto secureChannel = getenv_opt("security"); + auto isDialerStr = getenv_opt("is_dialer"); + std::string ip = getenv_opt("ip").value_or("0.0.0.0"); + std::string redisAddr = getenv_opt("redis_addr").value_or("redis:6379"); + auto testTimeoutStr = getenv_opt("test_timeout_seconds"); + + int testTimeout = 3 * 60; + if (testTimeoutStr) { + int value{}; + auto [ptr, ec] = std::from_chars(testTimeoutStr->data(), testTimeoutStr->data() + testTimeoutStr->size(), value); + if(ec == std::errc{}){ + testTimeout = value; + } + else{ + log->error("Invalid test timeout, using default\n"); + return 1; + } + } + + int redisPort = parse_redis_port(redisAddr, log); + + redisContext* ctx = connect_redis(ip, redisPort, testTimeout, log); + + if(!wait_for_redis(ctx, testTimeout)){ + return 1; + } + + bool isDialer = *isDialerStr == "true"; + + unsigned int random_seed = static_cast(std::random_device{}()); + auto sample_peer = libp2p::SamplePeer::makeEd25519(random_seed); + + std::shared_ptr io_context; + std::shared_ptr host; + std::shared_ptr random; + if(*transport == "quic"){ + auto injector = libp2p::injector::makeHostInjector( + libp2p::injector::useKeyPair(sample_peer.keypair), + libp2p::injector::useTransportAdaptors() + ); + + io_context = injector.create>(); + host = injector.create>(); + random = injector.create>(); + } + else{ + log->error("Unsupported transport protocol\n"); + return 1; + } + + libp2p::protocol::PingConfig pingConfig{}; + auto ping = std::make_shared(io_context, host, random, pingConfig); + + if (not host->listen(sample_peer.listen)) { + std::println("Error listening on {}", sample_peer.listen); + return 1; + } + + host->start(); + ping->start(); + + log->info("Connection string: {}", sample_peer.connect); + + if(isDialer){ + redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, fmt::format("BLPOP listenAddr {}", testTimeout).c_str()); + if(replyListenAddr){ + bool ok = replyListenAddr->type == REDIS_REPLY_STATUS; + if(ok){ + std::string listenAddr = replyListenAddr->str; + auto address_res = libp2p::Multiaddress::create(listenAddr); + auto address = address_res.value(); + auto peer_id_res = address.getPeerId(); + auto peer_id = libp2p::PeerId::fromBase58(peer_id_res.value()); + libp2p::peer::PeerInfo connect_info = {peer_id.value(), {address}}; + freeReplyObject(replyListenAddr); + + libp2p::coroSpawn(*io_context, [&]() -> libp2p::Coro { + log->info("Connecting to {}", connect_info.addresses.at(0)); + auto connect_res = co_await host->connect(connect_info); + if (!connect_res.has_value()) { + log->error("Failed to connect to peer"); + } else { + log->info("Connected to peer, pinging will start automatically"); + } + }); + } + else{ + log->error("Failed to wait for listener to be ready"); + return 1; + } + } + else{ + log->error("Failed to get listener address from redis"); + return 1; + } + } + + return 0; +} \ No newline at end of file From 97f6d77a18ad67466d4ab5bce0e52d01ff0aa389 Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Sat, 31 Jan 2026 18:28:11 +0530 Subject: [PATCH 04/31] feat: finished dialer in test plans --- test-plans/ping/ping.cpp | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/test-plans/ping/ping.cpp b/test-plans/ping/ping.cpp index 031f71b9..26556cd3 100644 --- a/test-plans/ping/ping.cpp +++ b/test-plans/ping/ping.cpp @@ -16,6 +16,7 @@ #include #include #include +#include std::optional getenv_opt(const char* name){ if(const char* v = std::getenv(name)){ @@ -144,7 +145,6 @@ int main(){ } host->start(); - ping->start(); log->info("Connection string: {}", sample_peer.connect); @@ -163,11 +163,37 @@ int main(){ libp2p::coroSpawn(*io_context, [&]() -> libp2p::Coro { log->info("Connecting to {}", connect_info.addresses.at(0)); - auto connect_res = co_await host->connect(connect_info); + auto handShakeStart = std::chrono::steady_clock::now(); + auto connect_res = (co_await host->connect(connect_info)); if (!connect_res.has_value()) { log->error("Failed to connect to peer"); - } else { - log->info("Connected to peer, pinging will start automatically"); + io_context->stop(); + co_return; + } + else{ + log->info("Connected successfully"); + auto connection = connect_res.value(); + + auto ping_res = (co_await ping->ping(connection, std::chrono::milliseconds(testTimeout))); + if(!ping_res.has_value()){ + log->error("Ping failed"); + io_context->stop(); + co_return; + } + else{ + auto handShakeEnd = std::chrono::steady_clock::now(); + log->info("Ping successful"); + auto ping_rtt = ping_res.value(); + auto handShakePlusOneRTT = std::chrono::duration_cast(handShakeEnd - handShakeStart); + + // Printing out results in stdout + std::cout << "latency:\n"; + std::cout << fmt::format(" handshake_plus_one_rtt: {}\n", handShakePlusOneRTT.count()); + std::cout << fmt::format(" ping_rtt: {}\n", ping_rtt.count()); + std::cout << " unit: ms\n"; + + io_context->stop(); + } } }); } @@ -180,6 +206,8 @@ int main(){ log->error("Failed to get listener address from redis"); return 1; } + }else{ + } return 0; From 3aada1bcafc54f111877a201d6bbc624912223fd Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Sat, 31 Jan 2026 21:31:15 +0530 Subject: [PATCH 05/31] feat: complete basic test-plans transport test --- test-plans/ping/CMakeLists.txt | 2 +- test-plans/ping/ping.cpp | 48 ++++++++++++++++++++++++++++++---- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/test-plans/ping/CMakeLists.txt b/test-plans/ping/CMakeLists.txt index 488c1bb7..e355df82 100644 --- a/test-plans/ping/CMakeLists.txt +++ b/test-plans/ping/CMakeLists.txt @@ -4,5 +4,5 @@ add_executable(ping target_link_libraries(ping libp2p p2p_protocol_ping - hiredis + hiredis::hiredis ) \ No newline at end of file diff --git a/test-plans/ping/ping.cpp b/test-plans/ping/ping.cpp index 26556cd3..bbc16d0c 100644 --- a/test-plans/ping/ping.cpp +++ b/test-plans/ping/ping.cpp @@ -17,6 +17,7 @@ #include #include #include +#include std::optional getenv_opt(const char* name){ if(const char* v = std::getenv(name)){ @@ -110,6 +111,7 @@ int main(){ redisContext* ctx = connect_redis(ip, redisPort, testTimeout, log); if(!wait_for_redis(ctx, testTimeout)){ + redisFree(ctx); return 1; } @@ -121,7 +123,7 @@ int main(){ std::shared_ptr io_context; std::shared_ptr host; std::shared_ptr random; - if(*transport == "quic"){ + if(*transport == "quic-v1"){ auto injector = libp2p::injector::makeHostInjector( libp2p::injector::useKeyPair(sample_peer.keypair), libp2p::injector::useTransportAdaptors() @@ -130,6 +132,8 @@ int main(){ io_context = injector.create>(); host = injector.create>(); random = injector.create>(); + + host->listenProtocol(injector.create>()); } else{ log->error("Unsupported transport protocol\n"); @@ -145,7 +149,7 @@ int main(){ } host->start(); - + ping->start(); log->info("Connection string: {}", sample_peer.connect); if(isDialer){ @@ -165,7 +169,7 @@ int main(){ log->info("Connecting to {}", connect_info.addresses.at(0)); auto handShakeStart = std::chrono::steady_clock::now(); auto connect_res = (co_await host->connect(connect_info)); - if (!connect_res.has_value()) { + if (not connect_res.has_value()) { log->error("Failed to connect to peer"); io_context->stop(); co_return; @@ -175,7 +179,7 @@ int main(){ auto connection = connect_res.value(); auto ping_res = (co_await ping->ping(connection, std::chrono::milliseconds(testTimeout))); - if(!ping_res.has_value()){ + if(not ping_res.has_value()){ log->error("Ping failed"); io_context->stop(); co_return; @@ -199,15 +203,49 @@ int main(){ } else{ log->error("Failed to wait for listener to be ready"); + redisFree(ctx); return 1; } } else{ log->error("Failed to get listener address from redis"); + redisFree(ctx); return 1; } }else{ - + redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, fmt::format("RPUSH listenAddr {}", testTimeout).c_str()); + if(replyListenAddr){ + bool ok = replyListenAddr->type == REDIS_REPLY_STATUS; + freeReplyObject(replyListenAddr); + if(ok){ + log->info("Listener address pushed to redis"); + + boost::asio::steady_timer timeout_timer(*io_context); + timeout_timer.expires_after(std::chrono::seconds(testTimeout)); + timeout_timer.async_wait([&](const boost::system::error_code& ec) { + if(!ec){ + log->info("Test timeout reached"); + io_context->stop(); + } + }); + + io_context->run(); + + log->info("Listener exiting"); + redisFree(ctx); + return 1; + } + else{ + log->error("Failed to push address to redis"); + redisFree(ctx); + return 1; + } + } + else{ + log->error("Failed to get status of address push from redis"); + redisFree(ctx); + return 1; + } } return 0; From 352659c4d1e52dbf143c9ad9443ccba05e63d5ea Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Sun, 1 Feb 2026 20:52:07 +0530 Subject: [PATCH 06/31] feat: add dockerfile for test-plans debugging --- test-plans/ping/Dockerfile | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 test-plans/ping/Dockerfile diff --git a/test-plans/ping/Dockerfile b/test-plans/ping/Dockerfile new file mode 100644 index 00000000..dde14555 --- /dev/null +++ b/test-plans/ping/Dockerfile @@ -0,0 +1,38 @@ +# Build stage +FROM ubuntu:24.04 AS builder + +# Install build dependencies +RUN apt-get update && apt-get install -y \ + git \ + cmake \ + ninja-build \ + curl \ + zip \ + unzip \ + tar \ + pkg-config \ + build-essential \ + && rm -rf /var/lib/apt/lists/* + +# Set up vcpkg +ENV VCPKG_ROOT=/opt/vcpkg +RUN git clone https://github.com/microsoft/vcpkg.git $VCPKG_ROOT \ + && $VCPKG_ROOT/bootstrap-vcpkg.sh \ + && rm -rf $VCPKG_ROOT/.git + +# Copy project files +WORKDIR /build +COPY . . + +# Configure and build +RUN cmake --preset test-plans \ + && cmake --build build -j$(nproc) --target ping + +# Runtime stage +FROM alpine + +# Copy the compiled binary +COPY --from=builder /build/build/test-plans/ping/ping /usr/local/bin/ping + +# Run the ping executable +ENTRYPOINT ["/usr/local/bin/ping"] \ No newline at end of file From 1e6e34284582eb7856c3d31c1b5a7fdd00466057 Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Sun, 1 Feb 2026 21:08:04 +0530 Subject: [PATCH 07/31] fix: added nasm to dockerfile --- test-plans/ping/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/test-plans/ping/Dockerfile b/test-plans/ping/Dockerfile index dde14555..dd5cbcb8 100644 --- a/test-plans/ping/Dockerfile +++ b/test-plans/ping/Dockerfile @@ -12,6 +12,7 @@ RUN apt-get update && apt-get install -y \ tar \ pkg-config \ build-essential \ + nasm \ && rm -rf /var/lib/apt/lists/* # Set up vcpkg From 7e96fd693cb729d9023e853aa60526ba34f42a40 Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Mon, 2 Feb 2026 03:10:39 +0530 Subject: [PATCH 08/31] fix: fixed address pushing and dockerfile --- test-plans/ping/Dockerfile | 17 ++++++++++++++--- test-plans/ping/ping.cpp | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/test-plans/ping/Dockerfile b/test-plans/ping/Dockerfile index dd5cbcb8..d3a028ec 100644 --- a/test-plans/ping/Dockerfile +++ b/test-plans/ping/Dockerfile @@ -3,6 +3,9 @@ FROM ubuntu:24.04 AS builder # Install build dependencies RUN apt-get update && apt-get install -y \ + software-properties-common \ + && add-apt-repository ppa:ubuntu-toolchain-r/test \ + && apt-get update && apt-get install -y \ git \ cmake \ ninja-build \ @@ -11,8 +14,12 @@ RUN apt-get update && apt-get install -y \ unzip \ tar \ pkg-config \ - build-essential \ + gcc-14 \ + g++-14 \ nasm \ + && update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 100 \ + && update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 100 \ + && update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-14 100 \ && rm -rf /var/lib/apt/lists/* # Set up vcpkg @@ -29,8 +36,12 @@ COPY . . RUN cmake --preset test-plans \ && cmake --build build -j$(nproc) --target ping -# Runtime stage -FROM alpine +FROM ubuntu:24.04 + +# Install only essential runtime dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* # Copy the compiled binary COPY --from=builder /build/build/test-plans/ping/ping /usr/local/bin/ping diff --git a/test-plans/ping/ping.cpp b/test-plans/ping/ping.cpp index bbc16d0c..cbc56356 100644 --- a/test-plans/ping/ping.cpp +++ b/test-plans/ping/ping.cpp @@ -213,7 +213,7 @@ int main(){ return 1; } }else{ - redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, fmt::format("RPUSH listenAddr {}", testTimeout).c_str()); + redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, fmt::format("RPUSH listenAddr {}", sample_peer.connect).c_str()); if(replyListenAddr){ bool ok = replyListenAddr->type == REDIS_REPLY_STATUS; freeReplyObject(replyListenAddr); From 52261b54189b29e160349d52695e73ee09ccdf50 Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Mon, 2 Feb 2026 03:21:17 +0530 Subject: [PATCH 09/31] fix: fixed redis interaction and redis port parsing --- test-plans/ping/ping.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/test-plans/ping/ping.cpp b/test-plans/ping/ping.cpp index cbc56356..dc701bad 100644 --- a/test-plans/ping/ping.cpp +++ b/test-plans/ping/ping.cpp @@ -67,14 +67,19 @@ bool wait_for_redis(redisContext* ctx, int timeout_ms){ } int parse_redis_port(std::string& redisAddr, libp2p::log::Logger log){ - std::string redisPortStr = redisAddr.substr(redisAddr.find(":"), redisAddr.length()); + size_t colon_pos = redisAddr.find(":"); + if (colon_pos == std::string::npos) { + log->error("Could not find port in redis address, using default\n"); + return 6379; + } + std::string redisPortStr = redisAddr.substr(colon_pos + 1); int port{}; auto [ptr, ec] = std::from_chars(redisPortStr.data(), redisPortStr.data() + redisPortStr.size(), port); if(ec == std::errc{}){ return port; } else{ - log->error("Could not parse reddis port, using default\n"); + log->error("Could not parse redis port, using default\n"); return 6379; } } @@ -153,7 +158,7 @@ int main(){ log->info("Connection string: {}", sample_peer.connect); if(isDialer){ - redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, fmt::format("BLPOP listenAddr {}", testTimeout).c_str()); + redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, "BLPOP listenAddr %d", testTimeout); if(replyListenAddr){ bool ok = replyListenAddr->type == REDIS_REPLY_STATUS; if(ok){ @@ -213,7 +218,7 @@ int main(){ return 1; } }else{ - redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, fmt::format("RPUSH listenAddr {}", sample_peer.connect).c_str()); + redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, "RPUSH listenAddr %s", sample_peer.connect); if(replyListenAddr){ bool ok = replyListenAddr->type == REDIS_REPLY_STATUS; freeReplyObject(replyListenAddr); From 3a9e3d0dba55dacf4ceb8ed2dc954460585d0fa0 Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Mon, 2 Feb 2026 03:23:15 +0530 Subject: [PATCH 10/31] refactor: decoupled preset in dockerfile for faster testing --- test-plans/ping/Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test-plans/ping/Dockerfile b/test-plans/ping/Dockerfile index d3a028ec..bc1cf107 100644 --- a/test-plans/ping/Dockerfile +++ b/test-plans/ping/Dockerfile @@ -33,8 +33,9 @@ WORKDIR /build COPY . . # Configure and build -RUN cmake --preset test-plans \ - && cmake --build build -j$(nproc) --target ping +# Separated both commands as preset loading takes a lot of time, caching it makes testing faster +RUN cmake --preset test-plans +RUN cmake --build build -j$(nproc) --target ping FROM ubuntu:24.04 From 6529bc98514a8a94c342e2b8597a443ff77715ea Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Mon, 2 Feb 2026 04:00:30 +0530 Subject: [PATCH 11/31] fix: dialer reply status --- test-plans/ping/ping.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-plans/ping/ping.cpp b/test-plans/ping/ping.cpp index dc701bad..833d9d7d 100644 --- a/test-plans/ping/ping.cpp +++ b/test-plans/ping/ping.cpp @@ -220,7 +220,7 @@ int main(){ }else{ redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, "RPUSH listenAddr %s", sample_peer.connect); if(replyListenAddr){ - bool ok = replyListenAddr->type == REDIS_REPLY_STATUS; + bool ok = replyListenAddr->type == REDIS_REPLY_ARRAY && replyListenAddr->elements == 2; freeReplyObject(replyListenAddr); if(ok){ log->info("Listener address pushed to redis"); From bada3edf39a3a7855aa00ed99840818047650ff6 Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Mon, 2 Feb 2026 16:37:58 +0530 Subject: [PATCH 12/31] feat: tested plaintext quic-v1 test-plans script --- test-plans/ping/ping.cpp | 42 ++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/test-plans/ping/ping.cpp b/test-plans/ping/ping.cpp index 833d9d7d..2d8ca8b1 100644 --- a/test-plans/ping/ping.cpp +++ b/test-plans/ping/ping.cpp @@ -160,9 +160,16 @@ int main(){ if(isDialer){ redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, "BLPOP listenAddr %d", testTimeout); if(replyListenAddr){ - bool ok = replyListenAddr->type == REDIS_REPLY_STATUS; + if(replyListenAddr->type == REDIS_REPLY_ERROR){ + log->error("Redis BLPOP error: {}", replyListenAddr->str); + freeReplyObject(replyListenAddr); + redisFree(ctx); + return 1; + } + bool ok = replyListenAddr->type == REDIS_REPLY_ARRAY && replyListenAddr->elements == 2; if(ok){ - std::string listenAddr = replyListenAddr->str; + std::string listenAddr = replyListenAddr->element[1]->str; + log->info("Retrieved listener address from redis: {}", listenAddr); auto address_res = libp2p::Multiaddress::create(listenAddr); auto address = address_res.value(); auto peer_id_res = address.getPeerId(); @@ -199,31 +206,45 @@ int main(){ std::cout << "latency:\n"; std::cout << fmt::format(" handshake_plus_one_rtt: {}\n", handShakePlusOneRTT.count()); std::cout << fmt::format(" ping_rtt: {}\n", ping_rtt.count()); - std::cout << " unit: ms\n"; + std::cout << " unit: ms\n"; io_context->stop(); } } }); + + io_context->run(); + redisFree(ctx); } else{ - log->error("Failed to wait for listener to be ready"); + log->error("Failed to wait for listener to be ready - unexpected reply type: {} (elements: {})", + replyListenAddr->type, + replyListenAddr->type == REDIS_REPLY_ARRAY ? replyListenAddr->elements : 0); + freeReplyObject(replyListenAddr); redisFree(ctx); return 1; } } else{ - log->error("Failed to get listener address from redis"); + log->error("Failed to get listener address from redis - {}", ctx->errstr); redisFree(ctx); return 1; } }else{ - redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, "RPUSH listenAddr %s", sample_peer.connect); + std::string connectStr = std::string(sample_peer.connect.getStringAddress()); + log->info("Pushing connect string {}", connectStr); + redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, "RPUSH listenAddr %s", connectStr.c_str()); if(replyListenAddr){ - bool ok = replyListenAddr->type == REDIS_REPLY_ARRAY && replyListenAddr->elements == 2; - freeReplyObject(replyListenAddr); + if(replyListenAddr->type == REDIS_REPLY_ERROR){ + log->error("Redis RPUSH error: {}", replyListenAddr->str); + freeReplyObject(replyListenAddr); + redisFree(ctx); + return 1; + } + bool ok = replyListenAddr->type == REDIS_REPLY_INTEGER; if(ok){ log->info("Listener address pushed to redis"); + freeReplyObject(replyListenAddr); boost::asio::steady_timer timeout_timer(*io_context); timeout_timer.expires_after(std::chrono::seconds(testTimeout)); @@ -241,13 +262,14 @@ int main(){ return 1; } else{ - log->error("Failed to push address to redis"); + log->error("Failed to push address to redis - unexpected reply type: {}", replyListenAddr->type); + freeReplyObject(replyListenAddr); redisFree(ctx); return 1; } } else{ - log->error("Failed to get status of address push from redis"); + log->error("Failed to get status of address push from redis - {}", ctx->errstr); redisFree(ctx); return 1; } From cd7b61ac129110deacf4c07d21b13904d67eec5f Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Mon, 2 Feb 2026 17:02:51 +0530 Subject: [PATCH 13/31] refactor: testing smaller dockerfile --- test-plans/ping/Dockerfile | 48 ++++++++++++++------------------------ 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/test-plans/ping/Dockerfile b/test-plans/ping/Dockerfile index bc1cf107..14704728 100644 --- a/test-plans/ping/Dockerfile +++ b/test-plans/ping/Dockerfile @@ -1,51 +1,37 @@ -# Build stage -FROM ubuntu:24.04 AS builder +FROM alpine:3.19 AS builder -# Install build dependencies -RUN apt-get update && apt-get install -y \ - software-properties-common \ - && add-apt-repository ppa:ubuntu-toolchain-r/test \ - && apt-get update && apt-get install -y \ +RUN apk add --no-cache \ git \ cmake \ - ninja-build \ + ninja \ curl \ zip \ unzip \ tar \ - pkg-config \ - gcc-14 \ - g++-14 \ + pkgconf \ + gcc \ + g++ \ nasm \ - && update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 100 \ - && update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 100 \ - && update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-14 100 \ - && rm -rf /var/lib/apt/lists/* + linux-headers \ + musl-dev \ + make \ + bash -# Set up vcpkg ENV VCPKG_ROOT=/opt/vcpkg RUN git clone https://github.com/microsoft/vcpkg.git $VCPKG_ROOT \ && $VCPKG_ROOT/bootstrap-vcpkg.sh \ && rm -rf $VCPKG_ROOT/.git -# Copy project files WORKDIR /build COPY . . -# Configure and build -# Separated both commands as preset loading takes a lot of time, caching it makes testing faster -RUN cmake --preset test-plans -RUN cmake --build build -j$(nproc) --target ping +RUN cmake --preset test-plans -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_EXE_LINKER_FLAGS="-static" \ + && cmake --build build -j$(nproc) --target ping -FROM ubuntu:24.04 +FROM alpine:3.19 -# Install only essential runtime dependencies -RUN apt-get update && apt-get install -y --no-install-recommends \ - ca-certificates \ - && rm -rf /var/lib/apt/lists/* +COPY --from=builder /build/build/test-plans/ping/ping /ping -# Copy the compiled binary -COPY --from=builder /build/build/test-plans/ping/ping /usr/local/bin/ping - -# Run the ping executable -ENTRYPOINT ["/usr/local/bin/ping"] \ No newline at end of file +ENTRYPOINT ["/ping"] \ No newline at end of file From 3bc375ff37469b021549475e4dab2e41e25ee878 Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Mon, 2 Feb 2026 17:08:31 +0530 Subject: [PATCH 14/31] fix: fixed builder container --- test-plans/ping/Dockerfile | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/test-plans/ping/Dockerfile b/test-plans/ping/Dockerfile index 14704728..deb78a44 100644 --- a/test-plans/ping/Dockerfile +++ b/test-plans/ping/Dockerfile @@ -1,21 +1,24 @@ -FROM alpine:3.19 AS builder +FROM ubuntu:24.04 AS builder -RUN apk add --no-cache \ +RUN apt-get update && apt-get install -y \ + software-properties-common \ + && add-apt-repository ppa:ubuntu-toolchain-r/test \ + && apt-get update && apt-get install -y \ git \ cmake \ - ninja \ + ninja-build \ curl \ zip \ unzip \ tar \ - pkgconf \ - gcc \ - g++ \ + pkg-config \ + gcc-14 \ + g++-14 \ nasm \ - linux-headers \ - musl-dev \ - make \ - bash + && update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 100 \ + && update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 100 \ + && update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-14 100 \ + && rm -rf /var/lib/apt/lists/* ENV VCPKG_ROOT=/opt/vcpkg RUN git clone https://github.com/microsoft/vcpkg.git $VCPKG_ROOT \ From cb7883177c43590b652d38ee9cac2c5525e04746 Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Mon, 2 Feb 2026 20:14:07 +0530 Subject: [PATCH 15/31] fix: redis host parsing added --- test-plans/ping/ping.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/test-plans/ping/ping.cpp b/test-plans/ping/ping.cpp index 2d8ca8b1..86ee0e9a 100644 --- a/test-plans/ping/ping.cpp +++ b/test-plans/ping/ping.cpp @@ -84,7 +84,19 @@ int parse_redis_port(std::string& redisAddr, libp2p::log::Logger log){ } } -std::shared_ptr make_host(){} +std::string parse_redis_host(const std::string &redisAddr, libp2p::log::Logger log) { + size_t colonPos = redisAddr.find(':'); + if (colonPos == std::string::npos) { + log->warn("No port separator found in redis address '{}', treating entire string as host", redisAddr); + return redisAddr; + } + std::string host = redisAddr.substr(0, colonPos); + if (host.empty()) { + log->error("Empty host in redis address '{}'", redisAddr); + return "localhost"; + } + return host; +} int main(){ libp2p::simpleLoggingSystem(); @@ -112,8 +124,9 @@ int main(){ } int redisPort = parse_redis_port(redisAddr, log); + std::string redisHost = parse_redis_host(redisAddr, log); - redisContext* ctx = connect_redis(ip, redisPort, testTimeout, log); + redisContext* ctx = connect_redis(redisHost, redisPort, testTimeout, log); if(!wait_for_redis(ctx, testTimeout)){ redisFree(ctx); From 6d377a8f2bec8da61e4165ba65677dcfec62ab53 Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Sun, 8 Feb 2026 09:20:28 +0530 Subject: [PATCH 16/31] fix: Adding ip in multiaddr --- test-plans/ping/ping.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-plans/ping/ping.cpp b/test-plans/ping/ping.cpp index 86ee0e9a..1cbaefa6 100644 --- a/test-plans/ping/ping.cpp +++ b/test-plans/ping/ping.cpp @@ -136,7 +136,7 @@ int main(){ bool isDialer = *isDialerStr == "true"; unsigned int random_seed = static_cast(std::random_device{}()); - auto sample_peer = libp2p::SamplePeer::makeEd25519(random_seed); + auto sample_peer = libp2p::SamplePeer(random_seed, ip, libp2p::SamplePeer::samplePort(random_seed), libp2p::SamplePeer::Ed25519); std::shared_ptr io_context; std::shared_ptr host; From 8c81fc29202539a36a6694ec4f49079699e4b077 Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Sun, 8 Feb 2026 20:53:07 +0530 Subject: [PATCH 17/31] fix: testTimout to seconds for dialer --- test-plans/ping/ping.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-plans/ping/ping.cpp b/test-plans/ping/ping.cpp index 1cbaefa6..eb57dd7c 100644 --- a/test-plans/ping/ping.cpp +++ b/test-plans/ping/ping.cpp @@ -203,7 +203,7 @@ int main(){ log->info("Connected successfully"); auto connection = connect_res.value(); - auto ping_res = (co_await ping->ping(connection, std::chrono::milliseconds(testTimeout))); + auto ping_res = (co_await ping->ping(connection, std::chrono::seconds(testTimeout))); if(not ping_res.has_value()){ log->error("Ping failed"); io_context->stop(); From 799b2c6c44caaea5213b9f1bedd31b686ff0302a Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Sun, 8 Feb 2026 23:25:24 +0530 Subject: [PATCH 18/31] feat: upgraded transport test script to new test-plans standard --- test-plans/ping/ping.cpp | 47 ++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/test-plans/ping/ping.cpp b/test-plans/ping/ping.cpp index eb57dd7c..1bdfbd27 100644 --- a/test-plans/ping/ping.cpp +++ b/test-plans/ping/ping.cpp @@ -102,38 +102,33 @@ int main(){ libp2p::simpleLoggingSystem(); auto log = libp2p::log::createLogger("Ping"); - auto transport = getenv_opt("transport"); - auto muxer = getenv_opt("muxer"); - auto secureChannel = getenv_opt("security"); - auto isDialerStr = getenv_opt("is_dialer"); - std::string ip = getenv_opt("ip").value_or("0.0.0.0"); - std::string redisAddr = getenv_opt("redis_addr").value_or("redis:6379"); - auto testTimeoutStr = getenv_opt("test_timeout_seconds"); - - int testTimeout = 3 * 60; - if (testTimeoutStr) { - int value{}; - auto [ptr, ec] = std::from_chars(testTimeoutStr->data(), testTimeoutStr->data() + testTimeoutStr->size(), value); - if(ec == std::errc{}){ - testTimeout = value; - } - else{ - log->error("Invalid test timeout, using default\n"); - return 1; - } - } + auto transport = getenv_opt("TRANSPORT"); + auto muxer = getenv_opt("MUXER"); //There for future use as skipped when transport=quic-v1 + auto secureChannel = getenv_opt("SECURE_CHANNEL"); //There for future use as skipped when transport=quic-v1 + auto isDialerStr = getenv_opt("IS_DIALER"); + std::string ip = getenv_opt("LISTENER_IP").value_or("0.0.0.0"); + std::string redisAddr = getenv_opt("REDIS_ADDR").value_or("redis:6379"); + auto testKey = getenv_opt("TEST_KEY"); + auto debugStr = getenv_opt("DEBUG"); + + int testTimeoutSeconds = 300; int redisPort = parse_redis_port(redisAddr, log); std::string redisHost = parse_redis_host(redisAddr, log); - redisContext* ctx = connect_redis(redisHost, redisPort, testTimeout, log); + redisContext* ctx = connect_redis(redisHost, redisPort, testTimeoutSeconds * 1000, log); //Redis connection needs timeout in ms - if(!wait_for_redis(ctx, testTimeout)){ + if(!wait_for_redis(ctx, testTimeoutSeconds)){ redisFree(ctx); return 1; } bool isDialer = *isDialerStr == "true"; + bool debug = *debugStr == "true"; + + if(!debug){ + log->setLevel(libp2p::log::Level::ERROR); + } unsigned int random_seed = static_cast(std::random_device{}()); auto sample_peer = libp2p::SamplePeer(random_seed, ip, libp2p::SamplePeer::samplePort(random_seed), libp2p::SamplePeer::Ed25519); @@ -171,7 +166,7 @@ int main(){ log->info("Connection string: {}", sample_peer.connect); if(isDialer){ - redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, "BLPOP listenAddr %d", testTimeout); + redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, "BLPOP %s %d", fmt::format("{}_listener_multiaddr", *testKey), testTimeoutSeconds); if(replyListenAddr){ if(replyListenAddr->type == REDIS_REPLY_ERROR){ log->error("Redis BLPOP error: {}", replyListenAddr->str); @@ -203,7 +198,7 @@ int main(){ log->info("Connected successfully"); auto connection = connect_res.value(); - auto ping_res = (co_await ping->ping(connection, std::chrono::seconds(testTimeout))); + auto ping_res = (co_await ping->ping(connection, std::chrono::seconds(testTimeoutSeconds))); if(not ping_res.has_value()){ log->error("Ping failed"); io_context->stop(); @@ -246,7 +241,7 @@ int main(){ }else{ std::string connectStr = std::string(sample_peer.connect.getStringAddress()); log->info("Pushing connect string {}", connectStr); - redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, "RPUSH listenAddr %s", connectStr.c_str()); + redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, "RPUSH %s %s", fmt::format("{}_listener_multiaddr", *testKey), connectStr.c_str()); if(replyListenAddr){ if(replyListenAddr->type == REDIS_REPLY_ERROR){ log->error("Redis RPUSH error: {}", replyListenAddr->str); @@ -260,7 +255,7 @@ int main(){ freeReplyObject(replyListenAddr); boost::asio::steady_timer timeout_timer(*io_context); - timeout_timer.expires_after(std::chrono::seconds(testTimeout)); + timeout_timer.expires_after(std::chrono::seconds(testTimeoutSeconds)); timeout_timer.async_wait([&](const boost::system::error_code& ec) { if(!ec){ log->info("Test timeout reached"); From a99a53e28a83d96b6b25964966755945df44fccd Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Mon, 9 Feb 2026 04:44:19 +0530 Subject: [PATCH 19/31] fix: Converting redisKey to c_str --- test-plans/ping/ping.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test-plans/ping/ping.cpp b/test-plans/ping/ping.cpp index 1bdfbd27..f7d04c0d 100644 --- a/test-plans/ping/ping.cpp +++ b/test-plans/ping/ping.cpp @@ -115,6 +115,8 @@ int main(){ int redisPort = parse_redis_port(redisAddr, log); std::string redisHost = parse_redis_host(redisAddr, log); + std::string redisKey = fmt::format("{}_listener_multiaddr", *testKey); + log->info("Redis key: {}", redisKey); redisContext* ctx = connect_redis(redisHost, redisPort, testTimeoutSeconds * 1000, log); //Redis connection needs timeout in ms @@ -166,7 +168,7 @@ int main(){ log->info("Connection string: {}", sample_peer.connect); if(isDialer){ - redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, "BLPOP %s %d", fmt::format("{}_listener_multiaddr", *testKey), testTimeoutSeconds); + redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, "BLPOP %s %d", redisKey.c_str(), testTimeoutSeconds); if(replyListenAddr){ if(replyListenAddr->type == REDIS_REPLY_ERROR){ log->error("Redis BLPOP error: {}", replyListenAddr->str); @@ -241,7 +243,7 @@ int main(){ }else{ std::string connectStr = std::string(sample_peer.connect.getStringAddress()); log->info("Pushing connect string {}", connectStr); - redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, "RPUSH %s %s", fmt::format("{}_listener_multiaddr", *testKey), connectStr.c_str()); + redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, "RPUSH %s %s", redisKey.c_str(), connectStr.c_str()); if(replyListenAddr){ if(replyListenAddr->type == REDIS_REPLY_ERROR){ log->error("Redis RPUSH error: {}", replyListenAddr->str); From 12df30405a86be97aaf606a9fcb23d5f74ee6db5 Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Mon, 9 Feb 2026 06:16:01 +0530 Subject: [PATCH 20/31] fix: moved redis key logging --- test-plans/ping/ping.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test-plans/ping/ping.cpp b/test-plans/ping/ping.cpp index f7d04c0d..827cd1df 100644 --- a/test-plans/ping/ping.cpp +++ b/test-plans/ping/ping.cpp @@ -109,10 +109,17 @@ int main(){ std::string ip = getenv_opt("LISTENER_IP").value_or("0.0.0.0"); std::string redisAddr = getenv_opt("REDIS_ADDR").value_or("redis:6379"); auto testKey = getenv_opt("TEST_KEY"); - auto debugStr = getenv_opt("DEBUG"); + std::string debugStr = getenv_opt("DEBUG").value_or("false"); int testTimeoutSeconds = 300; + bool isDialer = *isDialerStr == "true"; + bool debug = debugStr == "true"; + + if(!debug){ + log->setLevel(libp2p::log::Level::ERROR); + } + int redisPort = parse_redis_port(redisAddr, log); std::string redisHost = parse_redis_host(redisAddr, log); std::string redisKey = fmt::format("{}_listener_multiaddr", *testKey); @@ -125,13 +132,6 @@ int main(){ return 1; } - bool isDialer = *isDialerStr == "true"; - bool debug = *debugStr == "true"; - - if(!debug){ - log->setLevel(libp2p::log::Level::ERROR); - } - unsigned int random_seed = static_cast(std::random_device{}()); auto sample_peer = libp2p::SamplePeer(random_seed, ip, libp2p::SamplePeer::samplePort(random_seed), libp2p::SamplePeer::Ed25519); @@ -285,5 +285,5 @@ int main(){ } } - return 0; + return 1; } \ No newline at end of file From 6d3b52adf543a9770286557c6156573316629c64 Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Mon, 9 Feb 2026 06:22:12 +0530 Subject: [PATCH 21/31] fix: return statements --- test-plans/ping/ping.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test-plans/ping/ping.cpp b/test-plans/ping/ping.cpp index 827cd1df..7fb62e6d 100644 --- a/test-plans/ping/ping.cpp +++ b/test-plans/ping/ping.cpp @@ -225,6 +225,7 @@ int main(){ io_context->run(); redisFree(ctx); + return 0; } else{ log->error("Failed to wait for listener to be ready - unexpected reply type: {} (elements: {})", @@ -269,7 +270,7 @@ int main(){ log->info("Listener exiting"); redisFree(ctx); - return 1; + return 0; } else{ log->error("Failed to push address to redis - unexpected reply type: {}", replyListenAddr->type); From f54837cc29e1ee9b17b43a0a5cefb78fe4f55066 Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Wed, 11 Feb 2026 23:03:47 +0530 Subject: [PATCH 22/31] fix: Added automated IP discovery --- test-plans/ping/ping.cpp | 87 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/test-plans/ping/ping.cpp b/test-plans/ping/ping.cpp index 7fb62e6d..1a2d7153 100644 --- a/test-plans/ping/ping.cpp +++ b/test-plans/ping/ping.cpp @@ -18,6 +18,20 @@ #include #include #include +#include + +#ifdef _WIN32 +#include +#include +#include +#pragma comment(lib, "iphlpapi.lib") +#pragma comment(lib, "ws2_32.lib") +#else +#include +#include +#include +#include +#endif std::optional getenv_opt(const char* name){ if(const char* v = std::getenv(name)){ @@ -98,6 +112,64 @@ std::string parse_redis_host(const std::string &redisAddr, libp2p::log::Logger l return host; } +std::optional get_first_network_ip(libp2p::log::Logger log) { +#ifdef _WIN32 + // Windows implementation + ULONG bufferSize = 15000; + PIP_ADAPTER_ADDRESSES addresses = (IP_ADAPTER_ADDRESSES*)malloc(bufferSize); + + if (GetAdaptersAddresses(AF_INET, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, + NULL, addresses, &bufferSize) == NO_ERROR) { + for (PIP_ADAPTER_ADDRESSES addr = addresses; addr != NULL; addr = addr->Next) { + if (addr->OperStatus != IfOperStatusUp) continue; + if (addr->IfType == IF_TYPE_SOFTWARE_LOOPBACK) continue; + + for (PIP_ADAPTER_UNICAST_ADDRESS unicast = addr->FirstUnicastAddress; unicast != NULL; unicast = unicast->Next) { + if (unicast->Address.lpSockaddr->sa_family == AF_INET) { + struct sockaddr_in* sockaddr = (struct sockaddr_in*)unicast->Address.lpSockaddr; + char ip[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(sockaddr->sin_addr), ip, INET_ADDRSTRLEN); + log->info("Found network interface with IP {}", ip); + free(addresses); + return std::string(ip); + } + } + } + } + free(addresses); + return std::nullopt; +#else + // Unix/Linux implementation + struct ifaddrs *ifaddr, *ifa; + + if (getifaddrs(&ifaddr) == -1) { + log->error("getifaddrs failed"); + return std::nullopt; + } + + for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == nullptr) continue; + + // Skip loopback and non-running interfaces + if ((ifa->ifa_flags & IFF_LOOPBACK) || !(ifa->ifa_flags & IFF_UP)) continue; + + // Only handle IPv4 + if (ifa->ifa_addr->sa_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)ifa->ifa_addr; + char ip[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(addr->sin_addr), ip, INET_ADDRSTRLEN); + + log->info("Found network interface {} with IP {}", ifa->ifa_name, ip); + freeifaddrs(ifaddr); + return std::string(ip); + } + } + + freeifaddrs(ifaddr); + return std::nullopt; +#endif +} + int main(){ libp2p::simpleLoggingSystem(); auto log = libp2p::log::createLogger("Ping"); @@ -106,7 +178,7 @@ int main(){ auto muxer = getenv_opt("MUXER"); //There for future use as skipped when transport=quic-v1 auto secureChannel = getenv_opt("SECURE_CHANNEL"); //There for future use as skipped when transport=quic-v1 auto isDialerStr = getenv_opt("IS_DIALER"); - std::string ip = getenv_opt("LISTENER_IP").value_or("0.0.0.0"); + std::string listener_ip = getenv_opt("LISTENER_IP").value_or("0.0.0.0"); // When we create sample peer, it binds on 0.0.0.0 by default std::string redisAddr = getenv_opt("REDIS_ADDR").value_or("redis:6379"); auto testKey = getenv_opt("TEST_KEY"); std::string debugStr = getenv_opt("DEBUG").value_or("false"); @@ -120,6 +192,19 @@ int main(){ log->setLevel(libp2p::log::Level::ERROR); } + // Detect actual network IP if listener_ip is 0.0.0.0 + // This has to be done manually right now + std::string ip = listener_ip; + if (listener_ip == "0.0.0.0") { + auto detected_ip = get_first_network_ip(log); + if (detected_ip.has_value()) { + ip = detected_ip.value(); + log->info("Using detected network IP: {}", ip); + } else { + log->warn("Could not detect network IP, using 0.0.0.0"); + } + } + int redisPort = parse_redis_port(redisAddr, log); std::string redisHost = parse_redis_host(redisAddr, log); std::string redisKey = fmt::format("{}_listener_multiaddr", *testKey); From 0b4af85092be3d31898f63e7f552499ff1903889 Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Thu, 12 Feb 2026 04:07:47 +0530 Subject: [PATCH 23/31] feat: increased time precision --- test-plans/ping/ping.cpp | 51 +++++++--------------------------------- 1 file changed, 8 insertions(+), 43 deletions(-) diff --git a/test-plans/ping/ping.cpp b/test-plans/ping/ping.cpp index 1a2d7153..de62efe3 100644 --- a/test-plans/ping/ping.cpp +++ b/test-plans/ping/ping.cpp @@ -19,19 +19,10 @@ #include #include #include - -#ifdef _WIN32 -#include -#include -#include -#pragma comment(lib, "iphlpapi.lib") -#pragma comment(lib, "ws2_32.lib") -#else #include #include #include #include -#endif std::optional getenv_opt(const char* name){ if(const char* v = std::getenv(name)){ @@ -113,33 +104,6 @@ std::string parse_redis_host(const std::string &redisAddr, libp2p::log::Logger l } std::optional get_first_network_ip(libp2p::log::Logger log) { -#ifdef _WIN32 - // Windows implementation - ULONG bufferSize = 15000; - PIP_ADAPTER_ADDRESSES addresses = (IP_ADAPTER_ADDRESSES*)malloc(bufferSize); - - if (GetAdaptersAddresses(AF_INET, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, - NULL, addresses, &bufferSize) == NO_ERROR) { - for (PIP_ADAPTER_ADDRESSES addr = addresses; addr != NULL; addr = addr->Next) { - if (addr->OperStatus != IfOperStatusUp) continue; - if (addr->IfType == IF_TYPE_SOFTWARE_LOOPBACK) continue; - - for (PIP_ADAPTER_UNICAST_ADDRESS unicast = addr->FirstUnicastAddress; unicast != NULL; unicast = unicast->Next) { - if (unicast->Address.lpSockaddr->sa_family == AF_INET) { - struct sockaddr_in* sockaddr = (struct sockaddr_in*)unicast->Address.lpSockaddr; - char ip[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &(sockaddr->sin_addr), ip, INET_ADDRSTRLEN); - log->info("Found network interface with IP {}", ip); - free(addresses); - return std::string(ip); - } - } - } - } - free(addresses); - return std::nullopt; -#else - // Unix/Linux implementation struct ifaddrs *ifaddr, *ifa; if (getifaddrs(&ifaddr) == -1) { @@ -150,10 +114,8 @@ std::optional get_first_network_ip(libp2p::log::Logger log) { for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { if (ifa->ifa_addr == nullptr) continue; - // Skip loopback and non-running interfaces if ((ifa->ifa_flags & IFF_LOOPBACK) || !(ifa->ifa_flags & IFF_UP)) continue; - // Only handle IPv4 if (ifa->ifa_addr->sa_family == AF_INET) { struct sockaddr_in *addr = (struct sockaddr_in *)ifa->ifa_addr; char ip[INET_ADDRSTRLEN]; @@ -167,7 +129,6 @@ std::optional get_first_network_ip(libp2p::log::Logger log) { freeifaddrs(ifaddr); return std::nullopt; -#endif } int main(){ @@ -295,12 +256,16 @@ int main(){ auto handShakeEnd = std::chrono::steady_clock::now(); log->info("Ping successful"); auto ping_rtt = ping_res.value(); - auto handShakePlusOneRTT = std::chrono::duration_cast(handShakeEnd - handShakeStart); + + auto handShakePlusOneRTT_us = std::chrono::duration_cast(handShakeEnd - handShakeStart); + auto ping_rtt_us = std::chrono::duration_cast(ping_rtt); + + double handShakePlusOneRTT_ms = handShakePlusOneRTT_us.count() / 1000.0; + double ping_rtt_ms = ping_rtt_us.count() / 1000.0; - // Printing out results in stdout std::cout << "latency:\n"; - std::cout << fmt::format(" handshake_plus_one_rtt: {}\n", handShakePlusOneRTT.count()); - std::cout << fmt::format(" ping_rtt: {}\n", ping_rtt.count()); + std::cout << fmt::format(" handshake_plus_one_rtt: {}\n", handShakePlusOneRTT_ms); + std::cout << fmt::format(" ping_rtt: {}\n", ping_rtt_ms); std::cout << " unit: ms\n"; io_context->stop(); From c026347b07bc5a1e64293d3523135b576e7f8316 Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Thu, 12 Feb 2026 19:24:15 +0530 Subject: [PATCH 24/31] fix: exit code and error logging --- test-plans/ping/ping.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test-plans/ping/ping.cpp b/test-plans/ping/ping.cpp index de62efe3..579d27c3 100644 --- a/test-plans/ping/ping.cpp +++ b/test-plans/ping/ping.cpp @@ -205,7 +205,7 @@ int main(){ auto ping = std::make_shared(io_context, host, random, pingConfig); if (not host->listen(sample_peer.listen)) { - std::println("Error listening on {}", sample_peer.listen); + log->error("Error listening on {}", sample_peer.listen); return 1; } @@ -233,12 +233,14 @@ int main(){ libp2p::peer::PeerInfo connect_info = {peer_id.value(), {address}}; freeReplyObject(replyListenAddr); + int exitStatus = 0; libp2p::coroSpawn(*io_context, [&]() -> libp2p::Coro { log->info("Connecting to {}", connect_info.addresses.at(0)); auto handShakeStart = std::chrono::steady_clock::now(); auto connect_res = (co_await host->connect(connect_info)); if (not connect_res.has_value()) { log->error("Failed to connect to peer"); + exitStatus = 1; io_context->stop(); co_return; } @@ -249,6 +251,7 @@ int main(){ auto ping_res = (co_await ping->ping(connection, std::chrono::seconds(testTimeoutSeconds))); if(not ping_res.has_value()){ log->error("Ping failed"); + exitStatus = 1; io_context->stop(); co_return; } @@ -275,7 +278,7 @@ int main(){ io_context->run(); redisFree(ctx); - return 0; + return exitStatus; } else{ log->error("Failed to wait for listener to be ready - unexpected reply type: {} (elements: {})", From 054591f8cad9928fd99de8d4de2e00cca1945518 Mon Sep 17 00:00:00 2001 From: turuslan Date: Fri, 13 Feb 2026 10:01:53 +0500 Subject: [PATCH 25/31] clang-format --- test-plans/ping/ping.cpp | 636 +++++++++++++++++++++------------------ 1 file changed, 338 insertions(+), 298 deletions(-) diff --git a/test-plans/ping/ping.cpp b/test-plans/ping/ping.cpp index 579d27c3..c221fd08 100644 --- a/test-plans/ping/ping.cpp +++ b/test-plans/ping/ping.cpp @@ -1,343 +1,383 @@ -#include -#include -#include +#include +#include #include +#include +#include +#include #include -#include -#include #include #include -#include -#include -#include +#include +#include #include +#include +#include +#include #include -#include +#include +#include #include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include -std::optional getenv_opt(const char* name){ - if(const char* v = std::getenv(name)){ - return std::string(v); - } - else{ - return std::nullopt; - } +std::optional getenv_opt(const char *name) { + if (const char *v = std::getenv(name)) { + return std::string(v); + } else { + return std::nullopt; + } } -redisContext* connect_redis(const std::string& host, int port, int timeout_ms, libp2p::log::Logger log){ - struct timeval timeout; - timeout.tv_sec = timeout_ms / 1000; - timeout.tv_usec = (timeout_ms % 1000) * 1000; +redisContext *connect_redis(const std::string &host, + int port, + int timeout_ms, + libp2p::log::Logger log) { + struct timeval timeout; + timeout.tv_sec = timeout_ms / 1000; + timeout.tv_usec = (timeout_ms % 1000) * 1000; - redisContext* ctx = redisConnectWithTimeout(host.c_str(), port, timeout); + redisContext *ctx = redisConnectWithTimeout(host.c_str(), port, timeout); - if(!ctx || ctx->err){ - if(ctx){ - log->error("Failed to connect to redis:{}\n", ctx->errstr); - redisFree(ctx); - } - return nullptr; - } - else{ - return ctx; + if (!ctx || ctx->err) { + if (ctx) { + log->error("Failed to connect to redis:{}\n", ctx->errstr); + redisFree(ctx); } + return nullptr; + } else { + return ctx; + } } -bool wait_for_redis(redisContext* ctx, int timeout_ms){ - auto start_time = std::chrono::steady_clock::now(); - - while(true){ - redisReply* reply = (redisReply*)redisCommand(ctx, "PING"); - if(reply){ - bool ok = reply->type == REDIS_REPLY_STATUS && std::string(reply->str) == "PONG"; - freeReplyObject(reply); - if (ok) return true; - } - - if (std::chrono::steady_clock::now() - start_time < std::chrono::milliseconds(timeout_ms)){ - return false; - } - - std::this_thread::sleep_for(std::chrono::milliseconds(100)); +bool wait_for_redis(redisContext *ctx, int timeout_ms) { + auto start_time = std::chrono::steady_clock::now(); + + while (true) { + redisReply *reply = (redisReply *)redisCommand(ctx, "PING"); + if (reply) { + bool ok = reply->type == REDIS_REPLY_STATUS + && std::string(reply->str) == "PONG"; + freeReplyObject(reply); + if (ok) { + return true; + } } -} -int parse_redis_port(std::string& redisAddr, libp2p::log::Logger log){ - size_t colon_pos = redisAddr.find(":"); - if (colon_pos == std::string::npos) { - log->error("Could not find port in redis address, using default\n"); - return 6379; + if (std::chrono::steady_clock::now() - start_time + < std::chrono::milliseconds(timeout_ms)) { + return false; } - std::string redisPortStr = redisAddr.substr(colon_pos + 1); - int port{}; - auto [ptr, ec] = std::from_chars(redisPortStr.data(), redisPortStr.data() + redisPortStr.size(), port); - if(ec == std::errc{}){ - return port; - } - else{ - log->error("Could not parse redis port, using default\n"); - return 6379; - } -} -std::string parse_redis_host(const std::string &redisAddr, libp2p::log::Logger log) { - size_t colonPos = redisAddr.find(':'); - if (colonPos == std::string::npos) { - log->warn("No port separator found in redis address '{}', treating entire string as host", redisAddr); - return redisAddr; - } - std::string host = redisAddr.substr(0, colonPos); - if (host.empty()) { - log->error("Empty host in redis address '{}'", redisAddr); - return "localhost"; - } - return host; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } } -std::optional get_first_network_ip(libp2p::log::Logger log) { - struct ifaddrs *ifaddr, *ifa; - - if (getifaddrs(&ifaddr) == -1) { - log->error("getifaddrs failed"); - return std::nullopt; - } - - for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { - if (ifa->ifa_addr == nullptr) continue; - - if ((ifa->ifa_flags & IFF_LOOPBACK) || !(ifa->ifa_flags & IFF_UP)) continue; - - if (ifa->ifa_addr->sa_family == AF_INET) { - struct sockaddr_in *addr = (struct sockaddr_in *)ifa->ifa_addr; - char ip[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &(addr->sin_addr), ip, INET_ADDRSTRLEN); - - log->info("Found network interface {} with IP {}", ifa->ifa_name, ip); - freeifaddrs(ifaddr); - return std::string(ip); - } - } - - freeifaddrs(ifaddr); - return std::nullopt; +int parse_redis_port(std::string &redisAddr, libp2p::log::Logger log) { + size_t colon_pos = redisAddr.find(":"); + if (colon_pos == std::string::npos) { + log->error("Could not find port in redis address, using default\n"); + return 6379; + } + std::string redisPortStr = redisAddr.substr(colon_pos + 1); + int port{}; + auto [ptr, ec] = std::from_chars( + redisPortStr.data(), redisPortStr.data() + redisPortStr.size(), port); + if (ec == std::errc{}) { + return port; + } else { + log->error("Could not parse redis port, using default\n"); + return 6379; + } } -int main(){ - libp2p::simpleLoggingSystem(); - auto log = libp2p::log::createLogger("Ping"); +std::string parse_redis_host(const std::string &redisAddr, + libp2p::log::Logger log) { + size_t colonPos = redisAddr.find(':'); + if (colonPos == std::string::npos) { + log->warn( + "No port separator found in redis address '{}', treating entire string " + "as host", + redisAddr); + return redisAddr; + } + std::string host = redisAddr.substr(0, colonPos); + if (host.empty()) { + log->error("Empty host in redis address '{}'", redisAddr); + return "localhost"; + } + return host; +} - auto transport = getenv_opt("TRANSPORT"); - auto muxer = getenv_opt("MUXER"); //There for future use as skipped when transport=quic-v1 - auto secureChannel = getenv_opt("SECURE_CHANNEL"); //There for future use as skipped when transport=quic-v1 - auto isDialerStr = getenv_opt("IS_DIALER"); - std::string listener_ip = getenv_opt("LISTENER_IP").value_or("0.0.0.0"); // When we create sample peer, it binds on 0.0.0.0 by default - std::string redisAddr = getenv_opt("REDIS_ADDR").value_or("redis:6379"); - auto testKey = getenv_opt("TEST_KEY"); - std::string debugStr = getenv_opt("DEBUG").value_or("false"); +std::optional get_first_network_ip(libp2p::log::Logger log) { + struct ifaddrs *ifaddr, *ifa; - int testTimeoutSeconds = 300; + if (getifaddrs(&ifaddr) == -1) { + log->error("getifaddrs failed"); + return std::nullopt; + } - bool isDialer = *isDialerStr == "true"; - bool debug = debugStr == "true"; + for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == nullptr) { + continue; + } - if(!debug){ - log->setLevel(libp2p::log::Level::ERROR); + if ((ifa->ifa_flags & IFF_LOOPBACK) || !(ifa->ifa_flags & IFF_UP)) { + continue; } - // Detect actual network IP if listener_ip is 0.0.0.0 - // This has to be done manually right now - std::string ip = listener_ip; - if (listener_ip == "0.0.0.0") { - auto detected_ip = get_first_network_ip(log); - if (detected_ip.has_value()) { - ip = detected_ip.value(); - log->info("Using detected network IP: {}", ip); - } else { - log->warn("Could not detect network IP, using 0.0.0.0"); - } + if (ifa->ifa_addr->sa_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)ifa->ifa_addr; + char ip[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(addr->sin_addr), ip, INET_ADDRSTRLEN); + + log->info("Found network interface {} with IP {}", ifa->ifa_name, ip); + freeifaddrs(ifaddr); + return std::string(ip); } - - int redisPort = parse_redis_port(redisAddr, log); - std::string redisHost = parse_redis_host(redisAddr, log); - std::string redisKey = fmt::format("{}_listener_multiaddr", *testKey); - log->info("Redis key: {}", redisKey); + } - redisContext* ctx = connect_redis(redisHost, redisPort, testTimeoutSeconds * 1000, log); //Redis connection needs timeout in ms + freeifaddrs(ifaddr); + return std::nullopt; +} - if(!wait_for_redis(ctx, testTimeoutSeconds)){ - redisFree(ctx); - return 1; +int main() { + libp2p::simpleLoggingSystem(); + auto log = libp2p::log::createLogger("Ping"); + + auto transport = getenv_opt("TRANSPORT"); + auto muxer = getenv_opt( + "MUXER"); // There for future use as skipped when transport=quic-v1 + auto secureChannel = + getenv_opt("SECURE_CHANNEL"); // There for future use as skipped when + // transport=quic-v1 + auto isDialerStr = getenv_opt("IS_DIALER"); + std::string listener_ip = + getenv_opt("LISTENER_IP") + .value_or("0.0.0.0"); // When we create sample peer, it binds on + // 0.0.0.0 by default + std::string redisAddr = getenv_opt("REDIS_ADDR").value_or("redis:6379"); + auto testKey = getenv_opt("TEST_KEY"); + std::string debugStr = getenv_opt("DEBUG").value_or("false"); + + int testTimeoutSeconds = 300; + + bool isDialer = *isDialerStr == "true"; + bool debug = debugStr == "true"; + + if (!debug) { + log->setLevel(libp2p::log::Level::ERROR); + } + + // Detect actual network IP if listener_ip is 0.0.0.0 + // This has to be done manually right now + std::string ip = listener_ip; + if (listener_ip == "0.0.0.0") { + auto detected_ip = get_first_network_ip(log); + if (detected_ip.has_value()) { + ip = detected_ip.value(); + log->info("Using detected network IP: {}", ip); + } else { + log->warn("Could not detect network IP, using 0.0.0.0"); } + } - unsigned int random_seed = static_cast(std::random_device{}()); - auto sample_peer = libp2p::SamplePeer(random_seed, ip, libp2p::SamplePeer::samplePort(random_seed), libp2p::SamplePeer::Ed25519); + int redisPort = parse_redis_port(redisAddr, log); + std::string redisHost = parse_redis_host(redisAddr, log); + std::string redisKey = fmt::format("{}_listener_multiaddr", *testKey); + log->info("Redis key: {}", redisKey); - std::shared_ptr io_context; - std::shared_ptr host; - std::shared_ptr random; - if(*transport == "quic-v1"){ - auto injector = libp2p::injector::makeHostInjector( - libp2p::injector::useKeyPair(sample_peer.keypair), - libp2p::injector::useTransportAdaptors() - ); + redisContext *ctx = + connect_redis(redisHost, + redisPort, + testTimeoutSeconds * 1000, + log); // Redis connection needs timeout in ms - io_context = injector.create>(); - host = injector.create>(); - random = injector.create>(); + if (!wait_for_redis(ctx, testTimeoutSeconds)) { + redisFree(ctx); + return 1; + } + + unsigned int random_seed = static_cast(std::random_device{}()); + auto sample_peer = + libp2p::SamplePeer(random_seed, + ip, + libp2p::SamplePeer::samplePort(random_seed), + libp2p::SamplePeer::Ed25519); + + std::shared_ptr io_context; + std::shared_ptr host; + std::shared_ptr random; + if (*transport == "quic-v1") { + auto injector = libp2p::injector::makeHostInjector( + libp2p::injector::useKeyPair(sample_peer.keypair), + libp2p::injector::useTransportAdaptors< + libp2p::transport::QuicTransport>()); + + io_context = injector.create>(); + host = injector.create>(); + random = injector.create>(); + + host->listenProtocol( + injector.create>()); + } else { + log->error("Unsupported transport protocol\n"); + return 1; + } - host->listenProtocol(injector.create>()); - } - else{ - log->error("Unsupported transport protocol\n"); - return 1; - } + libp2p::protocol::PingConfig pingConfig{}; + auto ping = std::make_shared( + io_context, host, random, pingConfig); - libp2p::protocol::PingConfig pingConfig{}; - auto ping = std::make_shared(io_context, host, random, pingConfig); + if (not host->listen(sample_peer.listen)) { + log->error("Error listening on {}", sample_peer.listen); + return 1; + } + + host->start(); + ping->start(); + log->info("Connection string: {}", sample_peer.connect); + + if (isDialer) { + redisReply *replyListenAddr = (redisReply *)redisCommand( + ctx, "BLPOP %s %d", redisKey.c_str(), testTimeoutSeconds); + if (replyListenAddr) { + if (replyListenAddr->type == REDIS_REPLY_ERROR) { + log->error("Redis BLPOP error: {}", replyListenAddr->str); + freeReplyObject(replyListenAddr); + redisFree(ctx); + return 1; + } + bool ok = replyListenAddr->type == REDIS_REPLY_ARRAY + && replyListenAddr->elements == 2; + if (ok) { + std::string listenAddr = replyListenAddr->element[1]->str; + log->info("Retrieved listener address from redis: {}", listenAddr); + auto address_res = libp2p::Multiaddress::create(listenAddr); + auto address = address_res.value(); + auto peer_id_res = address.getPeerId(); + auto peer_id = libp2p::PeerId::fromBase58(peer_id_res.value()); + libp2p::peer::PeerInfo connect_info = {peer_id.value(), {address}}; + freeReplyObject(replyListenAddr); + + int exitStatus = 0; + libp2p::coroSpawn(*io_context, [&]() -> libp2p::Coro { + log->info("Connecting to {}", connect_info.addresses.at(0)); + auto handShakeStart = std::chrono::steady_clock::now(); + auto connect_res = (co_await host->connect(connect_info)); + if (not connect_res.has_value()) { + log->error("Failed to connect to peer"); + exitStatus = 1; + io_context->stop(); + co_return; + } else { + log->info("Connected successfully"); + auto connection = connect_res.value(); + + auto ping_res = (co_await ping->ping( + connection, std::chrono::seconds(testTimeoutSeconds))); + if (not ping_res.has_value()) { + log->error("Ping failed"); + exitStatus = 1; + io_context->stop(); + co_return; + } else { + auto handShakeEnd = std::chrono::steady_clock::now(); + log->info("Ping successful"); + auto ping_rtt = ping_res.value(); + + auto handShakePlusOneRTT_us = + std::chrono::duration_cast( + handShakeEnd - handShakeStart); + auto ping_rtt_us = + std::chrono::duration_cast( + ping_rtt); + + double handShakePlusOneRTT_ms = + handShakePlusOneRTT_us.count() / 1000.0; + double ping_rtt_ms = ping_rtt_us.count() / 1000.0; + + std::cout << "latency:\n"; + std::cout << fmt::format(" handshake_plus_one_rtt: {}\n", + handShakePlusOneRTT_ms); + std::cout << fmt::format(" ping_rtt: {}\n", ping_rtt_ms); + std::cout << " unit: ms\n"; + + io_context->stop(); + } + } + }); - if (not host->listen(sample_peer.listen)) { - log->error("Error listening on {}", sample_peer.listen); + io_context->run(); + redisFree(ctx); + return exitStatus; + } else { + log->error( + "Failed to wait for listener to be ready - unexpected reply type: " + "{} (elements: {})", + replyListenAddr->type, + replyListenAddr->type == REDIS_REPLY_ARRAY + ? replyListenAddr->elements + : 0); + freeReplyObject(replyListenAddr); + redisFree(ctx); return 1; + } + } else { + log->error("Failed to get listener address from redis - {}", ctx->errstr); + redisFree(ctx); + return 1; } - - host->start(); - ping->start(); - log->info("Connection string: {}", sample_peer.connect); - - if(isDialer){ - redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, "BLPOP %s %d", redisKey.c_str(), testTimeoutSeconds); - if(replyListenAddr){ - if(replyListenAddr->type == REDIS_REPLY_ERROR){ - log->error("Redis BLPOP error: {}", replyListenAddr->str); - freeReplyObject(replyListenAddr); - redisFree(ctx); - return 1; - } - bool ok = replyListenAddr->type == REDIS_REPLY_ARRAY && replyListenAddr->elements == 2; - if(ok){ - std::string listenAddr = replyListenAddr->element[1]->str; - log->info("Retrieved listener address from redis: {}", listenAddr); - auto address_res = libp2p::Multiaddress::create(listenAddr); - auto address = address_res.value(); - auto peer_id_res = address.getPeerId(); - auto peer_id = libp2p::PeerId::fromBase58(peer_id_res.value()); - libp2p::peer::PeerInfo connect_info = {peer_id.value(), {address}}; - freeReplyObject(replyListenAddr); - - int exitStatus = 0; - libp2p::coroSpawn(*io_context, [&]() -> libp2p::Coro { - log->info("Connecting to {}", connect_info.addresses.at(0)); - auto handShakeStart = std::chrono::steady_clock::now(); - auto connect_res = (co_await host->connect(connect_info)); - if (not connect_res.has_value()) { - log->error("Failed to connect to peer"); - exitStatus = 1; - io_context->stop(); - co_return; - } - else{ - log->info("Connected successfully"); - auto connection = connect_res.value(); - - auto ping_res = (co_await ping->ping(connection, std::chrono::seconds(testTimeoutSeconds))); - if(not ping_res.has_value()){ - log->error("Ping failed"); - exitStatus = 1; - io_context->stop(); - co_return; - } - else{ - auto handShakeEnd = std::chrono::steady_clock::now(); - log->info("Ping successful"); - auto ping_rtt = ping_res.value(); - - auto handShakePlusOneRTT_us = std::chrono::duration_cast(handShakeEnd - handShakeStart); - auto ping_rtt_us = std::chrono::duration_cast(ping_rtt); - - double handShakePlusOneRTT_ms = handShakePlusOneRTT_us.count() / 1000.0; - double ping_rtt_ms = ping_rtt_us.count() / 1000.0; - - std::cout << "latency:\n"; - std::cout << fmt::format(" handshake_plus_one_rtt: {}\n", handShakePlusOneRTT_ms); - std::cout << fmt::format(" ping_rtt: {}\n", ping_rtt_ms); - std::cout << " unit: ms\n"; - - io_context->stop(); - } - } - }); - - io_context->run(); - redisFree(ctx); - return exitStatus; - } - else{ - log->error("Failed to wait for listener to be ready - unexpected reply type: {} (elements: {})", - replyListenAddr->type, - replyListenAddr->type == REDIS_REPLY_ARRAY ? replyListenAddr->elements : 0); - freeReplyObject(replyListenAddr); - redisFree(ctx); - return 1; - } - } - else{ - log->error("Failed to get listener address from redis - {}", ctx->errstr); - redisFree(ctx); - return 1; - } - }else{ - std::string connectStr = std::string(sample_peer.connect.getStringAddress()); - log->info("Pushing connect string {}", connectStr); - redisReply* replyListenAddr = (redisReply*)redisCommand(ctx, "RPUSH %s %s", redisKey.c_str(), connectStr.c_str()); - if(replyListenAddr){ - if(replyListenAddr->type == REDIS_REPLY_ERROR){ - log->error("Redis RPUSH error: {}", replyListenAddr->str); - freeReplyObject(replyListenAddr); - redisFree(ctx); - return 1; - } - bool ok = replyListenAddr->type == REDIS_REPLY_INTEGER; - if(ok){ - log->info("Listener address pushed to redis"); - freeReplyObject(replyListenAddr); - - boost::asio::steady_timer timeout_timer(*io_context); - timeout_timer.expires_after(std::chrono::seconds(testTimeoutSeconds)); - timeout_timer.async_wait([&](const boost::system::error_code& ec) { - if(!ec){ - log->info("Test timeout reached"); - io_context->stop(); - } - }); - - io_context->run(); - - log->info("Listener exiting"); - redisFree(ctx); - return 0; - } - else{ - log->error("Failed to push address to redis - unexpected reply type: {}", replyListenAddr->type); - freeReplyObject(replyListenAddr); - redisFree(ctx); - return 1; - } - } - else{ - log->error("Failed to get status of address push from redis - {}", ctx->errstr); - redisFree(ctx); - return 1; - } + } else { + std::string connectStr = + std::string(sample_peer.connect.getStringAddress()); + log->info("Pushing connect string {}", connectStr); + redisReply *replyListenAddr = (redisReply *)redisCommand( + ctx, "RPUSH %s %s", redisKey.c_str(), connectStr.c_str()); + if (replyListenAddr) { + if (replyListenAddr->type == REDIS_REPLY_ERROR) { + log->error("Redis RPUSH error: {}", replyListenAddr->str); + freeReplyObject(replyListenAddr); + redisFree(ctx); + return 1; + } + bool ok = replyListenAddr->type == REDIS_REPLY_INTEGER; + if (ok) { + log->info("Listener address pushed to redis"); + freeReplyObject(replyListenAddr); + + boost::asio::steady_timer timeout_timer(*io_context); + timeout_timer.expires_after(std::chrono::seconds(testTimeoutSeconds)); + timeout_timer.async_wait([&](const boost::system::error_code &ec) { + if (!ec) { + log->info("Test timeout reached"); + io_context->stop(); + } + }); + + io_context->run(); + + log->info("Listener exiting"); + redisFree(ctx); + return 0; + } else { + log->error( + "Failed to push address to redis - unexpected reply type: {}", + replyListenAddr->type); + freeReplyObject(replyListenAddr); + redisFree(ctx); + return 1; + } + } else { + log->error("Failed to get status of address push from redis - {}", + ctx->errstr); + redisFree(ctx); + return 1; } + } - return 1; + return 1; } \ No newline at end of file From 3a8a3a1c5b7dedbd6d9034ac325be473d216cd4d Mon Sep 17 00:00:00 2001 From: turuslan Date: Fri, 13 Feb 2026 17:09:15 +0500 Subject: [PATCH 26/31] refactor - move reusable code to test-plans/common.hpp - unique_ptr for redis pointers - redis connect and commands helper functions - TRY_OR_SL_FATAL to simplify test code - TestTimeout accounts for elapsed time --- src/network/listener_manager.cpp | 8 + test-plans/CMakeLists.txt | 9 +- test-plans/common.cpp | 190 +++++++++++++ test-plans/common.hpp | 147 ++++++++++ test-plans/ping/CMakeLists.txt | 2 +- test-plans/ping/ping.cpp | 407 ++++++--------------------- vcpkg-overlay/qtils/portfile.cmake | 4 +- vcpkg-overlay/soralog/portfile.cmake | 6 +- 8 files changed, 447 insertions(+), 326 deletions(-) create mode 100644 test-plans/common.cpp create mode 100644 test-plans/common.hpp diff --git a/src/network/listener_manager.cpp b/src/network/listener_manager.cpp index 9a6f290f..0ffd6fa3 100644 --- a/src/network/listener_manager.cpp +++ b/src/network/listener_manager.cpp @@ -109,6 +109,7 @@ namespace libp2p::network { for (auto it = begin; it != end;) { auto r = it->second->listen(it->first); if (!r) { + SL_WARN(log(), "Can't listen on {}", it->first, r.error()); // can not start listening on this multiaddr, remove listener it = listeners_.erase(it); } else { @@ -162,6 +163,13 @@ namespace libp2p::network { this->onConnection(std::move(item)); } }); + if (started) { + auto r = listener->listen(ma); + if (not r.has_value()) { + SL_WARN(log(), "Can't listen on {}: {}", ma, r.error()); + return r.error(); + } + } listeners_.insert({ma, std::move(listener)}); diff --git a/test-plans/CMakeLists.txt b/test-plans/CMakeLists.txt index 1aed946e..3539484e 100644 --- a/test-plans/CMakeLists.txt +++ b/test-plans/CMakeLists.txt @@ -1 +1,8 @@ -add_subdirectory(ping) \ No newline at end of file +add_subdirectory(ping) + +add_library(test_plans_common + common.cpp +) +target_link_libraries(test_plans_common + hiredis::hiredis +) diff --git a/test-plans/common.cpp b/test-plans/common.cpp new file mode 100644 index 00000000..eb891bf8 --- /dev/null +++ b/test-plans/common.cpp @@ -0,0 +1,190 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "common.hpp" + +#include +#include +#include + +timeval asTimeval(std::chrono::microseconds us) { + timeval tv; + auto s = std::chrono::duration_cast(us); + tv.tv_sec = s.count(); + tv.tv_usec = (us - s).count(); + return tv; +} + +std::optional getenv_opt(const char *name) { + if (const char *v = std::getenv(name)) { + return std::string{v}; + } + return std::nullopt; +} + +std::optional parseBool(std::string_view str) { + if (str == "true") { + return true; + } + if (str == "false") { + return false; + } + return std::nullopt; +} + +std::optional get_first_network_ip(libp2p::log::Logger log) { + std::optional result; + struct ifaddrs *ifaddr; + + if (getifaddrs(&ifaddr) == -1) { + log->error("getifaddrs failed"); + return std::nullopt; + } + + for (auto *ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == nullptr) { + continue; + } + + if ((ifa->ifa_flags & IFF_LOOPBACK) != 0 + or (ifa->ifa_flags & IFF_UP) == 0) { + continue; + } + + if (ifa->ifa_addr->sa_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)ifa->ifa_addr; + result = boost::asio::ip::make_address_v4(ntohl(addr->sin_addr.s_addr)) + .to_string(); + log->info( + "Found network interface {} with IP {}", ifa->ifa_name, *result); + break; + } + } + + freeifaddrs(ifaddr); + return result; +} + +TestTimeout::TestTimeout(Timeout timeout) + : start_{Clock::now()}, timeout_{timeout} {} + +TestTimeout::Remaining TestTimeout::remaining() const { + auto now = Clock::now(); + auto deadline = start_ + timeout_; + if (now > deadline) { + return Remaining::zero(); + } + return deadline - now; +} + +Redis::Redis(libp2p::log::Logger log, ContextPtr ctx) + : log_{std::move(log)}, ctx_{std::move(ctx)} {} + +outcome::result Redis::parseAddress(std::string_view str) { + auto colon_pos = str.find(":"); + if (colon_pos == str.npos) { + return Address{str, 6379}; + } + std::string host{str.substr(0, colon_pos)}; + BOOST_OUTCOME_TRY(auto port, parseInt(str.substr(colon_pos + 1))); + return Address{host, port}; +} + +outcome::result> Redis::connect( + std::string_view address_str, std::chrono::microseconds timeout) { + auto log = libp2p::log::createLogger("redis"); + BOOST_OUTCOME_TRY(auto address, parseAddress(address_str)); + ContextPtr ctx{redisConnectWithTimeout( + address.first.c_str(), address.second, asTimeval(timeout))}; + if (ctx == nullptr) { + SL_ERROR(log, "Failed to connect to redis"); + return Error::CONNECT_ERROR; + } + if (ctx->err != 0) { + SL_ERROR(log, "Failed to connect to redis: {}", ctx->errstr); + return Error::CONNECT_ERROR; + } + return std::make_shared(log, std::move(ctx)); +} + +outcome::result Redis::ping() { + BOOST_OUTCOME_TRY(auto reply, tryReply(redisCommand(ctx_.get(), "PING"))); + if (replyStr(*reply) != "PONG") { + return Error::PING_REPLY_ERROR; + } + return outcome::success(); +} + +outcome::result Redis::blpop(const std::string &key, + TimeoutDouble timeout) { + BOOST_OUTCOME_TRY( + auto reply, + tryReply(redisCommand( + ctx_.get(), + "BLPOP %s %d", + key.c_str(), + static_cast( + std::chrono::duration_cast(timeout) + .count())))); + auto value = replyArray(*reply, 1); + if (not value.has_value()) { + return Error::BLPOP_REPLY_ERROR; + } + return std::string{replyStr(**value)}; +} + +outcome::result Redis::rpush(const std::string &key, + const std::string &value) { + BOOST_OUTCOME_TRY(tryReply( + redisCommand(ctx_.get(), "RPUSH %s %s", key.c_str(), value.c_str()))); + return outcome::success(); +} + +std::string_view Redis::replyStr(const redisReply &reply) { + return {reply.str, reply.len}; +} + +std::optional Redis::replyArray(const redisReply &reply, + size_t index) { + if (index >= reply.elements) { + return std::nullopt; + } + return reply.element[index]; +} + +outcome::result Redis::tryReply(void *reply_ptr) { + if (reply_ptr == nullptr) { + return Error::NO_REPLY; + } + ReplyPtr reply{static_cast(reply_ptr)}; + if (reply->type == REDIS_REPLY_ERROR) { + SL_ERROR(log_, "reply error: {}", replyStr(*reply)); + return Error::REPLY_ERROR; + } + return std::move(reply); +} + +std::shared_ptr testRedisConnect(libp2p::log::Logger log, + std::string_view address, + const TestTimeout &timeout) { + auto redis_res = Redis::connect(address, timeout.remainingUs()); + if (not redis_res.has_value()) { + SL_FATAL(log, "redis connect error: {}", redis_res.error()); + } + auto &redis = redis_res.value(); + while (true) { + auto ping_res = redis->ping(); + if (ping_res.has_value()) { + break; + } + SL_WARN(log, "redis ping error: {}", ping_res.error()); + if (timeout.remaining().count() == 0) { + SL_FATAL(log, "redis ping timeout"); + } + std::this_thread::sleep_for(std::chrono::milliseconds{100}); + } + return redis; +} diff --git a/test-plans/common.hpp b/test-plans/common.hpp new file mode 100644 index 00000000..6359b591 --- /dev/null +++ b/test-plans/common.hpp @@ -0,0 +1,147 @@ +/** + * Copyright Quadrivium LLC + * All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TRY_OR_SL_FATAL(r, log, format, ...) \ + ({ \ + auto __r = (r); \ + if (not __r.has_value()) { \ + SL_FATAL(log, format, __VA_ARGS__ __VA_OPT__(, ) __r.error()) \ + } \ + __r.value(); \ + }) + +struct redisContext; + +timeval asTimeval(std::chrono::microseconds us); + +template +outcome::result parseInt(std::string_view str) { + T num; + auto r = std::from_chars(str.data(), str.data() + str.size(), num); + if (r.ec != std::errc{}) { + return make_error_code(r.ec); + } + if (r.ptr - str.data() != str.size()) { + return std::errc::invalid_argument; + } + return num; +} + +std::optional getenv_opt(const char *name); + +std::optional parseBool(std::string_view str); + +std::optional get_first_network_ip(libp2p::log::Logger log); + +struct TestTimeout { + using Clock = std::chrono::steady_clock; + using Timeout = std::chrono::seconds; + using Remaining = std::chrono::nanoseconds; + + TestTimeout(Timeout timeout); + + Remaining remaining() const; + + std::chrono::microseconds remainingUs() const { + return std::chrono::duration_cast(remaining()); + } + std::chrono::milliseconds remainingMs() const { + return std::chrono::duration_cast(remaining()); + } + + Clock::time_point start_; + Timeout timeout_; +}; + +struct redisContextDeleter { + static void operator()(redisContext *ptr) { + if (ptr != nullptr) { + redisFree(ptr); + } + } +}; + +struct redisReplyDeleter { + static void operator()(redisReply *ptr) { + if (ptr != nullptr) { + freeReplyObject(ptr); + } + } +}; + +class Redis { + public: + using ContextPtr = std::unique_ptr; + using ReplyPtr = std::unique_ptr; + + using TimeoutDouble = std::chrono::duration; + + enum class Error { + CONNECT_ERROR, + PARSE_PORT_ERROR, + NO_REPLY, + REPLY_ERROR, + PING_REPLY_ERROR, + BLPOP_REPLY_ERROR, + }; + Q_ENUM_ERROR_CODE_FRIEND(Error) { + using E = decltype(e); + switch (e) { + case E::CONNECT_ERROR: + return "CONNECT_ERROR"; + case E::PARSE_PORT_ERROR: + return "PARSE_PORT_ERROR"; + case E::NO_REPLY: + return "NO_REPLY"; + case E::REPLY_ERROR: + return "REPLY_ERROR"; + case E::PING_REPLY_ERROR: + return "PING_REPLY_ERROR"; + case E::BLPOP_REPLY_ERROR: + return "BLPOP_REPLY_ERROR"; + } + abort(); + } + + Redis(libp2p::log::Logger log, ContextPtr ctx); + + using Address = std::pair; + static outcome::result
parseAddress(std::string_view str); + + static outcome::result> connect( + std::string_view address_str, std::chrono::microseconds timeout); + + outcome::result ping(); + outcome::result blpop(const std::string &key, + TimeoutDouble timeout); + outcome::result rpush(const std::string &key, const std::string &value); + + static std::string_view replyStr(const redisReply &reply); + static std::optional replyArray(const redisReply &reply, + size_t index); + + private: + outcome::result tryReply(void *reply_ptr); + + libp2p::log::Logger log_; + ContextPtr ctx_; +}; + +std::shared_ptr testRedisConnect(libp2p::log::Logger log, + std::string_view address, + const TestTimeout &timeout); diff --git a/test-plans/ping/CMakeLists.txt b/test-plans/ping/CMakeLists.txt index e355df82..afac8fcb 100644 --- a/test-plans/ping/CMakeLists.txt +++ b/test-plans/ping/CMakeLists.txt @@ -4,5 +4,5 @@ add_executable(ping target_link_libraries(ping libp2p p2p_protocol_ping - hiredis::hiredis + test_plans_common ) \ No newline at end of file diff --git a/test-plans/ping/ping.cpp b/test-plans/ping/ping.cpp index c221fd08..4864d2d6 100644 --- a/test-plans/ping/ping.cpp +++ b/test-plans/ping/ping.cpp @@ -1,150 +1,17 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include #include #include -#include #include #include #include #include -#include #include -#include -#include -#include - -std::optional getenv_opt(const char *name) { - if (const char *v = std::getenv(name)) { - return std::string(v); - } else { - return std::nullopt; - } -} - -redisContext *connect_redis(const std::string &host, - int port, - int timeout_ms, - libp2p::log::Logger log) { - struct timeval timeout; - timeout.tv_sec = timeout_ms / 1000; - timeout.tv_usec = (timeout_ms % 1000) * 1000; - - redisContext *ctx = redisConnectWithTimeout(host.c_str(), port, timeout); - - if (!ctx || ctx->err) { - if (ctx) { - log->error("Failed to connect to redis:{}\n", ctx->errstr); - redisFree(ctx); - } - return nullptr; - } else { - return ctx; - } -} - -bool wait_for_redis(redisContext *ctx, int timeout_ms) { - auto start_time = std::chrono::steady_clock::now(); - - while (true) { - redisReply *reply = (redisReply *)redisCommand(ctx, "PING"); - if (reply) { - bool ok = reply->type == REDIS_REPLY_STATUS - && std::string(reply->str) == "PONG"; - freeReplyObject(reply); - if (ok) { - return true; - } - } - - if (std::chrono::steady_clock::now() - start_time - < std::chrono::milliseconds(timeout_ms)) { - return false; - } - - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } -} - -int parse_redis_port(std::string &redisAddr, libp2p::log::Logger log) { - size_t colon_pos = redisAddr.find(":"); - if (colon_pos == std::string::npos) { - log->error("Could not find port in redis address, using default\n"); - return 6379; - } - std::string redisPortStr = redisAddr.substr(colon_pos + 1); - int port{}; - auto [ptr, ec] = std::from_chars( - redisPortStr.data(), redisPortStr.data() + redisPortStr.size(), port); - if (ec == std::errc{}) { - return port; - } else { - log->error("Could not parse redis port, using default\n"); - return 6379; - } -} - -std::string parse_redis_host(const std::string &redisAddr, - libp2p::log::Logger log) { - size_t colonPos = redisAddr.find(':'); - if (colonPos == std::string::npos) { - log->warn( - "No port separator found in redis address '{}', treating entire string " - "as host", - redisAddr); - return redisAddr; - } - std::string host = redisAddr.substr(0, colonPos); - if (host.empty()) { - log->error("Empty host in redis address '{}'", redisAddr); - return "localhost"; - } - return host; -} - -std::optional get_first_network_ip(libp2p::log::Logger log) { - struct ifaddrs *ifaddr, *ifa; - - if (getifaddrs(&ifaddr) == -1) { - log->error("getifaddrs failed"); - return std::nullopt; - } - - for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { - if (ifa->ifa_addr == nullptr) { - continue; - } - - if ((ifa->ifa_flags & IFF_LOOPBACK) || !(ifa->ifa_flags & IFF_UP)) { - continue; - } - - if (ifa->ifa_addr->sa_family == AF_INET) { - struct sockaddr_in *addr = (struct sockaddr_in *)ifa->ifa_addr; - char ip[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &(addr->sin_addr), ip, INET_ADDRSTRLEN); - - log->info("Found network interface {} with IP {}", ifa->ifa_name, ip); - freeifaddrs(ifaddr); - return std::string(ip); - } - } - - freeifaddrs(ifaddr); - return std::nullopt; -} +#include "../common.hpp" int main() { + setlinebuf(stdout); + setlinebuf(stderr); + libp2p::simpleLoggingSystem(); auto log = libp2p::log::createLogger("Ping"); @@ -154,19 +21,16 @@ int main() { auto secureChannel = getenv_opt("SECURE_CHANNEL"); // There for future use as skipped when // transport=quic-v1 - auto isDialerStr = getenv_opt("IS_DIALER"); + auto isDialer = getenv_opt("IS_DIALER").and_then(parseBool).value_or(false); std::string listener_ip = getenv_opt("LISTENER_IP") .value_or("0.0.0.0"); // When we create sample peer, it binds on // 0.0.0.0 by default - std::string redisAddr = getenv_opt("REDIS_ADDR").value_or("redis:6379"); + std::string redisAddr = getenv_opt("REDIS_ADDR").value_or("redis"); auto testKey = getenv_opt("TEST_KEY"); - std::string debugStr = getenv_opt("DEBUG").value_or("false"); + bool debug = getenv_opt("DEBUG").and_then(parseBool).value_or(false); - int testTimeoutSeconds = 300; - - bool isDialer = *isDialerStr == "true"; - bool debug = debugStr == "true"; + TestTimeout timeout{std::chrono::seconds{300}}; if (!debug) { log->setLevel(libp2p::log::Level::ERROR); @@ -175,31 +39,20 @@ int main() { // Detect actual network IP if listener_ip is 0.0.0.0 // This has to be done manually right now std::string ip = listener_ip; - if (listener_ip == "0.0.0.0") { + if (not isDialer and listener_ip == "0.0.0.0") { auto detected_ip = get_first_network_ip(log); if (detected_ip.has_value()) { ip = detected_ip.value(); - log->info("Using detected network IP: {}", ip); + SL_INFO(log, "Using detected network IP: {}", ip); } else { - log->warn("Could not detect network IP, using 0.0.0.0"); + SL_WARN(log, "Could not detect network IP, using 0.0.0.0"); } } - int redisPort = parse_redis_port(redisAddr, log); - std::string redisHost = parse_redis_host(redisAddr, log); std::string redisKey = fmt::format("{}_listener_multiaddr", *testKey); - log->info("Redis key: {}", redisKey); - - redisContext *ctx = - connect_redis(redisHost, - redisPort, - testTimeoutSeconds * 1000, - log); // Redis connection needs timeout in ms + SL_INFO(log, "Redis key: {}", redisKey); - if (!wait_for_redis(ctx, testTimeoutSeconds)) { - redisFree(ctx); - return 1; - } + auto redis = testRedisConnect(log, redisAddr, timeout); unsigned int random_seed = static_cast(std::random_device{}()); auto sample_peer = @@ -210,174 +63,90 @@ int main() { std::shared_ptr io_context; std::shared_ptr host; - std::shared_ptr random; + std::shared_ptr ping; + std::shared_ptr injector_lifetime; if (*transport == "quic-v1") { - auto injector = libp2p::injector::makeHostInjector( - libp2p::injector::useKeyPair(sample_peer.keypair), - libp2p::injector::useTransportAdaptors< - libp2p::transport::QuicTransport>()); - - io_context = injector.create>(); - host = injector.create>(); - random = injector.create>(); + auto make_injector = [&] { + return libp2p::injector::makeHostInjector( + libp2p::injector::useKeyPair(sample_peer.keypair), + libp2p::injector::useTransportAdaptors< + libp2p::transport::QuicTransport>()); + }; + auto injector = + std::make_shared(make_injector()); + injector_lifetime = injector; + + io_context = injector->create>(); + host = injector->create>(); + ping = injector->create>(); - host->listenProtocol( - injector.create>()); } else { - log->error("Unsupported transport protocol\n"); - return 1; - } - - libp2p::protocol::PingConfig pingConfig{}; - auto ping = std::make_shared( - io_context, host, random, pingConfig); - - if (not host->listen(sample_peer.listen)) { - log->error("Error listening on {}", sample_peer.listen); - return 1; + SL_FATAL(log, "Unsupported transport protocol"); } host->start(); + host->listenProtocol(ping); ping->start(); - log->info("Connection string: {}", sample_peer.connect); if (isDialer) { - redisReply *replyListenAddr = (redisReply *)redisCommand( - ctx, "BLPOP %s %d", redisKey.c_str(), testTimeoutSeconds); - if (replyListenAddr) { - if (replyListenAddr->type == REDIS_REPLY_ERROR) { - log->error("Redis BLPOP error: {}", replyListenAddr->str); - freeReplyObject(replyListenAddr); - redisFree(ctx); - return 1; - } - bool ok = replyListenAddr->type == REDIS_REPLY_ARRAY - && replyListenAddr->elements == 2; - if (ok) { - std::string listenAddr = replyListenAddr->element[1]->str; - log->info("Retrieved listener address from redis: {}", listenAddr); - auto address_res = libp2p::Multiaddress::create(listenAddr); - auto address = address_res.value(); - auto peer_id_res = address.getPeerId(); - auto peer_id = libp2p::PeerId::fromBase58(peer_id_res.value()); - libp2p::peer::PeerInfo connect_info = {peer_id.value(), {address}}; - freeReplyObject(replyListenAddr); - - int exitStatus = 0; - libp2p::coroSpawn(*io_context, [&]() -> libp2p::Coro { - log->info("Connecting to {}", connect_info.addresses.at(0)); - auto handShakeStart = std::chrono::steady_clock::now(); - auto connect_res = (co_await host->connect(connect_info)); - if (not connect_res.has_value()) { - log->error("Failed to connect to peer"); - exitStatus = 1; - io_context->stop(); - co_return; - } else { - log->info("Connected successfully"); - auto connection = connect_res.value(); - - auto ping_res = (co_await ping->ping( - connection, std::chrono::seconds(testTimeoutSeconds))); - if (not ping_res.has_value()) { - log->error("Ping failed"); - exitStatus = 1; - io_context->stop(); - co_return; - } else { - auto handShakeEnd = std::chrono::steady_clock::now(); - log->info("Ping successful"); - auto ping_rtt = ping_res.value(); - - auto handShakePlusOneRTT_us = - std::chrono::duration_cast( - handShakeEnd - handShakeStart); - auto ping_rtt_us = - std::chrono::duration_cast( - ping_rtt); - - double handShakePlusOneRTT_ms = - handShakePlusOneRTT_us.count() / 1000.0; - double ping_rtt_ms = ping_rtt_us.count() / 1000.0; - - std::cout << "latency:\n"; - std::cout << fmt::format(" handshake_plus_one_rtt: {}\n", - handShakePlusOneRTT_ms); - std::cout << fmt::format(" ping_rtt: {}\n", ping_rtt_ms); - std::cout << " unit: ms\n"; - - io_context->stop(); - } - } - }); - - io_context->run(); - redisFree(ctx); - return exitStatus; - } else { - log->error( - "Failed to wait for listener to be ready - unexpected reply type: " - "{} (elements: {})", - replyListenAddr->type, - replyListenAddr->type == REDIS_REPLY_ARRAY - ? replyListenAddr->elements - : 0); - freeReplyObject(replyListenAddr); - redisFree(ctx); - return 1; - } - } else { - log->error("Failed to get listener address from redis - {}", ctx->errstr); - redisFree(ctx); - return 1; + auto address_str = + TRY_OR_SL_FATAL(redis->blpop(redisKey, timeout.remaining()), + log, + "Retrieve listener address error: {}"); + SL_INFO(log, "Retrieved listener address from redis: {}", address_str); + auto address = TRY_OR_SL_FATAL(libp2p::Multiaddress::create(address_str), + log, + "Parse listener address error: {}"); + auto peer_id_str = address.getPeerId(); + if (not peer_id_str.has_value()) { + SL_FATAL(log, "No peer id in listener address"); } + auto peer_id = TRY_OR_SL_FATAL(libp2p::PeerId::fromBase58(*peer_id_str), + log, + "Parse listener address peer id"); + libp2p::peer::PeerInfo connect_info{peer_id, {address}}; + + int exitStatus = 0; + libp2p::coroSpawn(*io_context, [&]() -> libp2p::Coro { + SL_INFO(log, "Connecting to {}", connect_info.addresses.at(0)); + auto handShakeStart = std::chrono::steady_clock::now(); + auto connection = TRY_OR_SL_FATAL( + co_await host->connect(connect_info), log, "Connect error: {}"); + SL_INFO(log, "Connected successfully"); + auto ping_rtt = TRY_OR_SL_FATAL( + co_await ping->ping(connection, timeout.remainingMs()), + log, + "Ping error: {}"); + auto handShakeEnd = std::chrono::steady_clock::now(); + SL_INFO(log, "Ping successful"); + + auto handShakePlusOneRTT_ms = + std::chrono::duration_cast( + handShakeEnd - handShakeStart); + auto ping_rtt_ms = + std::chrono::duration_cast(ping_rtt); + + SL_INFO(log, "latency:"); + SL_INFO( + log, " handshake_plus_one_rtt: {}", handShakePlusOneRTT_ms.count()); + SL_INFO(log, " ping_rtt: {}", ping_rtt_ms.count()); + SL_INFO(log, " unit: ms"); + + io_context->stop(); + }); + io_context->run_for(timeout.remaining()); } else { - std::string connectStr = - std::string(sample_peer.connect.getStringAddress()); - log->info("Pushing connect string {}", connectStr); - redisReply *replyListenAddr = (redisReply *)redisCommand( - ctx, "RPUSH %s %s", redisKey.c_str(), connectStr.c_str()); - if (replyListenAddr) { - if (replyListenAddr->type == REDIS_REPLY_ERROR) { - log->error("Redis RPUSH error: {}", replyListenAddr->str); - freeReplyObject(replyListenAddr); - redisFree(ctx); - return 1; - } - bool ok = replyListenAddr->type == REDIS_REPLY_INTEGER; - if (ok) { - log->info("Listener address pushed to redis"); - freeReplyObject(replyListenAddr); - - boost::asio::steady_timer timeout_timer(*io_context); - timeout_timer.expires_after(std::chrono::seconds(testTimeoutSeconds)); - timeout_timer.async_wait([&](const boost::system::error_code &ec) { - if (!ec) { - log->info("Test timeout reached"); - io_context->stop(); - } - }); - - io_context->run(); - - log->info("Listener exiting"); - redisFree(ctx); - return 0; - } else { - log->error( - "Failed to push address to redis - unexpected reply type: {}", - replyListenAddr->type); - freeReplyObject(replyListenAddr); - redisFree(ctx); - return 1; - } - } else { - log->error("Failed to get status of address push from redis - {}", - ctx->errstr); - redisFree(ctx); - return 1; - } + TRY_OR_SL_FATAL(host->listen(sample_peer.listen), + log, + "Error listening on {}: {}", + sample_peer.listen); + std::string address{sample_peer.connect.getStringAddress()}; + SL_INFO(log, "Pushing connect address {}", address); + TRY_OR_SL_FATAL( + redis->rpush(redisKey, address), log, "Push connect address error: {}"); + SL_INFO(log, "Listener address pushed to redis"); + io_context->run_for(timeout.remaining()); + SL_INFO(log, "Listener exiting"); } - - return 1; -} \ No newline at end of file + return EXIT_SUCCESS; +} diff --git a/vcpkg-overlay/qtils/portfile.cmake b/vcpkg-overlay/qtils/portfile.cmake index 964ee973..75da5e32 100644 --- a/vcpkg-overlay/qtils/portfile.cmake +++ b/vcpkg-overlay/qtils/portfile.cmake @@ -2,8 +2,8 @@ vcpkg_check_linkage(ONLY_STATIC_LIBRARY) vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH REPO qdrvm/qtils - REF 4749d1f8332e848dbce2ac74fc1a0c1992e9cbdb - SHA512 5a3366d5a162b70461e73740313b5c1f43f4958bc52aab64372b9992d67f338b0c869125b00fe3cad599e368bd6918309a2aa4b1981f595eccb014f1bc655887 + REF refs/tags/v0.1.6 + SHA512 7f4bcc40f1201b40510b9f9f5aee6c65b4f611b5b001e7e0996f3b9cdd852c388ceed29cb3a3d3302f90edee7dd62422e33c712752c58dc9b2a95141169d8fec ) vcpkg_cmake_configure(SOURCE_PATH "${SOURCE_PATH}") vcpkg_cmake_install() diff --git a/vcpkg-overlay/soralog/portfile.cmake b/vcpkg-overlay/soralog/portfile.cmake index 0b96e8e4..5767b112 100644 --- a/vcpkg-overlay/soralog/portfile.cmake +++ b/vcpkg-overlay/soralog/portfile.cmake @@ -1,9 +1,9 @@ vcpkg_check_linkage(ONLY_STATIC_LIBRARY) vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH - REPO qdrvm/soralog - REF refs/tags/v0.2.5 - SHA512 47375cc61c78ebc4119781bf19ce3b92c4a5a40ed4dc77c0156ac0750df1e4d13455bf6f60d9ea2f0b7bf7dda75423eed320edce453617ab06d6c1c9a8a8843c + REPO xDimon/soralog + REF refs/tags/v0.2.6 + SHA512 8ad2698cf029b70e909d7ace1e500957dceecc80e2331cecd1d66e775bb19456c81957e0c375ce81010f0aa5c8b6f13dc38fbf25c8f8547833548e350f6ae3f3 ) vcpkg_cmake_configure(SOURCE_PATH "${SOURCE_PATH}") vcpkg_cmake_install() From 3e0206d7dd9309760bb02e1d07a559d9000ec4c1 Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Tue, 17 Feb 2026 21:23:56 +0530 Subject: [PATCH 27/31] fix: reference update to leanp2p --- example/00-vcpkg-install/vcpkg-overlay/leanp2p/portfile.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/00-vcpkg-install/vcpkg-overlay/leanp2p/portfile.cmake b/example/00-vcpkg-install/vcpkg-overlay/leanp2p/portfile.cmake index 71b20edd..a864c2fc 100644 --- a/example/00-vcpkg-install/vcpkg-overlay/leanp2p/portfile.cmake +++ b/example/00-vcpkg-install/vcpkg-overlay/leanp2p/portfile.cmake @@ -2,8 +2,8 @@ vcpkg_check_linkage(ONLY_STATIC_LIBRARY) vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH REPO qdrvm/leanp2p - REF f5d7e82fa0d16488ebc4974407e7fe11615bb638 - SHA512 d93160336590b70379256547b4b584a107743e8c84aa2ccc9fff8615409dbcd47ac9a51d4dc05bc841db907c97a3733c0f4307a472ec9fafefb9fb8260669f7b + REF 51e7a4f483433bed8ddca5bb8df969c27c590d4b + SHA512 4259788d600848c4d51b16e971fac8f8a13ad88f694cee551bf9461ba7869e2f0debc06548f883912d051161ed29c1b7c7dc15dbfc5a70b96b8d4c2927741dfe ) vcpkg_cmake_configure(SOURCE_PATH "${SOURCE_PATH}") vcpkg_cmake_install() From 6aa3e5a8821bee28c18347ddd44da8f08542ccce Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Tue, 17 Feb 2026 21:24:39 +0530 Subject: [PATCH 28/31] refactor: changing test-plans names for readability --- test-plans/CMakeLists.txt | 2 +- test-plans/ping/CMakeLists.txt | 8 -------- test-plans/transport_interop/CMakeLists.txt | 8 ++++++++ test-plans/{ping => transport_interop}/Dockerfile | 6 +++--- .../ping.cpp => transport_interop/test_plans_ping.cpp} | 0 5 files changed, 12 insertions(+), 12 deletions(-) delete mode 100644 test-plans/ping/CMakeLists.txt create mode 100644 test-plans/transport_interop/CMakeLists.txt rename test-plans/{ping => transport_interop}/Dockerfile (83%) rename test-plans/{ping/ping.cpp => transport_interop/test_plans_ping.cpp} (100%) diff --git a/test-plans/CMakeLists.txt b/test-plans/CMakeLists.txt index 3539484e..1e9c3782 100644 --- a/test-plans/CMakeLists.txt +++ b/test-plans/CMakeLists.txt @@ -1,4 +1,4 @@ -add_subdirectory(ping) +add_subdirectory(transport_interop) add_library(test_plans_common common.cpp diff --git a/test-plans/ping/CMakeLists.txt b/test-plans/ping/CMakeLists.txt deleted file mode 100644 index afac8fcb..00000000 --- a/test-plans/ping/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -add_executable(ping - ping.cpp -) -target_link_libraries(ping - libp2p - p2p_protocol_ping - test_plans_common -) \ No newline at end of file diff --git a/test-plans/transport_interop/CMakeLists.txt b/test-plans/transport_interop/CMakeLists.txt new file mode 100644 index 00000000..15e3a1c6 --- /dev/null +++ b/test-plans/transport_interop/CMakeLists.txt @@ -0,0 +1,8 @@ +add_executable(test_plans_ping + test_plans_ping.cpp +) +target_link_libraries(test_plans_ping + libp2p + p2p_protocol_ping + test_plans_common +) diff --git a/test-plans/ping/Dockerfile b/test-plans/transport_interop/Dockerfile similarity index 83% rename from test-plans/ping/Dockerfile rename to test-plans/transport_interop/Dockerfile index deb78a44..3612555a 100644 --- a/test-plans/ping/Dockerfile +++ b/test-plans/transport_interop/Dockerfile @@ -31,10 +31,10 @@ COPY . . RUN cmake --preset test-plans -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DCMAKE_EXE_LINKER_FLAGS="-static" \ - && cmake --build build -j$(nproc) --target ping + && cmake --build build -j$(nproc) --target test_plans_ping FROM alpine:3.19 -COPY --from=builder /build/build/test-plans/ping/ping /ping +COPY --from=builder /build/build/test-plans/transport_interop/test_plans_ping /test_plans_ping -ENTRYPOINT ["/ping"] \ No newline at end of file +ENTRYPOINT ["/test_plans_ping"] \ No newline at end of file diff --git a/test-plans/ping/ping.cpp b/test-plans/transport_interop/test_plans_ping.cpp similarity index 100% rename from test-plans/ping/ping.cpp rename to test-plans/transport_interop/test_plans_ping.cpp From bdea41d3f766bb1070cc39c84baf38e556c5f6bf Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Tue, 17 Feb 2026 21:25:01 +0530 Subject: [PATCH 29/31] refactor: Updating CMake presets for test-plans --- CMakeLists.txt | 6 +++--- CMakePresets.json | 4 ++-- vcpkg.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e1fa2ed..be1d82fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ find_package(libsecp256k1 CONFIG REQUIRED) find_package(Protobuf CONFIG REQUIRED) find_package(tsl_hat_trie CONFIG REQUIRED) find_package(Boost.DI CONFIG REQUIRED) -if(ENABLE_REDIS) +if(ENABLE_TEST_PLANS) find_package(hiredis CONFIG REQUIRED) endif() @@ -35,6 +35,6 @@ add_subdirectory(src) add_subdirectory(example) # Test-plans -if(ENABLE_REDIS) +if(ENABLE_TEST_PLANS) add_subdirectory(test-plans) -endif() \ No newline at end of file +endif() diff --git a/CMakePresets.json b/CMakePresets.json index 0b29583a..42938c21 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -18,8 +18,8 @@ "cacheVariables": { "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", "CMAKE_BUILD_TYPE": "Debug", - "ENABLE_REDIS": "ON", - "VCPKG_MANIFEST_FEATURES": "redis" + "ENABLE_TEST_PLANS": "ON", + "VCPKG_MANIFEST_FEATURES": "test-plans" } } ] diff --git a/vcpkg.json b/vcpkg.json index 8e01f017..cbd31a9f 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -2,7 +2,7 @@ "name": "leanp2p", "version": "0.1.0", "features": { - "redis": { + "test-plans": { "description": "Enable Redis support (needed for test-plans)", "dependencies": ["hiredis"] } From a28bc4af10f9d22e509936bfea12a6f11716b7a8 Mon Sep 17 00:00:00 2001 From: bismuth01 Date: Tue, 17 Feb 2026 21:26:58 +0530 Subject: [PATCH 30/31] fix: update CMake list option --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index be1d82fa..7000a62c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ project(leanp2p) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) -option(ENABLE_REDIS "Enable Redis support" OFF) +option(ENABLE_TEST_PLANS "Enable test-plans support" OFF) find_package(Boost CONFIG REQUIRED filesystem random beast program_options) find_package(OpenSSL CONFIG REQUIRED) From c409570af82757fc50fb9644e07968e9c43a7c22 Mon Sep 17 00:00:00 2001 From: turuslan Date: Tue, 17 Feb 2026 21:37:51 +0500 Subject: [PATCH 31/31] remove ENABLE_REDIS --- CMakePresets.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index 42938c21..63037151 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -7,8 +7,7 @@ "binaryDir": "${sourceDir}/build", "cacheVariables": { "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", - "CMAKE_BUILD_TYPE": "Debug", - "ENABLE_REDIS": "OFF" + "CMAKE_BUILD_TYPE": "Debug" } }, {